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 }