...

Source file src/k8s.io/kubernetes/pkg/util/taints/taints_test.go

Documentation: k8s.io/kubernetes/pkg/util/taints

     1  /*
     2  Copyright 2016 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 taints
    18  
    19  import (
    20  	"reflect"
    21  	"strings"
    22  	"testing"
    23  
    24  	v1 "k8s.io/api/core/v1"
    25  
    26  	"github.com/google/go-cmp/cmp"
    27  )
    28  
    29  func TestAddOrUpdateTaint(t *testing.T) {
    30  	taint := v1.Taint{
    31  		Key:    "foo",
    32  		Value:  "bar",
    33  		Effect: v1.TaintEffectNoSchedule,
    34  	}
    35  
    36  	taintNew := v1.Taint{
    37  		Key:    "foo_1",
    38  		Value:  "bar_1",
    39  		Effect: v1.TaintEffectNoSchedule,
    40  	}
    41  
    42  	taintUpdateValue := taint
    43  	taintUpdateValue.Value = "bar_1"
    44  
    45  	testcases := []struct {
    46  		name           string
    47  		node           *v1.Node
    48  		taint          *v1.Taint
    49  		expectedUpdate bool
    50  		expectedTaints []v1.Taint
    51  	}{
    52  		{
    53  			name:           "add a new taint",
    54  			node:           &v1.Node{},
    55  			taint:          &taint,
    56  			expectedUpdate: true,
    57  			expectedTaints: []v1.Taint{taint},
    58  		},
    59  		{
    60  			name: "add a unique taint",
    61  			node: &v1.Node{
    62  				Spec: v1.NodeSpec{Taints: []v1.Taint{taint}},
    63  			},
    64  			taint:          &taintNew,
    65  			expectedUpdate: true,
    66  			expectedTaints: []v1.Taint{taint, taintNew},
    67  		},
    68  		{
    69  			name: "add duplicate taint",
    70  			node: &v1.Node{
    71  				Spec: v1.NodeSpec{Taints: []v1.Taint{taint}},
    72  			},
    73  			taint:          &taint,
    74  			expectedUpdate: false,
    75  			expectedTaints: []v1.Taint{taint},
    76  		},
    77  		{
    78  			name: "update taint value",
    79  			node: &v1.Node{
    80  				Spec: v1.NodeSpec{Taints: []v1.Taint{taint}},
    81  			},
    82  			taint:          &taintUpdateValue,
    83  			expectedUpdate: true,
    84  			expectedTaints: []v1.Taint{taintUpdateValue},
    85  		},
    86  	}
    87  
    88  	for _, tc := range testcases {
    89  		t.Run(tc.name, func(t *testing.T) {
    90  			newNode, updated, err := AddOrUpdateTaint(tc.node, tc.taint)
    91  			if err != nil {
    92  				t.Errorf("[%s] should not raise error but got %v", tc.name, err)
    93  			}
    94  			if updated != tc.expectedUpdate {
    95  				t.Errorf("[%s] expected taints to not be updated", tc.name)
    96  			}
    97  			if diff := cmp.Diff(newNode.Spec.Taints, tc.expectedTaints); diff != "" {
    98  				t.Errorf("Unexpected result (-want, +got):\n%s", diff)
    99  			}
   100  		})
   101  	}
   102  }
   103  
   104  func TestTaintExists(t *testing.T) {
   105  	testingTaints := []v1.Taint{
   106  		{
   107  			Key:    "foo_1",
   108  			Value:  "bar_1",
   109  			Effect: v1.TaintEffectNoExecute,
   110  		},
   111  		{
   112  			Key:    "foo_2",
   113  			Value:  "bar_2",
   114  			Effect: v1.TaintEffectNoSchedule,
   115  		},
   116  	}
   117  
   118  	cases := []struct {
   119  		name           string
   120  		taintToFind    *v1.Taint
   121  		expectedResult bool
   122  	}{
   123  		{
   124  			name:           "taint exists",
   125  			taintToFind:    &v1.Taint{Key: "foo_1", Value: "bar_1", Effect: v1.TaintEffectNoExecute},
   126  			expectedResult: true,
   127  		},
   128  		{
   129  			name:           "different key",
   130  			taintToFind:    &v1.Taint{Key: "no_such_key", Value: "bar_1", Effect: v1.TaintEffectNoExecute},
   131  			expectedResult: false,
   132  		},
   133  		{
   134  			name:           "different effect",
   135  			taintToFind:    &v1.Taint{Key: "foo_1", Value: "bar_1", Effect: v1.TaintEffectNoSchedule},
   136  			expectedResult: false,
   137  		},
   138  	}
   139  
   140  	for _, c := range cases {
   141  		result := TaintExists(testingTaints, c.taintToFind)
   142  
   143  		if result != c.expectedResult {
   144  			t.Errorf("[%s] unexpected results: %v", c.name, result)
   145  			continue
   146  		}
   147  	}
   148  }
   149  
   150  func TestTaintKeyExists(t *testing.T) {
   151  	testingTaints := []v1.Taint{
   152  		{
   153  			Key:    "foo_1",
   154  			Value:  "bar_1",
   155  			Effect: v1.TaintEffectNoExecute,
   156  		},
   157  		{
   158  			Key:    "foo_2",
   159  			Value:  "bar_2",
   160  			Effect: v1.TaintEffectNoSchedule,
   161  		},
   162  	}
   163  
   164  	cases := []struct {
   165  		name            string
   166  		taintKeyToMatch string
   167  		expectedResult  bool
   168  	}{
   169  		{
   170  			name:            "taint key exists",
   171  			taintKeyToMatch: "foo_1",
   172  			expectedResult:  true,
   173  		},
   174  		{
   175  			name:            "taint key does not exist",
   176  			taintKeyToMatch: "foo_3",
   177  			expectedResult:  false,
   178  		},
   179  	}
   180  
   181  	for _, c := range cases {
   182  		t.Run(c.name, func(t *testing.T) {
   183  			result := TaintKeyExists(testingTaints, c.taintKeyToMatch)
   184  
   185  			if result != c.expectedResult {
   186  				t.Errorf("[%s] unexpected results: %v", c.name, result)
   187  			}
   188  		})
   189  	}
   190  }
   191  
   192  func TestTaintSetFilter(t *testing.T) {
   193  	testTaint1 := v1.Taint{
   194  		Key:    "foo_1",
   195  		Value:  "bar_1",
   196  		Effect: v1.TaintEffectNoExecute,
   197  	}
   198  	testTaint2 := v1.Taint{
   199  		Key:    "foo_2",
   200  		Value:  "bar_2",
   201  		Effect: v1.TaintEffectNoSchedule,
   202  	}
   203  
   204  	testTaint3 := v1.Taint{
   205  		Key:    "foo_3",
   206  		Value:  "bar_3",
   207  		Effect: v1.TaintEffectNoSchedule,
   208  	}
   209  	testTaints := []v1.Taint{testTaint1, testTaint2, testTaint3}
   210  
   211  	testcases := []struct {
   212  		name           string
   213  		fn             func(t *v1.Taint) bool
   214  		expectedTaints []v1.Taint
   215  	}{
   216  		{
   217  			name: "Filter out nothing",
   218  			fn: func(t *v1.Taint) bool {
   219  				if t.Key == v1.TaintNodeUnschedulable {
   220  					return true
   221  				}
   222  				return false
   223  			},
   224  			expectedTaints: []v1.Taint{},
   225  		},
   226  		{
   227  			name: "Filter out a subset",
   228  			fn: func(t *v1.Taint) bool {
   229  				if t.Effect == v1.TaintEffectNoExecute {
   230  					return true
   231  				}
   232  				return false
   233  			},
   234  			expectedTaints: []v1.Taint{testTaint1},
   235  		},
   236  		{
   237  			name:           "Filter out everything",
   238  			fn:             func(t *v1.Taint) bool { return true },
   239  			expectedTaints: []v1.Taint{testTaint1, testTaint2, testTaint3},
   240  		},
   241  	}
   242  	for _, tc := range testcases {
   243  		t.Run(tc.name, func(t *testing.T) {
   244  			taintsAfterFilter := TaintSetFilter(testTaints, tc.fn)
   245  			if diff := cmp.Diff(tc.expectedTaints, taintsAfterFilter); diff != "" {
   246  				t.Errorf("Unexpected postFilterResult (-want, +got):\n%s", diff)
   247  			}
   248  		})
   249  	}
   250  }
   251  
   252  func TestRemoveTaint(t *testing.T) {
   253  	cases := []struct {
   254  		name           string
   255  		node           *v1.Node
   256  		taintToRemove  *v1.Taint
   257  		expectedTaints []v1.Taint
   258  		expectedResult bool
   259  	}{
   260  		{
   261  			name: "remove taint unsuccessfully",
   262  			node: &v1.Node{
   263  				Spec: v1.NodeSpec{
   264  					Taints: []v1.Taint{
   265  						{
   266  							Key:    "foo",
   267  							Effect: v1.TaintEffectNoSchedule,
   268  						},
   269  					},
   270  				},
   271  			},
   272  			taintToRemove: &v1.Taint{
   273  				Key:    "foo_1",
   274  				Effect: v1.TaintEffectNoSchedule,
   275  			},
   276  			expectedTaints: []v1.Taint{
   277  				{
   278  					Key:    "foo",
   279  					Effect: v1.TaintEffectNoSchedule,
   280  				},
   281  			},
   282  			expectedResult: false,
   283  		},
   284  		{
   285  			name: "remove taint successfully",
   286  			node: &v1.Node{
   287  				Spec: v1.NodeSpec{
   288  					Taints: []v1.Taint{
   289  						{
   290  							Key:    "foo",
   291  							Effect: v1.TaintEffectNoSchedule,
   292  						},
   293  					},
   294  				},
   295  			},
   296  			taintToRemove: &v1.Taint{
   297  				Key:    "foo",
   298  				Effect: v1.TaintEffectNoSchedule,
   299  			},
   300  			expectedTaints: []v1.Taint{},
   301  			expectedResult: true,
   302  		},
   303  		{
   304  			name: "remove taint from node with no taint",
   305  			node: &v1.Node{
   306  				Spec: v1.NodeSpec{
   307  					Taints: []v1.Taint{},
   308  				},
   309  			},
   310  			taintToRemove: &v1.Taint{
   311  				Key:    "foo",
   312  				Effect: v1.TaintEffectNoSchedule,
   313  			},
   314  			expectedTaints: []v1.Taint{},
   315  			expectedResult: false,
   316  		},
   317  	}
   318  
   319  	for _, c := range cases {
   320  		newNode, result, err := RemoveTaint(c.node, c.taintToRemove)
   321  		if err != nil {
   322  			t.Errorf("[%s] should not raise error but got: %v", c.name, err)
   323  		}
   324  		if result != c.expectedResult {
   325  			t.Errorf("[%s] should return %t, but got: %t", c.name, c.expectedResult, result)
   326  		}
   327  		if !reflect.DeepEqual(newNode.Spec.Taints, c.expectedTaints) {
   328  			t.Errorf("[%s] the new node object should have taints %v, but got: %v", c.name, c.expectedTaints, newNode.Spec.Taints)
   329  		}
   330  	}
   331  }
   332  
   333  func TestDeleteTaint(t *testing.T) {
   334  	cases := []struct {
   335  		name           string
   336  		taints         []v1.Taint
   337  		taintToDelete  *v1.Taint
   338  		expectedTaints []v1.Taint
   339  		expectedResult bool
   340  	}{
   341  		{
   342  			name: "delete taint with different name",
   343  			taints: []v1.Taint{
   344  				{
   345  					Key:    "foo",
   346  					Effect: v1.TaintEffectNoSchedule,
   347  				},
   348  			},
   349  			taintToDelete: &v1.Taint{Key: "foo_1", Effect: v1.TaintEffectNoSchedule},
   350  			expectedTaints: []v1.Taint{
   351  				{
   352  					Key:    "foo",
   353  					Effect: v1.TaintEffectNoSchedule,
   354  				},
   355  			},
   356  			expectedResult: false,
   357  		},
   358  		{
   359  			name: "delete taint with different effect",
   360  			taints: []v1.Taint{
   361  				{
   362  					Key:    "foo",
   363  					Effect: v1.TaintEffectNoSchedule,
   364  				},
   365  			},
   366  			taintToDelete: &v1.Taint{Key: "foo", Effect: v1.TaintEffectNoExecute},
   367  			expectedTaints: []v1.Taint{
   368  				{
   369  					Key:    "foo",
   370  					Effect: v1.TaintEffectNoSchedule,
   371  				},
   372  			},
   373  			expectedResult: false,
   374  		},
   375  		{
   376  			name: "delete taint successfully",
   377  			taints: []v1.Taint{
   378  				{
   379  					Key:    "foo",
   380  					Effect: v1.TaintEffectNoSchedule,
   381  				},
   382  			},
   383  			taintToDelete:  &v1.Taint{Key: "foo", Effect: v1.TaintEffectNoSchedule},
   384  			expectedTaints: []v1.Taint{},
   385  			expectedResult: true,
   386  		},
   387  		{
   388  			name:           "delete taint from empty taint array",
   389  			taints:         []v1.Taint{},
   390  			taintToDelete:  &v1.Taint{Key: "foo", Effect: v1.TaintEffectNoSchedule},
   391  			expectedTaints: []v1.Taint{},
   392  			expectedResult: false,
   393  		},
   394  	}
   395  
   396  	for _, c := range cases {
   397  		taints, result := DeleteTaint(c.taints, c.taintToDelete)
   398  		if result != c.expectedResult {
   399  			t.Errorf("[%s] should return %t, but got: %t", c.name, c.expectedResult, result)
   400  		}
   401  		if !reflect.DeepEqual(taints, c.expectedTaints) {
   402  			t.Errorf("[%s] the result taints should be %v, but got: %v", c.name, c.expectedTaints, taints)
   403  		}
   404  	}
   405  }
   406  
   407  func TestDeleteTaintByKey(t *testing.T) {
   408  	cases := []struct {
   409  		name           string
   410  		taints         []v1.Taint
   411  		taintKey       string
   412  		expectedTaints []v1.Taint
   413  		expectedResult bool
   414  	}{
   415  		{
   416  			name: "delete taint unsuccessfully",
   417  			taints: []v1.Taint{
   418  				{
   419  					Key:    "foo",
   420  					Value:  "bar",
   421  					Effect: v1.TaintEffectNoSchedule,
   422  				},
   423  			},
   424  			taintKey: "foo_1",
   425  			expectedTaints: []v1.Taint{
   426  				{
   427  					Key:    "foo",
   428  					Value:  "bar",
   429  					Effect: v1.TaintEffectNoSchedule,
   430  				},
   431  			},
   432  			expectedResult: false,
   433  		},
   434  		{
   435  			name: "delete taint successfully",
   436  			taints: []v1.Taint{
   437  				{
   438  					Key:    "foo",
   439  					Value:  "bar",
   440  					Effect: v1.TaintEffectNoSchedule,
   441  				},
   442  			},
   443  			taintKey:       "foo",
   444  			expectedTaints: []v1.Taint{},
   445  			expectedResult: true,
   446  		},
   447  		{
   448  			name:           "delete taint from empty taint array",
   449  			taints:         []v1.Taint{},
   450  			taintKey:       "foo",
   451  			expectedTaints: []v1.Taint{},
   452  			expectedResult: false,
   453  		},
   454  	}
   455  
   456  	for _, c := range cases {
   457  		taints, result := DeleteTaintsByKey(c.taints, c.taintKey)
   458  		if result != c.expectedResult {
   459  			t.Errorf("[%s] should return %t, but got: %t", c.name, c.expectedResult, result)
   460  		}
   461  		if !reflect.DeepEqual(c.expectedTaints, taints) {
   462  			t.Errorf("[%s] the result taints should be %v, but got: %v", c.name, c.expectedTaints, taints)
   463  		}
   464  	}
   465  }
   466  
   467  func TestCheckIfTaintsAlreadyExists(t *testing.T) {
   468  	oldTaints := []v1.Taint{
   469  		{
   470  			Key:    "foo_1",
   471  			Value:  "bar",
   472  			Effect: v1.TaintEffectNoSchedule,
   473  		},
   474  		{
   475  			Key:    "foo_2",
   476  			Value:  "bar",
   477  			Effect: v1.TaintEffectNoSchedule,
   478  		},
   479  		{
   480  			Key:    "foo_3",
   481  			Value:  "bar",
   482  			Effect: v1.TaintEffectNoSchedule,
   483  		},
   484  	}
   485  
   486  	cases := []struct {
   487  		name           string
   488  		taintsToCheck  []v1.Taint
   489  		expectedResult string
   490  	}{
   491  		{
   492  			name:           "empty array",
   493  			taintsToCheck:  []v1.Taint{},
   494  			expectedResult: "",
   495  		},
   496  		{
   497  			name: "no match",
   498  			taintsToCheck: []v1.Taint{
   499  				{
   500  					Key:    "foo_1",
   501  					Effect: v1.TaintEffectNoExecute,
   502  				},
   503  			},
   504  			expectedResult: "",
   505  		},
   506  		{
   507  			name: "match one taint",
   508  			taintsToCheck: []v1.Taint{
   509  				{
   510  					Key:    "foo_2",
   511  					Effect: v1.TaintEffectNoSchedule,
   512  				},
   513  			},
   514  			expectedResult: "foo_2",
   515  		},
   516  		{
   517  			name: "match two taints",
   518  			taintsToCheck: []v1.Taint{
   519  				{
   520  					Key:    "foo_2",
   521  					Effect: v1.TaintEffectNoSchedule,
   522  				},
   523  				{
   524  					Key:    "foo_3",
   525  					Effect: v1.TaintEffectNoSchedule,
   526  				},
   527  			},
   528  			expectedResult: "foo_2,foo_3",
   529  		},
   530  	}
   531  
   532  	for _, c := range cases {
   533  		result := CheckIfTaintsAlreadyExists(oldTaints, c.taintsToCheck)
   534  		if result != c.expectedResult {
   535  			t.Errorf("[%s] should return '%s', but got: '%s'", c.name, c.expectedResult, result)
   536  		}
   537  	}
   538  }
   539  
   540  func TestParseTaints(t *testing.T) {
   541  	cases := []struct {
   542  		name                   string
   543  		spec                   []string
   544  		expectedTaints         []v1.Taint
   545  		expectedTaintsToRemove []v1.Taint
   546  		expectedErr            bool
   547  	}{
   548  		{
   549  			name:        "invalid empty spec format",
   550  			spec:        []string{""},
   551  			expectedErr: true,
   552  		},
   553  		// taint spec format without the suffix '-' must be either '<key>=<value>:<effect>', '<key>:<effect>', or '<key>'
   554  		{
   555  			name:        "invalid spec format without effect",
   556  			spec:        []string{"foo=abc"},
   557  			expectedErr: true,
   558  		},
   559  		{
   560  			name:        "invalid spec format with multiple '=' separators",
   561  			spec:        []string{"foo=abc=xyz:NoSchedule"},
   562  			expectedErr: true,
   563  		},
   564  		{
   565  			name:        "invalid spec format with multiple ':' separators",
   566  			spec:        []string{"foo=abc:xyz:NoSchedule"},
   567  			expectedErr: true,
   568  		},
   569  		{
   570  			name:        "invalid spec taint value without separator",
   571  			spec:        []string{"foo"},
   572  			expectedErr: true,
   573  		},
   574  		// taint spec must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character.
   575  		{
   576  			name:        "invalid spec taint value with special chars '%^@'",
   577  			spec:        []string{"foo=nospecialchars%^@:NoSchedule"},
   578  			expectedErr: true,
   579  		},
   580  		{
   581  			name:        "invalid spec taint value with non-alphanumeric characters",
   582  			spec:        []string{"foo=Tama-nui-te-rā.is.Māori.sun:NoSchedule"},
   583  			expectedErr: true,
   584  		},
   585  		{
   586  			name:        "invalid spec taint value with special chars '\\'",
   587  			spec:        []string{"foo=\\backslashes\\are\\bad:NoSchedule"},
   588  			expectedErr: true,
   589  		},
   590  		{
   591  			name:        "invalid spec taint value with start with an non-alphanumeric character '-'",
   592  			spec:        []string{"foo=-starts-with-dash:NoSchedule"},
   593  			expectedErr: true,
   594  		},
   595  		{
   596  			name:        "invalid spec taint value with end with an non-alphanumeric character '-'",
   597  			spec:        []string{"foo=ends-with-dash-:NoSchedule"},
   598  			expectedErr: true,
   599  		},
   600  		{
   601  			name:        "invalid spec taint value with start with an non-alphanumeric character '.'",
   602  			spec:        []string{"foo=.starts.with.dot:NoSchedule"},
   603  			expectedErr: true,
   604  		},
   605  		{
   606  			name:        "invalid spec taint value with end with an non-alphanumeric character '.'",
   607  			spec:        []string{"foo=ends.with.dot.:NoSchedule"},
   608  			expectedErr: true,
   609  		},
   610  		// The value range of taint effect is "NoSchedule", "PreferNoSchedule", "NoExecute"
   611  		{
   612  			name:        "invalid spec effect for adding taint",
   613  			spec:        []string{"foo=abc:invalid_effect"},
   614  			expectedErr: true,
   615  		},
   616  		{
   617  			name:        "invalid spec effect for deleting taint",
   618  			spec:        []string{"foo:invalid_effect-"},
   619  			expectedErr: true,
   620  		},
   621  		{
   622  			name:        "duplicated taints with the same key and effect",
   623  			spec:        []string{"foo=abc:NoSchedule", "foo=abc:NoSchedule"},
   624  			expectedErr: true,
   625  		},
   626  		{
   627  			name:        "invalid spec taint value exceeding the limit",
   628  			spec:        []string{strings.Repeat("a", 64)},
   629  			expectedErr: true,
   630  		},
   631  		{
   632  			name: "add new taints with no special chars",
   633  			spec: []string{"foo=abc:NoSchedule", "bar=abc:NoSchedule", "baz:NoSchedule", "qux:NoSchedule", "foobar=:NoSchedule"},
   634  			expectedTaints: []v1.Taint{
   635  				{
   636  					Key:    "foo",
   637  					Value:  "abc",
   638  					Effect: v1.TaintEffectNoSchedule,
   639  				},
   640  				{
   641  					Key:    "bar",
   642  					Value:  "abc",
   643  					Effect: v1.TaintEffectNoSchedule,
   644  				},
   645  				{
   646  					Key:    "baz",
   647  					Value:  "",
   648  					Effect: v1.TaintEffectNoSchedule,
   649  				},
   650  				{
   651  					Key:    "qux",
   652  					Value:  "",
   653  					Effect: v1.TaintEffectNoSchedule,
   654  				},
   655  				{
   656  					Key:    "foobar",
   657  					Value:  "",
   658  					Effect: v1.TaintEffectNoSchedule,
   659  				},
   660  			},
   661  			expectedErr: false,
   662  		},
   663  		{
   664  			name: "delete taints with no special chars",
   665  			spec: []string{"foo:NoSchedule-", "bar:NoSchedule-", "qux=:NoSchedule-", "dedicated-"},
   666  			expectedTaintsToRemove: []v1.Taint{
   667  				{
   668  					Key:    "foo",
   669  					Effect: v1.TaintEffectNoSchedule,
   670  				},
   671  				{
   672  					Key:    "bar",
   673  					Effect: v1.TaintEffectNoSchedule,
   674  				},
   675  				{
   676  					Key:    "qux",
   677  					Effect: v1.TaintEffectNoSchedule,
   678  				},
   679  				{
   680  					Key: "dedicated",
   681  				},
   682  			},
   683  			expectedErr: false,
   684  		},
   685  		{
   686  			name: "add taints and delete taints with no special chars",
   687  			spec: []string{"foo=abc:NoSchedule", "bar=abc:NoSchedule", "baz:NoSchedule", "qux:NoSchedule", "foobar=:NoSchedule", "foo:NoSchedule-", "bar:NoSchedule-", "baz=:NoSchedule-"},
   688  			expectedTaints: []v1.Taint{
   689  				{
   690  					Key:    "foo",
   691  					Value:  "abc",
   692  					Effect: v1.TaintEffectNoSchedule,
   693  				},
   694  				{
   695  					Key:    "bar",
   696  					Value:  "abc",
   697  					Effect: v1.TaintEffectNoSchedule,
   698  				},
   699  				{
   700  					Key:    "baz",
   701  					Value:  "",
   702  					Effect: v1.TaintEffectNoSchedule,
   703  				},
   704  				{
   705  					Key:    "qux",
   706  					Value:  "",
   707  					Effect: v1.TaintEffectNoSchedule,
   708  				},
   709  				{
   710  					Key:    "foobar",
   711  					Value:  "",
   712  					Effect: v1.TaintEffectNoSchedule,
   713  				},
   714  			},
   715  			expectedTaintsToRemove: []v1.Taint{
   716  				{
   717  					Key:    "foo",
   718  					Effect: v1.TaintEffectNoSchedule,
   719  				},
   720  				{
   721  					Key:    "bar",
   722  					Effect: v1.TaintEffectNoSchedule,
   723  				},
   724  				{
   725  					Key:    "baz",
   726  					Value:  "",
   727  					Effect: v1.TaintEffectNoSchedule,
   728  				},
   729  			},
   730  			expectedErr: false,
   731  		},
   732  	}
   733  
   734  	for _, c := range cases {
   735  		taints, taintsToRemove, err := ParseTaints(c.spec)
   736  		if c.expectedErr && err == nil {
   737  			t.Errorf("[%s] expected error for spec %s, but got nothing", c.name, c.spec)
   738  		}
   739  		if !c.expectedErr && err != nil {
   740  			t.Errorf("[%s] expected no error for spec %s, but got: %v", c.name, c.spec, err)
   741  		}
   742  		if !reflect.DeepEqual(c.expectedTaints, taints) {
   743  			t.Errorf("[%s] expected returen taints as %v, but got: %v", c.name, c.expectedTaints, taints)
   744  		}
   745  		if !reflect.DeepEqual(c.expectedTaintsToRemove, taintsToRemove) {
   746  			t.Errorf("[%s] expected return taints to be removed as %v, but got: %v", c.name, c.expectedTaintsToRemove, taintsToRemove)
   747  		}
   748  	}
   749  }
   750  
   751  func TestValidateTaint(t *testing.T) {
   752  	cases := []struct {
   753  		name          string
   754  		taintsToCheck v1.Taint
   755  		expectedErr   bool
   756  	}{
   757  		{
   758  			name:          "taint invalid key",
   759  			taintsToCheck: v1.Taint{Key: "", Value: "bar_1", Effect: v1.TaintEffectNoExecute},
   760  			expectedErr:   true,
   761  		},
   762  		{
   763  			name:          "taint invalid value",
   764  			taintsToCheck: v1.Taint{Key: "foo_1", Value: strings.Repeat("a", 64), Effect: v1.TaintEffectNoExecute},
   765  			expectedErr:   true,
   766  		},
   767  		{
   768  			name:          "taint invalid effect",
   769  			taintsToCheck: v1.Taint{Key: "foo_2", Value: "bar_2", Effect: "no_such_effect"},
   770  			expectedErr:   true,
   771  		},
   772  		{
   773  			name:          "valid taint",
   774  			taintsToCheck: v1.Taint{Key: "foo_3", Value: "bar_3", Effect: v1.TaintEffectNoExecute},
   775  			expectedErr:   false,
   776  		},
   777  		{
   778  			name:          "valid taint",
   779  			taintsToCheck: v1.Taint{Key: "foo_4", Effect: v1.TaintEffectNoExecute},
   780  			expectedErr:   false,
   781  		},
   782  		{
   783  			name:          "valid taint",
   784  			taintsToCheck: v1.Taint{Key: "foo_5", Value: "bar_5"},
   785  			expectedErr:   false,
   786  		},
   787  	}
   788  
   789  	for _, c := range cases {
   790  		err := CheckTaintValidation(c.taintsToCheck)
   791  
   792  		if c.expectedErr && err == nil {
   793  			t.Errorf("[%s] expected error for spec %+v, but got nothing", c.name, c.taintsToCheck)
   794  		}
   795  	}
   796  }
   797  
   798  func TestTaintSetDiff(t *testing.T) {
   799  	cases := []struct {
   800  		name                   string
   801  		t1                     []v1.Taint
   802  		t2                     []v1.Taint
   803  		expectedTaintsToAdd    []*v1.Taint
   804  		expectedTaintsToRemove []*v1.Taint
   805  	}{
   806  		{
   807  			name:                   "two_taints_are_nil",
   808  			expectedTaintsToAdd:    nil,
   809  			expectedTaintsToRemove: nil,
   810  		},
   811  		{
   812  			name: "one_taint_is_nil_and_the_other_is_not_nil",
   813  			t1: []v1.Taint{
   814  				{
   815  					Key:    "foo_1",
   816  					Value:  "bar_1",
   817  					Effect: v1.TaintEffectNoExecute,
   818  				},
   819  				{
   820  					Key:    "foo_2",
   821  					Value:  "bar_2",
   822  					Effect: v1.TaintEffectNoSchedule,
   823  				},
   824  			},
   825  			expectedTaintsToAdd: []*v1.Taint{
   826  				{
   827  					Key:    "foo_1",
   828  					Value:  "bar_1",
   829  					Effect: v1.TaintEffectNoExecute,
   830  				},
   831  				{
   832  					Key:    "foo_2",
   833  					Value:  "bar_2",
   834  					Effect: v1.TaintEffectNoSchedule,
   835  				},
   836  			},
   837  			expectedTaintsToRemove: nil,
   838  		},
   839  		{
   840  			name: "shared_taints_with_the_same_key_value_effect",
   841  			t1: []v1.Taint{
   842  				{
   843  					Key:    "foo_1",
   844  					Value:  "bar_1",
   845  					Effect: v1.TaintEffectNoExecute,
   846  				},
   847  				{
   848  					Key:    "foo_2",
   849  					Value:  "bar_2",
   850  					Effect: v1.TaintEffectNoSchedule,
   851  				},
   852  			},
   853  			t2: []v1.Taint{
   854  				{
   855  					Key:    "foo_3",
   856  					Value:  "bar_3",
   857  					Effect: v1.TaintEffectNoExecute,
   858  				},
   859  				{
   860  					Key:    "foo_2",
   861  					Value:  "bar_2",
   862  					Effect: v1.TaintEffectNoSchedule,
   863  				},
   864  			},
   865  			expectedTaintsToAdd: []*v1.Taint{
   866  				{
   867  					Key:    "foo_1",
   868  					Value:  "bar_1",
   869  					Effect: v1.TaintEffectNoExecute,
   870  				},
   871  			},
   872  			expectedTaintsToRemove: []*v1.Taint{
   873  				{
   874  					Key:    "foo_3",
   875  					Value:  "bar_3",
   876  					Effect: v1.TaintEffectNoExecute,
   877  				},
   878  			},
   879  		},
   880  		{
   881  			name: "shared_taints_with_the_same_key_effect_different_value",
   882  			t1: []v1.Taint{
   883  				{
   884  					Key:    "foo_1",
   885  					Value:  "bar_1",
   886  					Effect: v1.TaintEffectNoExecute,
   887  				},
   888  				{
   889  					Key:    "foo_2",
   890  					Value:  "different-value",
   891  					Effect: v1.TaintEffectNoSchedule,
   892  				},
   893  			},
   894  			t2: []v1.Taint{
   895  				{
   896  					Key:    "foo_3",
   897  					Value:  "bar_3",
   898  					Effect: v1.TaintEffectNoExecute,
   899  				},
   900  				{
   901  					Key:    "foo_2",
   902  					Value:  "bar_2",
   903  					Effect: v1.TaintEffectNoSchedule,
   904  				},
   905  			},
   906  			expectedTaintsToAdd: []*v1.Taint{
   907  				{
   908  					Key:    "foo_1",
   909  					Value:  "bar_1",
   910  					Effect: v1.TaintEffectNoExecute,
   911  				},
   912  			},
   913  			expectedTaintsToRemove: []*v1.Taint{
   914  				{
   915  					Key:    "foo_3",
   916  					Value:  "bar_3",
   917  					Effect: v1.TaintEffectNoExecute,
   918  				},
   919  			},
   920  		},
   921  		{
   922  			name: "shared_taints_with_the_same_key_different_value_effect",
   923  			t1: []v1.Taint{
   924  				{
   925  					Key:    "foo_1",
   926  					Value:  "bar_1",
   927  					Effect: v1.TaintEffectNoExecute,
   928  				},
   929  				{
   930  					Key:    "foo_2",
   931  					Value:  "different-value",
   932  					Effect: v1.TaintEffectNoExecute,
   933  				},
   934  			},
   935  			t2: []v1.Taint{
   936  				{
   937  					Key:    "foo_3",
   938  					Value:  "bar_3",
   939  					Effect: v1.TaintEffectNoExecute,
   940  				},
   941  				{
   942  					Key:    "foo_2",
   943  					Value:  "bar_2",
   944  					Effect: v1.TaintEffectNoSchedule,
   945  				},
   946  			},
   947  			expectedTaintsToAdd: []*v1.Taint{
   948  				{
   949  					Key:    "foo_1",
   950  					Value:  "bar_1",
   951  					Effect: v1.TaintEffectNoExecute,
   952  				},
   953  				{
   954  					Key:    "foo_2",
   955  					Value:  "different-value",
   956  					Effect: v1.TaintEffectNoExecute,
   957  				},
   958  			},
   959  			expectedTaintsToRemove: []*v1.Taint{
   960  				{
   961  					Key:    "foo_3",
   962  					Value:  "bar_3",
   963  					Effect: v1.TaintEffectNoExecute,
   964  				},
   965  				{
   966  					Key:    "foo_2",
   967  					Value:  "bar_2",
   968  					Effect: v1.TaintEffectNoSchedule,
   969  				},
   970  			},
   971  		},
   972  	}
   973  
   974  	for _, tt := range cases {
   975  		t.Run(tt.name, func(t *testing.T) {
   976  			add, remove := TaintSetDiff(tt.t1, tt.t2)
   977  			if !reflect.DeepEqual(add, tt.expectedTaintsToAdd) {
   978  				t.Errorf("taintsToAdd: %v should equal %v, but get unexpected results", add, tt.expectedTaintsToAdd)
   979  			}
   980  			if !reflect.DeepEqual(remove, tt.expectedTaintsToRemove) {
   981  				t.Errorf("taintsToRemove: %v should equal %v, but get unexpected results", remove, tt.expectedTaintsToRemove)
   982  			}
   983  		})
   984  	}
   985  }
   986  

View as plain text