sigs.k8s.io/cluster-api@v1.7.1/exp/runtime/topologymutation/variables_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 topologymutation
    18  
    19  import (
    20  	"testing"
    21  
    22  	. "github.com/onsi/gomega"
    23  	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    24  	"k8s.io/utils/ptr"
    25  
    26  	runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1"
    27  )
    28  
    29  func Test_GetRawTemplateVariable(t *testing.T) {
    30  	g := NewWithT(t)
    31  
    32  	varA := apiextensionsv1.JSON{Raw: toJSON("a")}
    33  	tests := []struct {
    34  		name                  string
    35  		variables             map[string]apiextensionsv1.JSON
    36  		variableName          string
    37  		expectedValue         *apiextensionsv1.JSON
    38  		expectedNotFoundError bool
    39  		expectedErr           bool
    40  	}{
    41  		{
    42  			name:                  "Fails for invalid variable reference",
    43  			variables:             nil,
    44  			variableName:          "invalid[",
    45  			expectedValue:         nil,
    46  			expectedNotFoundError: false,
    47  			expectedErr:           true,
    48  		},
    49  		{
    50  			name:                  "variable not found",
    51  			variables:             nil,
    52  			variableName:          "notExists",
    53  			expectedValue:         nil,
    54  			expectedNotFoundError: true,
    55  			expectedErr:           true,
    56  		},
    57  		{
    58  			name: "return a variable",
    59  			variables: map[string]apiextensionsv1.JSON{
    60  				"a": varA,
    61  			},
    62  			variableName:          "a",
    63  			expectedValue:         &varA,
    64  			expectedNotFoundError: false,
    65  			expectedErr:           false,
    66  		},
    67  	}
    68  	for _, tt := range tests {
    69  		t.Run(tt.name, func(*testing.T) {
    70  			value, err := GetVariable(tt.variables, tt.variableName)
    71  
    72  			g.Expect(value).To(BeComparableTo(tt.expectedValue))
    73  			if tt.expectedErr {
    74  				g.Expect(err).To(HaveOccurred())
    75  			} else {
    76  				g.Expect(err).ToNot(HaveOccurred())
    77  			}
    78  
    79  			if tt.expectedNotFoundError {
    80  				g.Expect(IsNotFoundError(err)).To(BeTrue())
    81  			}
    82  		})
    83  	}
    84  }
    85  
    86  func Test_GetStringTemplateVariable(t *testing.T) {
    87  	g := NewWithT(t)
    88  
    89  	varA := apiextensionsv1.JSON{Raw: toJSON("a")}
    90  	tests := []struct {
    91  		name                  string
    92  		variables             map[string]apiextensionsv1.JSON
    93  		variableName          string
    94  		expectedValue         string
    95  		expectedNotFoundError bool
    96  		expectedErr           bool
    97  	}{
    98  		{
    99  			name:                  "Fails for invalid variable reference",
   100  			variables:             nil,
   101  			variableName:          "invalid[",
   102  			expectedValue:         "",
   103  			expectedNotFoundError: false,
   104  			expectedErr:           true,
   105  		},
   106  		{
   107  			name:                  "variable not found",
   108  			variables:             nil,
   109  			variableName:          "notEsists",
   110  			expectedValue:         "",
   111  			expectedNotFoundError: true,
   112  			expectedErr:           true,
   113  		},
   114  		{
   115  			name: "valid variable",
   116  			variables: map[string]apiextensionsv1.JSON{
   117  				"a": varA,
   118  			},
   119  			variableName:          "a",
   120  			expectedValue:         "a",
   121  			expectedNotFoundError: false,
   122  			expectedErr:           false,
   123  		},
   124  	}
   125  	for _, tt := range tests {
   126  		t.Run(tt.name, func(*testing.T) {
   127  			value, err := GetStringVariable(tt.variables, tt.variableName)
   128  
   129  			g.Expect(value).To(Equal(tt.expectedValue))
   130  			if tt.expectedErr {
   131  				g.Expect(err).To(HaveOccurred())
   132  			} else {
   133  				g.Expect(err).ToNot(HaveOccurred())
   134  			}
   135  
   136  			if tt.expectedNotFoundError {
   137  				g.Expect(IsNotFoundError(err)).To(BeTrue())
   138  			}
   139  		})
   140  	}
   141  }
   142  
   143  func Test_GetBoolVariable(t *testing.T) {
   144  	g := NewWithT(t)
   145  
   146  	varA := apiextensionsv1.JSON{Raw: []byte(`true`)}
   147  	tests := []struct {
   148  		name                  string
   149  		variables             map[string]apiextensionsv1.JSON
   150  		variableName          string
   151  		expectedValue         bool
   152  		expectedNotFoundError bool
   153  		expectedErr           bool
   154  	}{
   155  		{
   156  			name:                  "Fails for invalid variable reference",
   157  			variables:             nil,
   158  			variableName:          "invalid[",
   159  			expectedValue:         false,
   160  			expectedNotFoundError: false,
   161  			expectedErr:           true,
   162  		},
   163  		{
   164  			name:                  "variable not found",
   165  			variables:             nil,
   166  			variableName:          "notEsists",
   167  			expectedValue:         false,
   168  			expectedNotFoundError: true,
   169  			expectedErr:           true,
   170  		},
   171  		{
   172  			name: "valid variable",
   173  			variables: map[string]apiextensionsv1.JSON{
   174  				"a": varA,
   175  			},
   176  			variableName:          "a",
   177  			expectedValue:         true,
   178  			expectedNotFoundError: false,
   179  			expectedErr:           false,
   180  		},
   181  	}
   182  	for _, tt := range tests {
   183  		t.Run(tt.name, func(*testing.T) {
   184  			value, err := GetBoolVariable(tt.variables, tt.variableName)
   185  			if tt.expectedErr {
   186  				g.Expect(err).To(HaveOccurred())
   187  			} else {
   188  				g.Expect(err).ToNot(HaveOccurred())
   189  			}
   190  			if tt.expectedNotFoundError {
   191  				g.Expect(IsNotFoundError(err)).To(BeTrue())
   192  			}
   193  			g.Expect(value).To(Equal(tt.expectedValue))
   194  		})
   195  	}
   196  }
   197  
   198  func Test_GetVariableObjectWithNestedType(t *testing.T) {
   199  	type AddressesFromPool struct {
   200  		APIGroup string `json:"apiGroup"`
   201  		Kind     string `json:"kind"`
   202  		Name     string `json:"name"`
   203  	}
   204  	type Network struct {
   205  		AddressesFromPools *[]AddressesFromPool `json:"addressesFromPools,omitempty"`
   206  		Ipv6Primary        *bool                `json:"ipv6Primary,omitempty"`
   207  	}
   208  
   209  	g := NewWithT(t)
   210  
   211  	tests := []struct {
   212  		name                   string
   213  		variables              map[string]apiextensionsv1.JSON
   214  		variableName           string
   215  		expectedNotFoundError  bool
   216  		expectedErr            bool
   217  		object                 *Network
   218  		expectedVariableObject interface{}
   219  	}{
   220  		{
   221  			name:                   "Fails for invalid variable reference",
   222  			variables:              nil,
   223  			variableName:           "invalid[",
   224  			expectedNotFoundError:  false,
   225  			object:                 &Network{},
   226  			expectedVariableObject: Network{},
   227  			expectedErr:            true,
   228  		},
   229  		{
   230  			name:                   "variable not found",
   231  			variables:              nil,
   232  			variableName:           "notEsists",
   233  			expectedNotFoundError:  true,
   234  			object:                 &Network{},
   235  			expectedVariableObject: Network{},
   236  			expectedErr:            true,
   237  		},
   238  		{
   239  			name: "unmarshal error",
   240  			variables: map[string]apiextensionsv1.JSON{
   241  				"node":    {Raw: []byte(`{"name": "aadfasdfasd`)},
   242  				"network": {Raw: []byte(`{"ipv6Primary": true, "addressesFromPools":[{"name":"name"}]asdfasdf`)},
   243  			},
   244  			variableName:           "network",
   245  			expectedNotFoundError:  false,
   246  			object:                 &Network{},
   247  			expectedVariableObject: Network{},
   248  			expectedErr:            true,
   249  		},
   250  		{
   251  			name: "valid variable",
   252  			variables: map[string]apiextensionsv1.JSON{
   253  				"node":    {Raw: []byte(`{"name": "a"}`)},
   254  				"network": {Raw: []byte(`{"ipv6Primary": true, "addressesFromPools":[{"name":"name"}]}`)},
   255  			},
   256  			variableName:          "network",
   257  			expectedNotFoundError: false,
   258  			expectedErr:           false,
   259  			object:                &Network{},
   260  			expectedVariableObject: Network{
   261  				Ipv6Primary: ptr.To(true),
   262  				AddressesFromPools: &[]AddressesFromPool{
   263  					{
   264  						Name: "name",
   265  					},
   266  				},
   267  			},
   268  		},
   269  	}
   270  	for _, tt := range tests {
   271  		t.Run(tt.name, func(*testing.T) {
   272  			err := GetObjectVariableInto(tt.variables, tt.variableName, tt.object)
   273  			if tt.expectedErr {
   274  				g.Expect(err).To(HaveOccurred())
   275  			} else {
   276  				g.Expect(err).ToNot(HaveOccurred())
   277  			}
   278  			if tt.expectedNotFoundError {
   279  				g.Expect(IsNotFoundError(err)).To(BeTrue())
   280  			}
   281  			g.Expect(*tt.object).To(Equal(tt.expectedVariableObject))
   282  		})
   283  	}
   284  }
   285  
   286  func TestMergeVariables(t *testing.T) {
   287  	t.Run("Merge variables", func(t *testing.T) {
   288  		g := NewWithT(t)
   289  
   290  		m, err := MergeVariableMaps(
   291  			map[string]apiextensionsv1.JSON{
   292  				runtimehooksv1.BuiltinsName: {Raw: []byte(`{"cluster":{"name":"cluster-name","namespace":"default","topology":{"class":"clusterClass1","version":"v1.21.1"}}}`)},
   293  				"a":                         {Raw: []byte("a-different")},
   294  				"c":                         {Raw: []byte("c")},
   295  			},
   296  			map[string]apiextensionsv1.JSON{
   297  				// Verify that builtin variables are merged correctly and
   298  				// the latter variables take precedent ("cluster-name-overwrite").
   299  				runtimehooksv1.BuiltinsName: {Raw: []byte(`{"controlPlane":{"replicas":3},"cluster":{"name":"cluster-name-overwrite"}}`)},
   300  				"a":                         {Raw: []byte("a")},
   301  				"b":                         {Raw: []byte("b")},
   302  			},
   303  		)
   304  		g.Expect(err).ToNot(HaveOccurred())
   305  
   306  		g.Expect(m).To(HaveKeyWithValue(runtimehooksv1.BuiltinsName, apiextensionsv1.JSON{Raw: []byte(`{"cluster":{"name":"cluster-name-overwrite","namespace":"default","topology":{"version":"v1.21.1","class":"clusterClass1"}},"controlPlane":{"replicas":3}}`)}))
   307  		g.Expect(m).To(HaveKeyWithValue("a", apiextensionsv1.JSON{Raw: []byte("a")}))
   308  		g.Expect(m).To(HaveKeyWithValue("b", apiextensionsv1.JSON{Raw: []byte("b")}))
   309  		g.Expect(m).To(HaveKeyWithValue("c", apiextensionsv1.JSON{Raw: []byte("c")}))
   310  	})
   311  }