sigs.k8s.io/cluster-api-provider-azure@v1.17.0/util/webhook/validator_test.go (about)

     1  /*
     2  Copyright 2022 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 webhook
    18  
    19  import (
    20  	"testing"
    21  
    22  	. "github.com/onsi/gomega"
    23  	"k8s.io/apimachinery/pkg/util/validation/field"
    24  	"k8s.io/utils/ptr"
    25  )
    26  
    27  func TestValidateImmutableBoolPtr(t *testing.T) {
    28  	testPath := field.NewPath("spec", "foo")
    29  
    30  	tests := []struct {
    31  		name           string
    32  		input1         *bool
    33  		input2         *bool
    34  		expectedOutput *field.Error
    35  	}{
    36  		{
    37  			name:   "nil",
    38  			input1: nil,
    39  			input2: nil,
    40  		},
    41  		{
    42  			name:   "no change",
    43  			input1: ptr.To(true),
    44  			input2: ptr.To(true),
    45  		},
    46  		{
    47  			name:           "can't unset",
    48  			input1:         ptr.To(true),
    49  			input2:         nil,
    50  			expectedOutput: field.Invalid(testPath, nil, unsetMessage),
    51  		},
    52  		{
    53  			name:           "can't set from empty",
    54  			input1:         nil,
    55  			input2:         ptr.To(true),
    56  			expectedOutput: field.Invalid(testPath, nil, setMessage),
    57  		},
    58  		{
    59  			name:           "can't change",
    60  			input1:         ptr.To(true),
    61  			input2:         ptr.To(false),
    62  			expectedOutput: field.Invalid(testPath, nil, immutableMessage),
    63  		},
    64  	}
    65  	for _, tc := range tests {
    66  		t.Run(tc.name, func(t *testing.T) {
    67  			g := NewWithT(t)
    68  			err := ValidateImmutable(testPath, tc.input1, tc.input2)
    69  			if tc.expectedOutput != nil {
    70  				g.Expect(err).To(HaveOccurred())
    71  				g.Expect(err.Detail).To(Equal(tc.expectedOutput.Detail))
    72  				g.Expect(err.Type).To(Equal(tc.expectedOutput.Type))
    73  				g.Expect(err.Field).To(Equal(tc.expectedOutput.Field))
    74  			} else {
    75  				g.Expect(err).NotTo(HaveOccurred())
    76  			}
    77  		})
    78  	}
    79  }
    80  
    81  func TestValidateImmutableString(t *testing.T) {
    82  	testPath := field.NewPath("spec", "foo")
    83  
    84  	tests := []struct {
    85  		name           string
    86  		input1         string
    87  		input2         string
    88  		expectedOutput *field.Error
    89  	}{
    90  		{
    91  			name:   "empty string",
    92  			input1: "",
    93  			input2: "",
    94  		},
    95  		{
    96  			name:   "no change",
    97  			input1: "foo",
    98  			input2: "foo",
    99  		},
   100  		{
   101  			name:           "can't unset",
   102  			input1:         "foo",
   103  			input2:         "",
   104  			expectedOutput: field.Invalid(testPath, nil, unsetMessage),
   105  		},
   106  		{
   107  			name:           "can't set from empty",
   108  			input1:         "",
   109  			input2:         "foo",
   110  			expectedOutput: field.Invalid(testPath, nil, setMessage),
   111  		},
   112  		{
   113  			name:           "can't change",
   114  			input1:         "foo",
   115  			input2:         "bar",
   116  			expectedOutput: field.Invalid(testPath, nil, immutableMessage),
   117  		},
   118  	}
   119  	for _, tc := range tests {
   120  		t.Run(tc.name, func(t *testing.T) {
   121  			g := NewWithT(t)
   122  			err := ValidateImmutable(testPath, tc.input1, tc.input2)
   123  			if tc.expectedOutput != nil {
   124  				g.Expect(err).To(HaveOccurred())
   125  				g.Expect(err.Detail).To(Equal(tc.expectedOutput.Detail))
   126  				g.Expect(err.Type).To(Equal(tc.expectedOutput.Type))
   127  				g.Expect(err.Field).To(Equal(tc.expectedOutput.Field))
   128  			} else {
   129  				g.Expect(err).NotTo(HaveOccurred())
   130  			}
   131  		})
   132  	}
   133  }
   134  
   135  func TestValidateImmutableStringPtr(t *testing.T) {
   136  	testPath := field.NewPath("spec", "foo")
   137  
   138  	tests := []struct {
   139  		name           string
   140  		input1         *string
   141  		input2         *string
   142  		expectedOutput *field.Error
   143  	}{
   144  		{
   145  			name:   "nil",
   146  			input1: nil,
   147  			input2: nil,
   148  		},
   149  		{
   150  			name:   "no change",
   151  			input1: ptr.To("foo"),
   152  			input2: ptr.To("foo"),
   153  		},
   154  		{
   155  			name:           "can't unset",
   156  			input1:         ptr.To("foo"),
   157  			input2:         nil,
   158  			expectedOutput: field.Invalid(testPath, nil, unsetMessage),
   159  		},
   160  		{
   161  			name:           "can't set from empty",
   162  			input1:         nil,
   163  			input2:         ptr.To("foo"),
   164  			expectedOutput: field.Invalid(testPath, nil, setMessage),
   165  		},
   166  		{
   167  			name:           "can't change",
   168  			input1:         ptr.To("foo"),
   169  			input2:         ptr.To("bar"),
   170  			expectedOutput: field.Invalid(testPath, nil, immutableMessage),
   171  		},
   172  	}
   173  	for _, tc := range tests {
   174  		t.Run(tc.name, func(t *testing.T) {
   175  			g := NewWithT(t)
   176  			err := ValidateImmutable(testPath, tc.input1, tc.input2)
   177  			if tc.expectedOutput != nil {
   178  				g.Expect(err).To(HaveOccurred())
   179  				g.Expect(err.Detail).To(Equal(tc.expectedOutput.Detail))
   180  				g.Expect(err.Type).To(Equal(tc.expectedOutput.Type))
   181  				g.Expect(err.Field).To(Equal(tc.expectedOutput.Field))
   182  			} else {
   183  				g.Expect(err).NotTo(HaveOccurred())
   184  			}
   185  		})
   186  	}
   187  }
   188  
   189  func TestValidateImmutableInt32(t *testing.T) {
   190  	testPath := field.NewPath("spec", "foo")
   191  
   192  	tests := []struct {
   193  		name           string
   194  		input1         int32
   195  		input2         int32
   196  		expectedOutput *field.Error
   197  	}{
   198  		{
   199  			name:   "unset",
   200  			input1: 0,
   201  			input2: 0,
   202  		},
   203  		{
   204  			name:   "no change",
   205  			input1: 5,
   206  			input2: 5,
   207  		},
   208  		{
   209  			name:           "can't unset",
   210  			input1:         5,
   211  			input2:         0,
   212  			expectedOutput: field.Invalid(testPath, nil, unsetMessage),
   213  		},
   214  		{
   215  			name:           "can't set from empty",
   216  			input1:         0,
   217  			input2:         5,
   218  			expectedOutput: field.Invalid(testPath, nil, setMessage),
   219  		},
   220  		{
   221  			name:           "can't change",
   222  			input1:         5,
   223  			input2:         6,
   224  			expectedOutput: field.Invalid(testPath, nil, immutableMessage),
   225  		},
   226  	}
   227  	for _, tc := range tests {
   228  		t.Run(tc.name, func(t *testing.T) {
   229  			g := NewWithT(t)
   230  			err := ValidateImmutable(testPath, tc.input1, tc.input2)
   231  			if tc.expectedOutput != nil {
   232  				g.Expect(err).To(HaveOccurred())
   233  				g.Expect(err.Detail).To(Equal(tc.expectedOutput.Detail))
   234  				g.Expect(err.Type).To(Equal(tc.expectedOutput.Type))
   235  				g.Expect(err.Field).To(Equal(tc.expectedOutput.Field))
   236  			} else {
   237  				g.Expect(err).NotTo(HaveOccurred())
   238  			}
   239  		})
   240  	}
   241  }
   242  
   243  func TestEnsureStringSlicesAreEquivalent(t *testing.T) {
   244  	tests := []struct {
   245  		name           string
   246  		input1         []string
   247  		input2         []string
   248  		expectedOutput bool
   249  	}{
   250  		{
   251  			name:           "nil",
   252  			input1:         nil,
   253  			input2:         nil,
   254  			expectedOutput: true,
   255  		},
   256  		{
   257  			name:           "no change",
   258  			input1:         []string{"foo", "bar"},
   259  			input2:         []string{"foo", "bar"},
   260  			expectedOutput: true,
   261  		},
   262  		{
   263  			name:           "different",
   264  			input1:         []string{"foo", "bar"},
   265  			input2:         []string{"foo", "foo"},
   266  			expectedOutput: false,
   267  		},
   268  		{
   269  			name:           "different order, but equal",
   270  			input1:         []string{"1", "2"},
   271  			input2:         []string{"2", "1"},
   272  			expectedOutput: true,
   273  		},
   274  		{
   275  			name:           "different lengths",
   276  			input1:         []string{"foo"},
   277  			input2:         []string{"foo", "foo"},
   278  			expectedOutput: false,
   279  		},
   280  		{
   281  			name:           "different",
   282  			input1:         []string{"1", "2", "3", "4", "5", "6", "7", "8", "9"},
   283  			input2:         []string{"1", "2", "3", "4", "5", "7", "8", "9"},
   284  			expectedOutput: false,
   285  		},
   286  		{
   287  			name:           "another different variant",
   288  			input1:         []string{"a", "a", "b"},
   289  			input2:         []string{"a", "b", "b"},
   290  			expectedOutput: false,
   291  		},
   292  	}
   293  	for _, tc := range tests {
   294  		t.Run(tc.name, func(t *testing.T) {
   295  			g := NewWithT(t)
   296  			ret := EnsureStringSlicesAreEquivalent(tc.input1, tc.input2)
   297  			g.Expect(ret).To(Equal(tc.expectedOutput))
   298  		})
   299  	}
   300  }
   301  
   302  func TestValidateZeroTransitionPtr(t *testing.T) {
   303  	testPath := field.NewPath("spec", "foo")
   304  
   305  	tests := []struct {
   306  		name           string
   307  		input1         *bool
   308  		input2         *bool
   309  		expectedOutput *field.Error
   310  	}{
   311  		{
   312  			name:   "nil",
   313  			input1: nil,
   314  			input2: nil,
   315  		},
   316  		{
   317  			name:   "no change",
   318  			input1: ptr.To(true),
   319  			input2: ptr.To(true),
   320  		},
   321  		{
   322  			name:   "can unset",
   323  			input1: ptr.To(true),
   324  			input2: nil,
   325  		},
   326  		{
   327  			name:           "can't set from empty",
   328  			input1:         nil,
   329  			input2:         ptr.To(true),
   330  			expectedOutput: field.Invalid(testPath, nil, setMessage),
   331  		},
   332  		{
   333  			name:           "can't change",
   334  			input1:         ptr.To(true),
   335  			input2:         ptr.To(false),
   336  			expectedOutput: field.Invalid(testPath, nil, immutableMessage),
   337  		},
   338  	}
   339  	for _, tc := range tests {
   340  		t.Run(tc.name, func(t *testing.T) {
   341  			g := NewWithT(t)
   342  			err := ValidateZeroTransition(testPath, tc.input1, tc.input2)
   343  			if tc.expectedOutput != nil {
   344  				g.Expect(err).To(HaveOccurred())
   345  				g.Expect(err.Detail).To(Equal(tc.expectedOutput.Detail))
   346  				g.Expect(err.Type).To(Equal(tc.expectedOutput.Type))
   347  				g.Expect(err.Field).To(Equal(tc.expectedOutput.Field))
   348  			} else {
   349  				g.Expect(err).NotTo(HaveOccurred())
   350  			}
   351  		})
   352  	}
   353  }
   354  
   355  func TestValidateZeroTransitionString(t *testing.T) {
   356  	testPath := field.NewPath("spec", "foo")
   357  
   358  	tests := []struct {
   359  		name           string
   360  		input1         string
   361  		input2         string
   362  		expectedOutput *field.Error
   363  	}{
   364  		{
   365  			name:   "empty string",
   366  			input1: "",
   367  			input2: "",
   368  		},
   369  		{
   370  			name:   "no change",
   371  			input1: "foo",
   372  			input2: "foo",
   373  		},
   374  		{
   375  			name:   "can unset",
   376  			input1: "foo",
   377  			input2: "",
   378  		},
   379  		{
   380  			name:           "can't set from empty",
   381  			input1:         "",
   382  			input2:         "foo",
   383  			expectedOutput: field.Invalid(testPath, nil, setMessage),
   384  		},
   385  		{
   386  			name:           "can't change",
   387  			input1:         "foo",
   388  			input2:         "bar",
   389  			expectedOutput: field.Invalid(testPath, nil, immutableMessage),
   390  		},
   391  	}
   392  	for _, tc := range tests {
   393  		t.Run(tc.name, func(t *testing.T) {
   394  			g := NewWithT(t)
   395  			err := ValidateZeroTransition(testPath, tc.input1, tc.input2)
   396  			if tc.expectedOutput != nil {
   397  				g.Expect(err).To(HaveOccurred())
   398  				g.Expect(err.Detail).To(Equal(tc.expectedOutput.Detail))
   399  				g.Expect(err.Type).To(Equal(tc.expectedOutput.Type))
   400  				g.Expect(err.Field).To(Equal(tc.expectedOutput.Field))
   401  			} else {
   402  				g.Expect(err).NotTo(HaveOccurred())
   403  			}
   404  		})
   405  	}
   406  }
   407  
   408  func TestValidateZeroTransitionStringPtr(t *testing.T) {
   409  	testPath := field.NewPath("spec", "foo")
   410  
   411  	tests := []struct {
   412  		name           string
   413  		input1         *string
   414  		input2         *string
   415  		expectedOutput *field.Error
   416  	}{
   417  		{
   418  			name:   "nil",
   419  			input1: nil,
   420  			input2: nil,
   421  		},
   422  		{
   423  			name:   "no change",
   424  			input1: ptr.To("foo"),
   425  			input2: ptr.To("foo"),
   426  		},
   427  		{
   428  			name:   "can unset",
   429  			input1: ptr.To("foo"),
   430  			input2: nil,
   431  		},
   432  		{
   433  			name:           "can't set from empty",
   434  			input1:         nil,
   435  			input2:         ptr.To("foo"),
   436  			expectedOutput: field.Invalid(testPath, nil, setMessage),
   437  		},
   438  		{
   439  			name:           "can't change",
   440  			input1:         ptr.To("foo"),
   441  			input2:         ptr.To("bar"),
   442  			expectedOutput: field.Invalid(testPath, nil, immutableMessage),
   443  		},
   444  	}
   445  	for _, tc := range tests {
   446  		t.Run(tc.name, func(t *testing.T) {
   447  			g := NewWithT(t)
   448  			err := ValidateZeroTransition(testPath, tc.input1, tc.input2)
   449  			if tc.expectedOutput != nil {
   450  				g.Expect(err).To(HaveOccurred())
   451  				g.Expect(err.Detail).To(Equal(tc.expectedOutput.Detail))
   452  				g.Expect(err.Type).To(Equal(tc.expectedOutput.Type))
   453  				g.Expect(err.Field).To(Equal(tc.expectedOutput.Field))
   454  			} else {
   455  				g.Expect(err).NotTo(HaveOccurred())
   456  			}
   457  		})
   458  	}
   459  }
   460  
   461  func TestValidateZeroTransitionInt32(t *testing.T) {
   462  	testPath := field.NewPath("spec", "foo")
   463  
   464  	tests := []struct {
   465  		name           string
   466  		input1         int32
   467  		input2         int32
   468  		expectedOutput *field.Error
   469  	}{
   470  		{
   471  			name:   "unset",
   472  			input1: 0,
   473  			input2: 0,
   474  		},
   475  		{
   476  			name:   "no change",
   477  			input1: 5,
   478  			input2: 5,
   479  		},
   480  		{
   481  			name:   "can unset",
   482  			input1: 5,
   483  			input2: 0,
   484  		},
   485  		{
   486  			name:           "can't set from empty",
   487  			input1:         0,
   488  			input2:         5,
   489  			expectedOutput: field.Invalid(testPath, nil, setMessage),
   490  		},
   491  		{
   492  			name:           "can't change",
   493  			input1:         5,
   494  			input2:         6,
   495  			expectedOutput: field.Invalid(testPath, nil, immutableMessage),
   496  		},
   497  	}
   498  	for _, tc := range tests {
   499  		t.Run(tc.name, func(t *testing.T) {
   500  			g := NewWithT(t)
   501  			err := ValidateZeroTransition(testPath, tc.input1, tc.input2)
   502  			if tc.expectedOutput != nil {
   503  				g.Expect(err).To(HaveOccurred())
   504  				g.Expect(err.Detail).To(Equal(tc.expectedOutput.Detail))
   505  				g.Expect(err.Type).To(Equal(tc.expectedOutput.Type))
   506  				g.Expect(err.Field).To(Equal(tc.expectedOutput.Field))
   507  			} else {
   508  				g.Expect(err).NotTo(HaveOccurred())
   509  			}
   510  		})
   511  	}
   512  }