...

Source file src/k8s.io/kubectl/pkg/scale/scale_test.go

Documentation: k8s.io/kubectl/pkg/scale

     1  /*
     2  Copyright 2014 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package scale
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"testing"
    23  	"time"
    24  
    25  	autoscalingv1 "k8s.io/api/autoscaling/v1"
    26  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	api "k8s.io/apimachinery/pkg/apis/testapigroup/v1"
    29  	"k8s.io/apimachinery/pkg/runtime"
    30  	"k8s.io/apimachinery/pkg/runtime/schema"
    31  	"k8s.io/apimachinery/pkg/types"
    32  	"k8s.io/client-go/scale"
    33  	fakescale "k8s.io/client-go/scale/fake"
    34  	testcore "k8s.io/client-go/testing"
    35  )
    36  
    37  var (
    38  	rcgvr = schema.GroupVersionResource{
    39  		Group:    "",
    40  		Version:  "v1",
    41  		Resource: "replicationcontrollers",
    42  	}
    43  	rsgvr = schema.GroupVersionResource{
    44  		Group:    "extensions",
    45  		Version:  "v1beta1",
    46  		Resource: "replicasets",
    47  	}
    48  	deploygvr = schema.GroupVersionResource{
    49  		Group:    "apps",
    50  		Version:  "v1",
    51  		Resource: "deployments",
    52  	}
    53  	stsgvr = schema.GroupVersionResource{
    54  		Group:    "apps",
    55  		Version:  "v1",
    56  		Resource: "statefulsets",
    57  	}
    58  )
    59  
    60  func TestReplicationControllerScaleRetry(t *testing.T) {
    61  	verbsOnError := map[string]*apierrors.StatusError{
    62  		"patch": apierrors.NewConflict(api.Resource("Status"), "foo", nil),
    63  	}
    64  	scaleClientExpectedAction := []string{"patch", "get"}
    65  	scaleClient := createFakeScaleClient("replicationcontrollers", "foo-v1", 2, verbsOnError)
    66  	scaler := NewScaler(scaleClient)
    67  	count := uint(3)
    68  	name := "foo-v1"
    69  	namespace := metav1.NamespaceDefault
    70  
    71  	scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, rcgvr, false)
    72  	pass, err := scaleFunc()
    73  	if pass {
    74  		t.Errorf("Expected an update failure to return pass = false, got pass = %v", pass)
    75  	}
    76  	if err != nil {
    77  		t.Errorf("Did not expect an error on update conflict failure, got %v", err)
    78  	}
    79  	preconditions := ScalePrecondition{3, ""}
    80  	scaleFunc = ScaleCondition(scaler, &preconditions, namespace, name, count, nil, rcgvr, false)
    81  	_, err = scaleFunc()
    82  	if err == nil {
    83  		t.Errorf("Expected error on precondition failure")
    84  	}
    85  	actions := scaleClient.Actions()
    86  	if len(actions) != len(scaleClientExpectedAction) {
    87  		t.Errorf("unexpected actions: %v, expected %d actions got %d", actions, len(scaleClientExpectedAction), len(actions))
    88  	}
    89  	for i, verb := range scaleClientExpectedAction {
    90  		if actions[i].GetVerb() != verb {
    91  			t.Errorf("unexpected action: %+v, expected %s", actions[i].GetVerb(), verb)
    92  		}
    93  	}
    94  }
    95  
    96  func TestReplicationControllerScaleInvalid(t *testing.T) {
    97  	verbsOnError := map[string]*apierrors.StatusError{
    98  		"patch": apierrors.NewInvalid(api.Kind("Status"), "foo", nil),
    99  	}
   100  	scaleClientExpectedAction := []string{"patch"}
   101  	scaleClient := createFakeScaleClient("replicationcontrollers", "foo-v1", 1, verbsOnError)
   102  	scaler := NewScaler(scaleClient)
   103  	count := uint(3)
   104  	name := "foo-v1"
   105  	namespace := "default"
   106  
   107  	scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, rcgvr, false)
   108  	pass, err := scaleFunc()
   109  	if pass {
   110  		t.Errorf("Expected an update failure to return pass = false, got pass = %v", pass)
   111  	}
   112  	if err == nil {
   113  		t.Errorf("Expected error on invalid update failure, got %v", err)
   114  	}
   115  	actions := scaleClient.Actions()
   116  	if len(actions) != len(scaleClientExpectedAction) {
   117  		t.Errorf("unexpected actions: %v, expected %d actions got %d", actions, len(scaleClientExpectedAction), len(actions))
   118  	}
   119  	for i, verb := range scaleClientExpectedAction {
   120  		if actions[i].GetVerb() != verb {
   121  			t.Errorf("unexpected action: %+v, expected %s", actions[i].GetVerb(), verb)
   122  		}
   123  	}
   124  }
   125  
   126  func TestReplicationControllerScale(t *testing.T) {
   127  	scaleClientExpectedAction := []string{"patch"}
   128  	scaleClient := createFakeScaleClient("replicationcontrollers", "foo-v1", 2, nil)
   129  	scaler := NewScaler(scaleClient)
   130  	count := uint(3)
   131  	name := "foo-v1"
   132  	err := scaler.Scale("default", name, count, nil, nil, nil, rcgvr, false)
   133  
   134  	if err != nil {
   135  		t.Fatalf("unexpected error occurred = %v while scaling the resource", err)
   136  	}
   137  	actions := scaleClient.Actions()
   138  	if len(actions) != len(scaleClientExpectedAction) {
   139  		t.Errorf("unexpected actions: %v, expected %d actions got %d", actions, len(scaleClientExpectedAction), len(actions))
   140  	}
   141  	for i, verb := range scaleClientExpectedAction {
   142  		if actions[i].GetVerb() != verb {
   143  			t.Errorf("unexpected action: %+v, expected %s", actions[i].GetVerb(), verb)
   144  		}
   145  	}
   146  }
   147  
   148  func TestReplicationControllerScaleFailsPreconditions(t *testing.T) {
   149  	scaleClientExpectedAction := []string{"get"}
   150  	scaleClient := createFakeScaleClient("replicationcontrollers", "foo", 10, nil)
   151  	scaler := NewScaler(scaleClient)
   152  	preconditions := ScalePrecondition{2, ""}
   153  	count := uint(3)
   154  	name := "foo"
   155  	err := scaler.Scale("default", name, count, &preconditions, nil, nil, rcgvr, false)
   156  	if err == nil {
   157  		t.Fatal("expected to get an error but none was returned")
   158  	}
   159  	actions := scaleClient.Actions()
   160  	if len(actions) != len(scaleClientExpectedAction) {
   161  		t.Errorf("unexpected actions: %v, expected %d actions got %d", actions, len(scaleClientExpectedAction), len(actions))
   162  	}
   163  	for i, verb := range scaleClientExpectedAction {
   164  		if actions[i].GetVerb() != verb {
   165  			t.Errorf("unexpected action: %+v, expected %s", actions[i].GetVerb(), verb)
   166  		}
   167  	}
   168  }
   169  
   170  func TestDeploymentScaleRetry(t *testing.T) {
   171  	verbsOnError := map[string]*apierrors.StatusError{
   172  		"patch": apierrors.NewConflict(api.Resource("Status"), "foo", nil),
   173  	}
   174  	scaleClientExpectedAction := []string{"patch", "get"}
   175  	scaleClient := createFakeScaleClient("deployments", "foo", 2, verbsOnError)
   176  	scaler := NewScaler(scaleClient)
   177  	count := uint(3)
   178  	name := "foo"
   179  	namespace := "default"
   180  
   181  	scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, deploygvr, false)
   182  	pass, err := scaleFunc()
   183  	if pass != false {
   184  		t.Errorf("Expected an update failure to return pass = false, got pass = %v", pass)
   185  	}
   186  	if err != nil {
   187  		t.Errorf("Did not expect an error on update failure, got %v", err)
   188  	}
   189  	preconditions := &ScalePrecondition{3, ""}
   190  	scaleFunc = ScaleCondition(scaler, preconditions, namespace, name, count, nil, deploygvr, false)
   191  	_, err = scaleFunc()
   192  	if err == nil {
   193  		t.Error("Expected error on precondition failure")
   194  	}
   195  	actions := scaleClient.Actions()
   196  	if len(actions) != len(scaleClientExpectedAction) {
   197  		t.Errorf("unexpected actions: %v, expected %d actions got %d", actions, len(scaleClientExpectedAction), len(actions))
   198  	}
   199  	for i, verb := range scaleClientExpectedAction {
   200  		if actions[i].GetVerb() != verb {
   201  			t.Errorf("unexpected action: %+v, expected %s", actions[i].GetVerb(), verb)
   202  		}
   203  	}
   204  }
   205  
   206  func TestDeploymentScale(t *testing.T) {
   207  	scaleClientExpectedAction := []string{"patch"}
   208  	scaleClient := createFakeScaleClient("deployments", "foo", 2, nil)
   209  	scaler := NewScaler(scaleClient)
   210  	count := uint(3)
   211  	name := "foo"
   212  	err := scaler.Scale("default", name, count, nil, nil, nil, deploygvr, false)
   213  	if err != nil {
   214  		t.Fatal(err)
   215  	}
   216  	actions := scaleClient.Actions()
   217  	if len(actions) != len(scaleClientExpectedAction) {
   218  		t.Errorf("unexpected actions: %v, expected %d actions got %d", actions, len(scaleClientExpectedAction), len(actions))
   219  	}
   220  	for i, verb := range scaleClientExpectedAction {
   221  		if actions[i].GetVerb() != verb {
   222  			t.Errorf("unexpected action: %+v, expected %s", actions[i].GetVerb(), verb)
   223  		}
   224  	}
   225  }
   226  
   227  func TestDeploymentScaleInvalid(t *testing.T) {
   228  	scaleClientExpectedAction := []string{"patch"}
   229  	verbsOnError := map[string]*apierrors.StatusError{
   230  		"patch": apierrors.NewInvalid(api.Kind("Status"), "foo", nil),
   231  	}
   232  	scaleClient := createFakeScaleClient("deployments", "foo", 2, verbsOnError)
   233  	scaler := NewScaler(scaleClient)
   234  	count := uint(3)
   235  	name := "foo"
   236  	namespace := "default"
   237  
   238  	scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, deploygvr, false)
   239  	pass, err := scaleFunc()
   240  	if pass {
   241  		t.Errorf("Expected an update failure to return pass = false, got pass = %v", pass)
   242  	}
   243  	if err == nil {
   244  		t.Errorf("Expected error on invalid update failure, got %v", err)
   245  	}
   246  	actions := scaleClient.Actions()
   247  	if len(actions) != len(scaleClientExpectedAction) {
   248  		t.Errorf("unexpected actions: %v, expected %d actions got %d", actions, len(scaleClientExpectedAction), len(actions))
   249  	}
   250  	for i, verb := range scaleClientExpectedAction {
   251  		if actions[i].GetVerb() != verb {
   252  			t.Errorf("unexpected action: %+v, expected %s", actions[i].GetVerb(), verb)
   253  		}
   254  	}
   255  }
   256  
   257  func TestDeploymentScaleFailsPreconditions(t *testing.T) {
   258  	scaleClientExpectedAction := []string{"get"}
   259  	scaleClient := createFakeScaleClient("deployments", "foo", 10, nil)
   260  	scaler := NewScaler(scaleClient)
   261  	preconditions := ScalePrecondition{2, ""}
   262  	count := uint(3)
   263  	name := "foo"
   264  	err := scaler.Scale("default", name, count, &preconditions, nil, nil, deploygvr, false)
   265  	if err == nil {
   266  		t.Fatal("exptected to get an error but none was returned")
   267  	}
   268  	actions := scaleClient.Actions()
   269  	if len(actions) != len(scaleClientExpectedAction) {
   270  		t.Errorf("unexpected actions: %v, expected %d actions got %d", actions, len(scaleClientExpectedAction), len(actions))
   271  	}
   272  	for i, verb := range scaleClientExpectedAction {
   273  		if actions[i].GetVerb() != verb {
   274  			t.Errorf("unexpected action: %+v, expected %s", actions[i].GetVerb(), verb)
   275  		}
   276  	}
   277  }
   278  
   279  func TestStatefulSetScale(t *testing.T) {
   280  	scaleClientExpectedAction := []string{"patch"}
   281  	scaleClient := createFakeScaleClient("statefulsets", "foo", 2, nil)
   282  	scaler := NewScaler(scaleClient)
   283  	count := uint(3)
   284  	name := "foo"
   285  	err := scaler.Scale("default", name, count, nil, nil, nil, stsgvr, false)
   286  	if err != nil {
   287  		t.Fatal(err)
   288  	}
   289  	actions := scaleClient.Actions()
   290  	if len(actions) != len(scaleClientExpectedAction) {
   291  		t.Errorf("unexpected actions: %v, expected %d actions got %d", actions, len(scaleClientExpectedAction), len(actions))
   292  	}
   293  	for i, verb := range scaleClientExpectedAction {
   294  		if actions[i].GetVerb() != verb {
   295  			t.Errorf("unexpected action: %+v, expected %s", actions[i].GetVerb(), verb)
   296  		}
   297  	}
   298  }
   299  
   300  func TestStatefulSetScaleRetry(t *testing.T) {
   301  	scaleClientExpectedAction := []string{"patch", "get"}
   302  	verbsOnError := map[string]*apierrors.StatusError{
   303  		"patch": apierrors.NewConflict(api.Resource("Status"), "foo", nil),
   304  	}
   305  	scaleClient := createFakeScaleClient("statefulsets", "foo", 2, verbsOnError)
   306  	scaler := NewScaler(scaleClient)
   307  	count := uint(3)
   308  	name := "foo"
   309  	namespace := "default"
   310  
   311  	scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, stsgvr, false)
   312  	pass, err := scaleFunc()
   313  	if pass != false {
   314  		t.Errorf("Expected an update failure to return pass = false, got pass = %v", pass)
   315  	}
   316  	if err != nil {
   317  		t.Errorf("Did not expect an error on update failure, got %v", err)
   318  	}
   319  	preconditions := &ScalePrecondition{3, ""}
   320  	scaleFunc = ScaleCondition(scaler, preconditions, namespace, name, count, nil, stsgvr, false)
   321  	_, err = scaleFunc()
   322  	if err == nil {
   323  		t.Error("Expected error on precondition failure")
   324  	}
   325  	actions := scaleClient.Actions()
   326  	if len(actions) != len(scaleClientExpectedAction) {
   327  		t.Errorf("unexpected actions: %v, expected %d actions got %d", actions, len(scaleClientExpectedAction), len(actions))
   328  	}
   329  	for i, verb := range scaleClientExpectedAction {
   330  		if actions[i].GetVerb() != verb {
   331  			t.Errorf("unexpected action: %+v, expected %s", actions[i].GetVerb(), verb)
   332  		}
   333  	}
   334  }
   335  
   336  func TestStatefulSetScaleInvalid(t *testing.T) {
   337  	scaleClientExpectedAction := []string{"patch"}
   338  	verbsOnError := map[string]*apierrors.StatusError{
   339  		"patch": apierrors.NewInvalid(api.Kind("Status"), "foo", nil),
   340  	}
   341  	scaleClient := createFakeScaleClient("statefulsets", "foo", 2, verbsOnError)
   342  	scaler := NewScaler(scaleClient)
   343  	count := uint(3)
   344  	name := "foo"
   345  	namespace := "default"
   346  
   347  	scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, stsgvr, false)
   348  	pass, err := scaleFunc()
   349  	if pass {
   350  		t.Errorf("Expected an update failure to return pass = false, got pass = %v", pass)
   351  	}
   352  	if err == nil {
   353  		t.Errorf("Expected error on invalid update failure, got %v", err)
   354  	}
   355  	actions := scaleClient.Actions()
   356  	if len(actions) != len(scaleClientExpectedAction) {
   357  		t.Errorf("unexpected actions: %v, expected %d actions got %d", actions, len(scaleClientExpectedAction), len(actions))
   358  	}
   359  	for i, verb := range scaleClientExpectedAction {
   360  		if actions[i].GetVerb() != verb {
   361  			t.Errorf("unexpected action: %+v, expected %s", actions[i].GetVerb(), verb)
   362  		}
   363  	}
   364  }
   365  
   366  func TestStatefulSetScaleFailsPreconditions(t *testing.T) {
   367  	scaleClientExpectedAction := []string{"get"}
   368  	scaleClient := createFakeScaleClient("statefulsets", "foo", 10, nil)
   369  	scaler := NewScaler(scaleClient)
   370  	preconditions := ScalePrecondition{2, ""}
   371  	count := uint(3)
   372  	name := "foo"
   373  	err := scaler.Scale("default", name, count, &preconditions, nil, nil, stsgvr, false)
   374  	if err == nil {
   375  		t.Fatal("expected to get an error but none was returned")
   376  	}
   377  	actions := scaleClient.Actions()
   378  	if len(actions) != len(scaleClientExpectedAction) {
   379  		t.Errorf("unexpected actions: %v, expected %d actions got %d", actions, len(scaleClientExpectedAction), len(actions))
   380  	}
   381  	for i, verb := range scaleClientExpectedAction {
   382  		if actions[i].GetVerb() != verb {
   383  			t.Errorf("unexpected action: %+v, expected %s", actions[i].GetVerb(), verb)
   384  		}
   385  	}
   386  }
   387  
   388  func TestReplicaSetScale(t *testing.T) {
   389  	scaleClientExpectedAction := []string{"patch"}
   390  	scaleClient := createFakeScaleClient("replicasets", "foo", 10, nil)
   391  	scaler := NewScaler(scaleClient)
   392  	count := uint(3)
   393  	name := "foo"
   394  	err := scaler.Scale("default", name, count, nil, nil, nil, rsgvr, false)
   395  	if err != nil {
   396  		t.Fatal(err)
   397  	}
   398  	actions := scaleClient.Actions()
   399  	if len(actions) != len(scaleClientExpectedAction) {
   400  		t.Errorf("unexpected actions: %v, expected %d actions got %d", actions, len(scaleClientExpectedAction), len(actions))
   401  	}
   402  	for i, verb := range scaleClientExpectedAction {
   403  		if actions[i].GetVerb() != verb {
   404  			t.Errorf("unexpected action: %+v, expected %s", actions[i].GetVerb(), verb)
   405  		}
   406  	}
   407  }
   408  
   409  func TestReplicaSetScaleRetry(t *testing.T) {
   410  	verbsOnError := map[string]*apierrors.StatusError{
   411  		"patch": apierrors.NewConflict(api.Resource("Status"), "foo", nil),
   412  	}
   413  	scaleClientExpectedAction := []string{"patch", "get"}
   414  	scaleClient := createFakeScaleClient("replicasets", "foo", 2, verbsOnError)
   415  	scaler := NewScaler(scaleClient)
   416  	count := uint(3)
   417  	name := "foo"
   418  	namespace := "default"
   419  
   420  	scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, rsgvr, false)
   421  	pass, err := scaleFunc()
   422  	if pass != false {
   423  		t.Errorf("Expected an update failure to return pass = false, got pass = %v", pass)
   424  	}
   425  	if err != nil {
   426  		t.Errorf("Did not expect an error on update failure, got %v", err)
   427  	}
   428  	preconditions := &ScalePrecondition{3, ""}
   429  	scaleFunc = ScaleCondition(scaler, preconditions, namespace, name, count, nil, rsgvr, false)
   430  	_, err = scaleFunc()
   431  	if err == nil {
   432  		t.Error("Expected error on precondition failure")
   433  	}
   434  	actions := scaleClient.Actions()
   435  	if len(actions) != len(scaleClientExpectedAction) {
   436  		t.Errorf("unexpected actions: %v, expected %d actions got %d", actions, len(scaleClientExpectedAction), len(actions))
   437  	}
   438  	for i, verb := range scaleClientExpectedAction {
   439  		if actions[i].GetVerb() != verb {
   440  			t.Errorf("unexpected action: %+v, expected %s", actions[i].GetVerb(), verb)
   441  		}
   442  	}
   443  }
   444  
   445  func TestReplicaSetScaleInvalid(t *testing.T) {
   446  	verbsOnError := map[string]*apierrors.StatusError{
   447  		"patch": apierrors.NewInvalid(api.Kind("Status"), "foo", nil),
   448  	}
   449  	scaleClientExpectedAction := []string{"patch"}
   450  	scaleClient := createFakeScaleClient("replicasets", "foo", 2, verbsOnError)
   451  	scaler := NewScaler(scaleClient)
   452  	count := uint(3)
   453  	name := "foo"
   454  	namespace := "default"
   455  
   456  	scaleFunc := ScaleCondition(scaler, nil, namespace, name, count, nil, rsgvr, false)
   457  	pass, err := scaleFunc()
   458  	if pass {
   459  		t.Errorf("Expected an update failure to return pass = false, got pass = %v", pass)
   460  	}
   461  	if err == nil {
   462  		t.Errorf("Expected error on invalid update failure, got %v", err)
   463  	}
   464  	actions := scaleClient.Actions()
   465  	if len(actions) != len(scaleClientExpectedAction) {
   466  		t.Errorf("unexpected actions: %v, expected %d actions got %d", actions, len(scaleClientExpectedAction), len(actions))
   467  	}
   468  	for i, verb := range scaleClientExpectedAction {
   469  		if actions[i].GetVerb() != verb {
   470  			t.Errorf("unexpected action: %+v, expected %s", actions[i].GetVerb(), verb)
   471  		}
   472  	}
   473  }
   474  
   475  func TestReplicaSetsGetterFailsPreconditions(t *testing.T) {
   476  	scaleClientExpectedAction := []string{"get"}
   477  	scaleClient := createFakeScaleClient("replicasets", "foo", 10, nil)
   478  	scaler := NewScaler(scaleClient)
   479  	preconditions := ScalePrecondition{2, ""}
   480  	count := uint(3)
   481  	name := "foo"
   482  	err := scaler.Scale("default", name, count, &preconditions, nil, nil, rsgvr, false)
   483  	if err == nil {
   484  		t.Fatal("expected to get an error but non was returned")
   485  	}
   486  	actions := scaleClient.Actions()
   487  	if len(actions) != len(scaleClientExpectedAction) {
   488  		t.Errorf("unexpected actions: %v, expected %d actions got %d", actions, len(scaleClientExpectedAction), len(actions))
   489  	}
   490  	for i, verb := range scaleClientExpectedAction {
   491  		if actions[i].GetVerb() != verb {
   492  			t.Errorf("unexpected action: %+v, expected %s", actions[i].GetVerb(), verb)
   493  		}
   494  	}
   495  }
   496  
   497  // TestGenericScaleSimple exercises GenericScaler.ScaleSimple method
   498  func TestGenericScaleSimple(t *testing.T) {
   499  	// test data
   500  	scaleClient := createFakeScaleClient("deployments", "abc", 5, nil)
   501  	// expected actions
   502  	scaleClientExpectedAction := []string{"patch", "get", "update", "get", "update", "get", "get", "update", "get"}
   503  
   504  	// test scenarios
   505  	scenarios := []struct {
   506  		name         string
   507  		precondition *ScalePrecondition
   508  		newSize      int
   509  		targetGVR    schema.GroupVersionResource
   510  		resName      string
   511  		scaleGetter  scale.ScalesGetter
   512  		expectError  bool
   513  	}{
   514  		// scenario 0: scale up the "abc" deployment without precondition
   515  		{
   516  			name:         "scale up the \"abc\" deployment without precondition",
   517  			precondition: nil,
   518  			newSize:      10,
   519  			targetGVR:    deploygvr,
   520  			resName:      "abc",
   521  			scaleGetter:  scaleClient,
   522  		},
   523  		// scenario 1: scale up the "abc" deployment
   524  		{
   525  			name:         "scale up the \"abc\" deployment",
   526  			precondition: &ScalePrecondition{10, ""},
   527  			newSize:      20,
   528  			targetGVR:    deploygvr,
   529  			resName:      "abc",
   530  			scaleGetter:  scaleClient,
   531  		},
   532  		// scenario 2: scale down the "abc" deployment
   533  		{
   534  			name:         "scale down the \"abs\" deployment",
   535  			precondition: &ScalePrecondition{20, ""},
   536  			newSize:      5,
   537  			targetGVR:    deploygvr,
   538  			resName:      "abc",
   539  			scaleGetter:  scaleClient,
   540  		},
   541  		// scenario 3: precondition error, expected size is 1,
   542  		// note that the previous scenario (2) set the size to 5
   543  		{
   544  			name:         "precondition error, expected size is 1",
   545  			precondition: &ScalePrecondition{1, ""},
   546  			newSize:      5,
   547  			targetGVR:    deploygvr,
   548  			resName:      "abc",
   549  			scaleGetter:  scaleClient,
   550  			expectError:  true,
   551  		},
   552  		// scenario 4: precondition is not validated when the precondition size is set to -1
   553  		{
   554  			name:         "precondition is not validated when the size is set to -1",
   555  			precondition: &ScalePrecondition{-1, ""},
   556  			newSize:      5,
   557  			targetGVR:    deploygvr,
   558  			resName:      "abc",
   559  			scaleGetter:  scaleClient,
   560  		},
   561  		// scenario 5: precondition error, resource version mismatch
   562  		{
   563  			name:         "precondition error, resource version mismatch",
   564  			precondition: &ScalePrecondition{5, "v1"},
   565  			newSize:      5,
   566  			targetGVR:    deploygvr,
   567  			resName:      "abc",
   568  			scaleGetter:  scaleClient,
   569  			expectError:  true,
   570  		},
   571  	}
   572  
   573  	// act
   574  	for index, scenario := range scenarios {
   575  		t.Run(fmt.Sprintf("running scenario %d: %s", index+1, scenario.name), func(t *testing.T) {
   576  			target := NewScaler(scenario.scaleGetter)
   577  
   578  			resVersion, err := target.ScaleSimple("default", scenario.resName, scenario.precondition, uint(scenario.newSize), scenario.targetGVR, false)
   579  
   580  			if scenario.expectError && err == nil {
   581  				t.Fatal("expected an error but was not returned")
   582  			}
   583  			if !scenario.expectError && err != nil {
   584  				t.Fatalf("unexpected error: %v", err)
   585  			}
   586  			if resVersion != "" {
   587  				t.Fatalf("unexpected resource version returned = %s, wanted = %s", resVersion, "")
   588  			}
   589  		})
   590  	}
   591  
   592  	// check actions
   593  	actions := scaleClient.Actions()
   594  	if len(actions) != len(scaleClientExpectedAction) {
   595  		t.Errorf("unexpected actions: %v, expected %d actions got %d", actions, len(scaleClientExpectedAction), len(actions))
   596  	}
   597  	for i, verb := range scaleClientExpectedAction {
   598  		if actions[i].GetVerb() != verb {
   599  			t.Errorf("unexpected action: %+v, expected %s", actions[i].GetVerb(), verb)
   600  		}
   601  	}
   602  }
   603  
   604  // TestGenericScale exercises GenericScaler.Scale method
   605  func TestGenericScale(t *testing.T) {
   606  	// test data
   607  	scaleClient := createFakeScaleClient("deployments", "abc", 5, nil)
   608  	// expected actions
   609  	scaleClientExpectedAction := []string{"patch", "get", "update", "get", "get"}
   610  
   611  	// test scenarios
   612  	scenarios := []struct {
   613  		name            string
   614  		precondition    *ScalePrecondition
   615  		newSize         int
   616  		targetGVR       schema.GroupVersionResource
   617  		resName         string
   618  		scaleGetter     scale.ScalesGetter
   619  		waitForReplicas *RetryParams
   620  		expectError     bool
   621  	}{
   622  		// scenario 0: scale up the "abc" deployment without precondition
   623  		{
   624  			name:         "scale up the \"abc\" deployment without precondition",
   625  			precondition: nil,
   626  			newSize:      10,
   627  			targetGVR:    deploygvr,
   628  			resName:      "abc",
   629  			scaleGetter:  scaleClient,
   630  		},
   631  		// scenario 1: scale up the "abc" deployment
   632  		{
   633  			name:         "scale up the \"abc\" deployment",
   634  			precondition: &ScalePrecondition{10, ""},
   635  			newSize:      20,
   636  			targetGVR:    deploygvr,
   637  			resName:      "abc",
   638  			scaleGetter:  scaleClient,
   639  		},
   640  		//scenario 2: a resource name cannot be empty
   641  		{
   642  			name:         "a resource name cannot be empty",
   643  			precondition: &ScalePrecondition{10, ""},
   644  			newSize:      20,
   645  			targetGVR:    deploygvr,
   646  			resName:      "",
   647  			scaleGetter:  scaleClient,
   648  			expectError:  true,
   649  		},
   650  		// scenario 3: wait for replicas error due to status.Replicas != spec.Replicas
   651  		{
   652  			name:            "wait for replicas error due to status.Replicas != spec.Replicas",
   653  			precondition:    &ScalePrecondition{10, ""},
   654  			newSize:         20,
   655  			targetGVR:       deploygvr,
   656  			resName:         "abc",
   657  			scaleGetter:     scaleClient,
   658  			waitForReplicas: &RetryParams{time.Duration(5 * time.Second), time.Duration(5 * time.Second)},
   659  			expectError:     true,
   660  		},
   661  	}
   662  
   663  	// act
   664  	for _, scenario := range scenarios {
   665  		t.Run(scenario.name, func(t *testing.T) {
   666  			target := NewScaler(scenario.scaleGetter)
   667  
   668  			err := target.Scale("default", scenario.resName, uint(scenario.newSize), scenario.precondition, nil, scenario.waitForReplicas, scenario.targetGVR, false)
   669  
   670  			if scenario.expectError && err == nil {
   671  				t.Fatal("expected an error but was not returned")
   672  			}
   673  			if !scenario.expectError && err != nil {
   674  				t.Fatalf("unexpected error: %v", err)
   675  			}
   676  		})
   677  	}
   678  
   679  	// check actions
   680  	actions := scaleClient.Actions()
   681  	if len(actions) != len(scaleClientExpectedAction) {
   682  		t.Errorf("unexpected actions: %v, expected %d actions got %d", actions, len(scaleClientExpectedAction), len(actions))
   683  	}
   684  	for i, verb := range scaleClientExpectedAction {
   685  		if actions[i].GetVerb() != verb {
   686  			t.Errorf("unexpected action: %+v, expected %s", actions[i].GetVerb(), verb)
   687  		}
   688  	}
   689  }
   690  
   691  func createFakeScaleClient(resource string, resourceName string, replicas int, errorsOnVerb map[string]*apierrors.StatusError) *fakescale.FakeScaleClient {
   692  	shouldReturnAnError := func(verb string) (*apierrors.StatusError, bool) {
   693  		if anError, anErrorExists := errorsOnVerb[verb]; anErrorExists {
   694  			return anError, true
   695  		}
   696  		return &apierrors.StatusError{}, false
   697  	}
   698  	newReplicas := int32(replicas)
   699  	scaleClient := &fakescale.FakeScaleClient{}
   700  	scaleClient.AddReactor("get", resource, func(rawAction testcore.Action) (handled bool, ret runtime.Object, err error) {
   701  		action := rawAction.(testcore.GetAction)
   702  		if action.GetName() != resourceName {
   703  			return true, nil, fmt.Errorf("expected = %s, got = %s", resourceName, action.GetName())
   704  		}
   705  		if anError, should := shouldReturnAnError("get"); should {
   706  			return true, nil, anError
   707  		}
   708  		obj := &autoscalingv1.Scale{
   709  			ObjectMeta: metav1.ObjectMeta{
   710  				Name:      action.GetName(),
   711  				Namespace: action.GetNamespace(),
   712  			},
   713  			Spec: autoscalingv1.ScaleSpec{
   714  				Replicas: newReplicas,
   715  			},
   716  		}
   717  		return true, obj, nil
   718  	})
   719  
   720  	scaleClient.AddReactor("update", resource, func(rawAction testcore.Action) (handled bool, ret runtime.Object, err error) {
   721  		action := rawAction.(testcore.UpdateAction)
   722  		obj := action.GetObject().(*autoscalingv1.Scale)
   723  		if obj.Name != resourceName {
   724  			return true, nil, fmt.Errorf("expected = %s, got = %s", resourceName, obj.Name)
   725  		}
   726  		if anError, should := shouldReturnAnError("update"); should {
   727  			return true, nil, anError
   728  		}
   729  		newReplicas = obj.Spec.Replicas
   730  		return true, &autoscalingv1.Scale{
   731  			ObjectMeta: metav1.ObjectMeta{
   732  				Name:      obj.Name,
   733  				Namespace: action.GetNamespace(),
   734  			},
   735  			Spec: autoscalingv1.ScaleSpec{
   736  				Replicas: newReplicas,
   737  			},
   738  		}, nil
   739  	})
   740  
   741  	scaleClient.AddReactor("patch", resource, func(rawAction testcore.Action) (handled bool, ret runtime.Object, err error) {
   742  		action := rawAction.(testcore.PatchAction)
   743  		pt := action.GetPatchType()
   744  		if pt != types.MergePatchType {
   745  			return true, nil, fmt.Errorf("unexpected patch type: expected = %s, got = %s", types.MergePatchType, pt)
   746  		}
   747  		var scale autoscalingv1.Scale
   748  		err = json.Unmarshal(action.GetPatch(), &scale)
   749  		if err != nil {
   750  			return true, nil, fmt.Errorf("invalid patch: %s", err)
   751  		}
   752  		name := action.GetName()
   753  		if name != resourceName {
   754  			return true, nil, fmt.Errorf("expected = %s, got = %s", resourceName, name)
   755  		}
   756  		if anError, should := shouldReturnAnError("patch"); should {
   757  			return true, nil, anError
   758  		}
   759  		newReplicas = scale.Spec.Replicas
   760  		return true, &autoscalingv1.Scale{
   761  			ObjectMeta: metav1.ObjectMeta{
   762  				Name:      name,
   763  				Namespace: action.GetNamespace(),
   764  			},
   765  			Spec: autoscalingv1.ScaleSpec{
   766  				Replicas: newReplicas,
   767  			},
   768  		}, nil
   769  	})
   770  	return scaleClient
   771  }
   772  

View as plain text