sigs.k8s.io/cluster-api@v1.7.1/cmd/clusterctl/client/config/providers_client_test.go (about) 1 /* 2 Copyright 2019 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 config 18 19 import ( 20 "fmt" 21 "os" 22 "sort" 23 "testing" 24 25 . "github.com/onsi/gomega" 26 "github.com/onsi/gomega/format" 27 28 clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" 29 "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test" 30 ) 31 32 func Test_providers_List(t *testing.T) { 33 reader := test.NewFakeReader() 34 35 p := &providersClient{ 36 reader: reader, 37 } 38 39 defaults := p.defaults() 40 sort.Slice(defaults, func(i, j int) bool { 41 return defaults[i].Less(defaults[j]) 42 }) 43 44 defaultsAndZZZ := append(defaults, NewProvider("zzz", "https://zzz/infrastructure-components.yaml", "InfrastructureProvider")) 45 // AddonProviders are at the end of the list so we want to make sure this InfrastructureProvider is before the AddonProviders. 46 sort.Slice(defaultsAndZZZ, func(i, j int) bool { 47 return defaultsAndZZZ[i].Less(defaultsAndZZZ[j]) 48 }) 49 50 defaultsWithOverride := append([]Provider{}, defaults...) 51 defaultsWithOverride[0] = NewProvider(defaults[0].Name(), "https://zzz/infrastructure-components.yaml", defaults[0].Type()) 52 53 type fields struct { 54 configGetter Reader 55 } 56 tests := []struct { 57 name string 58 fields fields 59 envVars map[string]string 60 want []Provider 61 wantErr bool 62 }{ 63 { 64 name: "Returns default provider configurations", 65 fields: fields{ 66 configGetter: test.NewFakeReader(), 67 }, 68 want: defaults, 69 wantErr: false, 70 }, 71 { 72 name: "Returns user defined provider configurations", 73 fields: fields{ 74 configGetter: test.NewFakeReader(). 75 WithVar( 76 ProvidersConfigKey, 77 "- name: \"zzz\"\n"+ 78 " url: \"https://zzz/infrastructure-components.yaml\"\n"+ 79 " type: \"InfrastructureProvider\"\n", 80 ), 81 }, 82 want: defaultsAndZZZ, 83 wantErr: false, 84 }, 85 { 86 name: "Returns user defined provider configurations with evaluated env vars", 87 fields: fields{ 88 configGetter: test.NewFakeReader(). 89 WithVar( 90 ProvidersConfigKey, 91 "- name: \"zzz\"\n"+ 92 " url: \"${TEST_REPO_PATH}/infrastructure-components.yaml\"\n"+ 93 " type: \"InfrastructureProvider\"\n", 94 ), 95 }, 96 envVars: map[string]string{ 97 "TEST_REPO_PATH": "https://zzz", 98 }, 99 want: defaultsAndZZZ, 100 wantErr: false, 101 }, 102 { 103 name: "User defined provider configurations override defaults", 104 fields: fields{ 105 configGetter: test.NewFakeReader(). 106 WithVar( 107 ProvidersConfigKey, 108 fmt.Sprintf("- name: %q\n", defaults[0].Name())+ 109 " url: \"https://zzz/infrastructure-components.yaml\"\n"+ 110 fmt.Sprintf(" type: %q\n", defaults[0].Type()), 111 ), 112 }, 113 want: defaultsWithOverride, 114 wantErr: false, 115 }, 116 { 117 name: "Fails for invalid user defined provider configurations", 118 fields: fields{ 119 configGetter: test.NewFakeReader(). 120 WithVar( 121 ProvidersConfigKey, 122 "- foo\n", 123 ), 124 }, 125 want: nil, 126 wantErr: true, 127 }, 128 { 129 name: "Fails for invalid user defined provider configurations", 130 fields: fields{ 131 configGetter: test.NewFakeReader(). 132 WithVar( 133 ProvidersConfigKey, 134 "- name: \"\"\n"+ // name must not be empty 135 " url: \"\"\n"+ 136 " type: \"\"\n", 137 ), 138 }, 139 want: nil, 140 wantErr: true, 141 }, 142 } 143 144 format.MaxLength = 15000 // This way it doesn't truncate the output on test failure 145 146 for _, tt := range tests { 147 t.Run(tt.name, func(t *testing.T) { 148 g := NewWithT(t) 149 150 for k, v := range tt.envVars { 151 g.Expect(os.Setenv(k, v)).To(Succeed()) 152 } 153 defer func() { 154 for k := range tt.envVars { 155 g.Expect(os.Unsetenv(k)).To(Succeed()) 156 } 157 }() 158 p := &providersClient{ 159 reader: tt.fields.configGetter, 160 } 161 got, err := p.List() 162 if tt.wantErr { 163 g.Expect(err).To(HaveOccurred()) 164 return 165 } 166 167 g.Expect(err).ToNot(HaveOccurred()) 168 g.Expect(got).To(Equal(tt.want)) 169 }) 170 } 171 } 172 173 func Test_validateProvider(t *testing.T) { 174 type args struct { 175 r Provider 176 } 177 tests := []struct { 178 name string 179 args args 180 wantErr bool 181 }{ 182 { 183 name: "Pass", 184 args: args{ 185 r: NewProvider("foo", "https://something.com", clusterctlv1.InfrastructureProviderType), 186 }, 187 wantErr: false, 188 }, 189 { 190 name: "Pass (core provider)", 191 args: args{ 192 r: NewProvider(ClusterAPIProviderName, "https://something.com", clusterctlv1.CoreProviderType), 193 }, 194 wantErr: false, 195 }, 196 { 197 name: "Fails if cluster-api name used with wrong type", 198 args: args{ 199 r: NewProvider(ClusterAPIProviderName, "https://something.com", clusterctlv1.BootstrapProviderType), 200 }, 201 wantErr: true, 202 }, 203 { 204 name: "Fails if CoreProviderType used with wrong name", 205 args: args{ 206 r: NewProvider("sss", "https://something.com", clusterctlv1.CoreProviderType), 207 }, 208 wantErr: true, 209 }, 210 { 211 name: "Fails if name is empty", 212 args: args{ 213 r: NewProvider("", "", ""), 214 }, 215 wantErr: true, 216 }, 217 { 218 name: "Fails if name is not valid", 219 args: args{ 220 r: NewProvider("FOo", "https://something.com", ""), 221 }, 222 wantErr: true, 223 }, 224 { 225 name: "Fails if url is empty", 226 args: args{ 227 r: NewProvider("foo", "", ""), 228 }, 229 wantErr: true, 230 }, 231 { 232 name: "Fails if url is not valid", 233 args: args{ 234 r: NewProvider("foo", "%gh&%ij", "bar"), 235 }, 236 wantErr: true, 237 }, 238 { 239 name: "Fails if type is empty", 240 args: args{ 241 r: NewProvider("foo", "https://something.com", ""), 242 }, 243 wantErr: true, 244 }, 245 { 246 name: "Fails if type is not valid", 247 args: args{ 248 r: NewProvider("foo", "https://something.com", "bar"), 249 }, 250 wantErr: true, 251 }, 252 } 253 for _, tt := range tests { 254 t.Run(tt.name, func(t *testing.T) { 255 g := NewWithT(t) 256 257 err := validateProvider(tt.args.r) 258 if tt.wantErr { 259 g.Expect(err).To(HaveOccurred()) 260 } else { 261 g.Expect(err).ToNot(HaveOccurred()) 262 } 263 }) 264 } 265 } 266 267 // check if Defaults returns valid provider repository configurations 268 // this is a safeguard for catching changes leading to formally invalid default configurations. 269 func Test_providers_Defaults(t *testing.T) { 270 g := NewWithT(t) 271 272 reader := test.NewFakeReader() 273 274 p := &providersClient{ 275 reader: reader, 276 } 277 278 defaults := p.defaults() 279 280 for _, d := range defaults { 281 err := validateProvider(d) 282 g.Expect(err).ToNot(HaveOccurred()) 283 } 284 } 285 286 func Test_providers_Get(t *testing.T) { 287 reader := test.NewFakeReader() 288 289 p := &providersClient{ 290 reader: reader, 291 } 292 293 defaults := p.defaults() 294 295 type args struct { 296 name string 297 providerType clusterctlv1.ProviderType 298 } 299 tests := []struct { 300 name string 301 args args 302 want Provider 303 wantErr bool 304 }{ 305 { 306 name: "pass", 307 args: args{ 308 name: p.defaults()[0].Name(), 309 providerType: p.defaults()[0].Type(), 310 }, 311 want: defaults[0], 312 wantErr: false, 313 }, 314 { 315 name: "kubeadm bootstrap", 316 args: args{ 317 name: KubeadmBootstrapProviderName, 318 providerType: clusterctlv1.BootstrapProviderType, 319 }, 320 want: NewProvider(KubeadmBootstrapProviderName, "https://github.com/kubernetes-sigs/cluster-api/releases/latest/bootstrap-components.yaml", clusterctlv1.BootstrapProviderType), 321 wantErr: false, 322 }, 323 { 324 name: "kubeadm control-plane", 325 args: args{ 326 name: KubeadmControlPlaneProviderName, 327 providerType: clusterctlv1.ControlPlaneProviderType, 328 }, 329 want: NewProvider(KubeadmControlPlaneProviderName, "https://github.com/kubernetes-sigs/cluster-api/releases/latest/control-plane-components.yaml", clusterctlv1.ControlPlaneProviderType), 330 wantErr: false, 331 }, 332 { 333 name: "fails if the provider does not exists (wrong name)", 334 args: args{ 335 name: "foo", 336 providerType: clusterctlv1.CoreProviderType, 337 }, 338 want: nil, 339 wantErr: true, 340 }, 341 { 342 name: "fails if the provider does not exists (wrong type)", 343 args: args{ 344 name: ClusterAPIProviderName, 345 providerType: clusterctlv1.InfrastructureProviderType, 346 }, 347 want: nil, 348 wantErr: true, 349 }, 350 } 351 for _, tt := range tests { 352 t.Run(tt.name, func(t *testing.T) { 353 g := NewWithT(t) 354 355 p := &providersClient{ 356 reader: reader, 357 } 358 got, err := p.Get(tt.args.name, tt.args.providerType) 359 if tt.wantErr { 360 g.Expect(err).To(HaveOccurred()) 361 return 362 } 363 364 g.Expect(err).ToNot(HaveOccurred()) 365 g.Expect(got).To(Equal(tt.want)) 366 }) 367 } 368 }