sigs.k8s.io/cluster-api@v1.7.1/cmd/clusterctl/client/cluster/upgrader_test.go (about) 1 /* 2 Copyright 2020 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 cluster 18 19 import ( 20 "context" 21 "testing" 22 23 "github.com/google/go-cmp/cmp" 24 . "github.com/onsi/gomega" 25 26 clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" 27 "sigs.k8s.io/cluster-api/cmd/clusterctl/client/config" 28 "sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository" 29 "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test" 30 ) 31 32 func Test_providerUpgrader_Plan(t *testing.T) { 33 type fields struct { 34 reader config.Reader 35 repository map[string]repository.Repository 36 proxy Proxy 37 } 38 tests := []struct { 39 name string 40 fields fields 41 want []UpgradePlan 42 wantErr bool 43 }{ 44 { 45 name: "Upgrade within the current contract", 46 fields: fields{ 47 // config for two providers 48 reader: test.NewFakeReader(). 49 WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). 50 WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), 51 repository: map[string]repository.Repository{ 52 "cluster-api": repository.NewMemoryRepository(). 53 WithVersions("v1.0.0", "v1.0.1"). 54 WithMetadata("v1.0.1", &clusterctlv1.Metadata{ 55 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 56 {Major: 1, Minor: 0, Contract: test.CurrentCAPIContract}, 57 }, 58 }), 59 "infrastructure-infra": repository.NewMemoryRepository(). 60 WithVersions("v2.0.0", "v2.0.1"). 61 WithMetadata("v2.0.1", &clusterctlv1.Metadata{ 62 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 63 {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, 64 }, 65 }), 66 }, 67 // two providers existing in the cluster 68 proxy: test.NewFakeProxy(). 69 WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"). 70 WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 71 }, 72 want: []UpgradePlan{ 73 { // one upgrade plan with the latest releases the current contract 74 Contract: test.CurrentCAPIContract, 75 Providers: []UpgradeItem{ 76 { 77 Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"), 78 NextVersion: "v1.0.1", 79 }, 80 { 81 Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 82 NextVersion: "v2.0.1", 83 }, 84 }, 85 }, 86 }, 87 wantErr: false, 88 }, 89 { 90 name: "pre-releases should be ignored", 91 fields: fields{ 92 // config for two providers 93 reader: test.NewFakeReader(). 94 WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). 95 WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), 96 repository: map[string]repository.Repository{ 97 "cluster-api": repository.NewMemoryRepository(). 98 WithVersions("v1.0.0", "v1.0.1"). 99 WithMetadata("v1.0.1", &clusterctlv1.Metadata{ 100 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 101 {Major: 1, Minor: 0, Contract: test.CurrentCAPIContract}, 102 }, 103 }), 104 "infrastructure-infra": repository.NewMemoryRepository(). 105 WithVersions("v2.0.0", "v2.0.1", "v3.0.0-alpha.0"). 106 WithMetadata("v2.0.1", &clusterctlv1.Metadata{ 107 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 108 {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, 109 }, 110 }). 111 WithMetadata("v3.0.0-alpha.0", &clusterctlv1.Metadata{ 112 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 113 {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, 114 {Major: 3, Minor: 0, Contract: test.CurrentCAPIContract}, 115 }, 116 }), 117 }, 118 // two providers existing in the cluster 119 proxy: test.NewFakeProxy(). 120 WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"). 121 WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 122 }, 123 want: []UpgradePlan{ 124 { // one upgrade plan with the latest releases the current contract 125 Contract: test.CurrentCAPIContract, 126 Providers: []UpgradeItem{ 127 { 128 Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"), 129 NextVersion: "v1.0.1", 130 }, 131 { 132 Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 133 NextVersion: "v2.0.1", 134 }, 135 }, 136 }, 137 }, 138 wantErr: false, 139 }, 140 { 141 name: "Upgrade for previous contract (not supported), current contract", // upgrade plan should report unsupported options 142 fields: fields{ 143 // config for two providers 144 reader: test.NewFakeReader(). 145 WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). 146 WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), 147 repository: map[string]repository.Repository{ 148 "cluster-api": repository.NewMemoryRepository(). 149 WithVersions("v1.0.0", "v1.0.1", "v2.0.0"). 150 WithMetadata("v2.0.0", &clusterctlv1.Metadata{ 151 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 152 {Major: 1, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, 153 {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, 154 }, 155 }), 156 "infrastructure-infra": repository.NewMemoryRepository(). 157 WithVersions("v2.0.0", "v2.0.1", "v3.0.0"). 158 WithMetadata("v3.0.0", &clusterctlv1.Metadata{ 159 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 160 {Major: 2, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, 161 {Major: 3, Minor: 0, Contract: test.CurrentCAPIContract}, 162 }, 163 }), 164 }, 165 // two providers existing in the cluster 166 proxy: test.NewFakeProxy(). 167 WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"). 168 WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 169 }, 170 want: []UpgradePlan{ 171 { // one upgrade plan with the latest releases in the previous contract (not supported, but upgrade plan should report these options) 172 Contract: test.PreviousCAPIContractNotSupported, 173 Providers: []UpgradeItem{ 174 { 175 Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"), 176 NextVersion: "v1.0.1", 177 }, 178 { 179 Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 180 NextVersion: "v2.0.1", 181 }, 182 }, 183 }, 184 { // one upgrade plan with the latest releases in the current contract 185 Contract: test.CurrentCAPIContract, 186 Providers: []UpgradeItem{ 187 { 188 Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"), 189 NextVersion: "v2.0.0", 190 }, 191 { 192 Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 193 NextVersion: "v3.0.0", 194 }, 195 }, 196 }, 197 }, 198 wantErr: false, 199 }, 200 { 201 name: "Upgrade for both current contract and next contract (not supported)", // upgrade plan should report unsupported options 202 fields: fields{ 203 // config for two providers 204 reader: test.NewFakeReader(). 205 WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). 206 WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), 207 repository: map[string]repository.Repository{ 208 "cluster-api": repository.NewMemoryRepository(). 209 WithVersions("v1.0.0", "v1.0.1", "v2.0.0"). 210 WithMetadata("v2.0.0", &clusterctlv1.Metadata{ 211 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 212 {Major: 1, Minor: 0, Contract: test.CurrentCAPIContract}, 213 {Major: 2, Minor: 0, Contract: test.NextCAPIContractNotSupported}, 214 }, 215 }), 216 "infrastructure-infra": repository.NewMemoryRepository(). 217 WithVersions("v2.0.0", "v2.0.1", "v3.0.0"). 218 WithMetadata("v3.0.0", &clusterctlv1.Metadata{ 219 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 220 {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, 221 {Major: 3, Minor: 0, Contract: test.NextCAPIContractNotSupported}, 222 }, 223 }), 224 }, 225 // two providers existing in the cluster 226 proxy: test.NewFakeProxy(). 227 WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"). 228 WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 229 }, 230 want: []UpgradePlan{ 231 { // one upgrade plan with the latest releases in the current 232 Contract: test.CurrentCAPIContract, 233 Providers: []UpgradeItem{ 234 { 235 Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"), 236 NextVersion: "v1.0.1", 237 }, 238 { 239 Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 240 NextVersion: "v2.0.1", 241 }, 242 }, 243 }, 244 { // one upgrade plan with the latest releases in the next contract (not supported, but upgrade plan should report these options) 245 Contract: test.NextCAPIContractNotSupported, 246 Providers: []UpgradeItem{ 247 { 248 Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"), 249 NextVersion: "v2.0.0", 250 }, 251 { 252 Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 253 NextVersion: "v3.0.0", 254 }, 255 }, 256 }, 257 }, 258 wantErr: false, 259 }, 260 { 261 name: "Partial upgrades for next contract", // upgrade plan should report unsupported options 262 fields: fields{ 263 // config for two providers 264 reader: test.NewFakeReader(). 265 WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). 266 WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), 267 repository: map[string]repository.Repository{ 268 "cluster-api": repository.NewMemoryRepository(). 269 WithVersions("v1.0.0", "v1.0.1", "v2.0.0"). 270 WithMetadata("v2.0.0", &clusterctlv1.Metadata{ 271 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 272 {Major: 1, Minor: 0, Contract: test.CurrentCAPIContract}, 273 {Major: 2, Minor: 0, Contract: test.NextCAPIContractNotSupported}, 274 }, 275 }), 276 "infrastructure-infra": repository.NewMemoryRepository(). 277 WithVersions("v2.0.0"). // no new releases available for the infra provider (only the current release exists) 278 WithMetadata("v2.0.0", &clusterctlv1.Metadata{ 279 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 280 {Major: 2, Minor: 0, Contract: test.NextCAPIContractNotSupported}, 281 }, 282 }), 283 }, 284 // two providers existing in the cluster 285 proxy: test.NewFakeProxy(). 286 WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"). 287 WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 288 }, 289 want: []UpgradePlan{ 290 { // one upgrade plan with the latest releases in the current contract 291 Contract: test.CurrentCAPIContract, 292 Providers: []UpgradeItem{ 293 { 294 Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"), 295 NextVersion: "v1.0.1", 296 }, 297 { 298 Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 299 NextVersion: "", // we are already to the latest version for the infra provider, but this is acceptable for the current contract 300 }, 301 }, 302 }, 303 // the upgrade plan with the latest releases in the next contract should be dropped because all the provider are required to change the contract at the same time 304 }, 305 wantErr: false, 306 }, 307 } 308 for _, tt := range tests { 309 t.Run(tt.name, func(t *testing.T) { 310 g := NewWithT(t) 311 312 ctx := context.Background() 313 314 configClient, _ := config.New(ctx, "", config.InjectReader(tt.fields.reader)) 315 316 u := &providerUpgrader{ 317 configClient: configClient, 318 repositoryClientFactory: func(ctx context.Context, provider config.Provider, configClient config.Client, _ ...repository.Option) (repository.Client, error) { 319 return repository.New(ctx, provider, configClient, repository.InjectRepository(tt.fields.repository[provider.ManifestLabel()])) 320 }, 321 providerInventory: newInventoryClient(tt.fields.proxy, nil), 322 } 323 got, err := u.Plan(ctx) 324 if tt.wantErr { 325 g.Expect(err).To(HaveOccurred()) 326 return 327 } 328 329 g.Expect(err).ToNot(HaveOccurred()) 330 g.Expect(got).To(BeComparableTo(tt.want), cmp.Diff(got, tt.want)) 331 }) 332 } 333 } 334 335 func Test_providerUpgrader_createCustomPlan(t *testing.T) { 336 type fields struct { 337 reader config.Reader 338 repository map[string]repository.Repository 339 proxy Proxy 340 } 341 type args struct { 342 coreProvider clusterctlv1.Provider 343 providersToUpgrade []UpgradeItem 344 } 345 tests := []struct { 346 name string 347 fields fields 348 args args 349 want *UpgradePlan 350 wantErr bool 351 }{ 352 { 353 name: "pass if upgrade infra provider, same contract", 354 fields: fields{ 355 // config for two providers 356 reader: test.NewFakeReader(). 357 WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). 358 WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), 359 repository: map[string]repository.Repository{ 360 "cluster-api": repository.NewMemoryRepository(). 361 WithVersions("v1.0.0", "v1.0.1"). 362 WithMetadata("v1.0.1", &clusterctlv1.Metadata{ 363 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 364 {Major: 1, Minor: 0, Contract: test.CurrentCAPIContract}, 365 }, 366 }), 367 "infra": repository.NewMemoryRepository(). 368 WithVersions("v2.0.0", "v2.0.1"). 369 WithMetadata("v2.0.1", &clusterctlv1.Metadata{ 370 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 371 {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, 372 }, 373 }), 374 }, 375 // two providers existing in the cluster 376 proxy: test.NewFakeProxy(). 377 WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"). 378 WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 379 }, 380 args: args{ 381 coreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "", "cluster-api-system"), 382 providersToUpgrade: []UpgradeItem{ 383 { 384 Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 385 NextVersion: "v2.0.1", // upgrade to next release in the current contract 386 }, 387 }, 388 }, 389 want: &UpgradePlan{ 390 Contract: test.CurrentCAPIContract, 391 Providers: []UpgradeItem{ 392 { 393 Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 394 NextVersion: "v2.0.1", 395 }, 396 }, 397 }, 398 wantErr: false, 399 }, 400 { 401 name: "pass if upgrade core provider, same contract", 402 fields: fields{ 403 // config for two providers 404 reader: test.NewFakeReader(). 405 WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). 406 WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), 407 repository: map[string]repository.Repository{ 408 "cluster-api": repository.NewMemoryRepository(). 409 WithVersions("v1.0.0", "v1.0.1"). 410 WithMetadata("v1.0.1", &clusterctlv1.Metadata{ 411 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 412 {Major: 1, Minor: 0, Contract: test.CurrentCAPIContract}, 413 }, 414 }), 415 "infra": repository.NewMemoryRepository(). 416 WithVersions("v2.0.0", "v2.0.1"). 417 WithMetadata("v2.0.1", &clusterctlv1.Metadata{ 418 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 419 {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, 420 }, 421 }), 422 }, 423 // two providers existing in the cluster 424 proxy: test.NewFakeProxy(). 425 WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"). 426 WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 427 }, 428 args: args{ 429 coreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "", "cluster-api-system"), 430 providersToUpgrade: []UpgradeItem{ 431 { 432 Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"), 433 NextVersion: "v1.0.1", // upgrade to next release in the current contract 434 }, 435 }, 436 }, 437 want: &UpgradePlan{ 438 Contract: test.CurrentCAPIContract, 439 Providers: []UpgradeItem{ 440 { 441 Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"), 442 NextVersion: "v1.0.1", 443 }, 444 }, 445 }, 446 wantErr: false, 447 }, 448 { 449 name: "pass if upgrade core and infra provider, same contract", 450 fields: fields{ 451 // config for two providers 452 reader: test.NewFakeReader(). 453 WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). 454 WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), 455 repository: map[string]repository.Repository{ 456 "cluster-api": repository.NewMemoryRepository(). 457 WithVersions("v1.0.0", "v2.0.0"). 458 WithMetadata("v2.0.0", &clusterctlv1.Metadata{ 459 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 460 {Major: 1, Minor: 0, Contract: test.CurrentCAPIContract}, 461 {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, 462 }, 463 }), 464 "infra": repository.NewMemoryRepository(). 465 WithVersions("v2.0.0", "v3.0.0"). 466 WithMetadata("v3.0.0", &clusterctlv1.Metadata{ 467 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 468 {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, 469 {Major: 3, Minor: 0, Contract: test.CurrentCAPIContract}, 470 }, 471 }), 472 }, 473 // two providers existing in the cluster 474 proxy: test.NewFakeProxy(). 475 WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"). 476 WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 477 }, 478 args: args{ 479 coreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "", "cluster-api-system"), 480 providersToUpgrade: []UpgradeItem{ 481 { 482 Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"), 483 NextVersion: "v2.0.0", // upgrade to next release in the next contract; not supported in current clusterctl release. 484 }, 485 { 486 Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 487 NextVersion: "v3.0.0", // upgrade to next release in the next contract; not supported in current clusterctl release. 488 }, 489 }, 490 }, 491 want: &UpgradePlan{ 492 Contract: test.CurrentCAPIContract, 493 Providers: []UpgradeItem{ 494 { 495 Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"), 496 NextVersion: "v2.0.0", 497 }, 498 { 499 Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 500 NextVersion: "v3.0.0", 501 }, 502 }, 503 }, 504 wantErr: false, 505 }, 506 { 507 name: "fail if upgrade infra provider alone from current to the next contract", // not supported in current clusterctl release. 508 fields: fields{ 509 // config for two providers 510 reader: test.NewFakeReader(). 511 WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). 512 WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), 513 repository: map[string]repository.Repository{ 514 "cluster-api": repository.NewMemoryRepository(). 515 WithVersions("v1.0.0", "v2.0.0"). 516 WithMetadata("v2.0.0", &clusterctlv1.Metadata{ 517 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 518 {Major: 1, Minor: 0, Contract: test.CurrentCAPIContract}, 519 {Major: 2, Minor: 0, Contract: test.NextCAPIContractNotSupported}, 520 }, 521 }), 522 "infra": repository.NewMemoryRepository(). 523 WithVersions("v2.0.0", "v3.0.0"). 524 WithMetadata("v3.0.0", &clusterctlv1.Metadata{ 525 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 526 {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, 527 {Major: 3, Minor: 0, Contract: test.NextCAPIContractNotSupported}, 528 }, 529 }), 530 }, 531 // two providers existing in the cluster 532 proxy: test.NewFakeProxy(). 533 WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"). 534 WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 535 }, 536 args: args{ 537 coreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "", "cluster-api-system"), 538 providersToUpgrade: []UpgradeItem{ 539 { 540 Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 541 NextVersion: "v3.0.0", // upgrade to next release in the next contract; not supported in current clusterctl release. 542 }, 543 }, 544 }, 545 want: nil, 546 wantErr: true, 547 }, 548 { 549 name: "fail if upgrade infra provider alone from previous to the current contract", 550 fields: fields{ 551 // config for two providers 552 reader: test.NewFakeReader(). 553 WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). 554 WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), 555 repository: map[string]repository.Repository{ 556 "cluster-api": repository.NewMemoryRepository(). 557 WithVersions("v1.0.0", "v2.0.0"). 558 WithMetadata("v2.0.0", &clusterctlv1.Metadata{ 559 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 560 {Major: 1, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, 561 {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, 562 }, 563 }), 564 "infra": repository.NewMemoryRepository(). 565 WithVersions("v2.0.0", "v3.0.0"). 566 WithMetadata("v3.0.0", &clusterctlv1.Metadata{ 567 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 568 {Major: 2, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, 569 {Major: 3, Minor: 0, Contract: test.CurrentCAPIContract}, 570 }, 571 }), 572 }, 573 // two providers existing in the cluster 574 proxy: test.NewFakeProxy(). 575 WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"). 576 WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 577 }, 578 args: args{ 579 coreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "", "cluster-api-system"), 580 providersToUpgrade: []UpgradeItem{ 581 { 582 Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 583 NextVersion: "v3.0.0", // upgrade to next release in the current contract. 584 }, 585 }, 586 }, 587 want: nil, 588 wantErr: true, 589 }, 590 { 591 name: "fail if upgrade core provider alone from current to the next contract", // not supported in current clusterctl release. 592 fields: fields{ 593 // config for two providers 594 reader: test.NewFakeReader(). 595 WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). 596 WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), 597 repository: map[string]repository.Repository{ 598 "cluster-api": repository.NewMemoryRepository(). 599 WithVersions("v1.0.0", "v2.0.0"). 600 WithMetadata("v2.0.0", &clusterctlv1.Metadata{ 601 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 602 {Major: 1, Minor: 0, Contract: test.CurrentCAPIContract}, 603 {Major: 2, Minor: 0, Contract: test.NextCAPIContractNotSupported}, 604 }, 605 }), 606 "infra": repository.NewMemoryRepository(). 607 WithVersions("v2.0.0", "v3.0.0"). 608 WithMetadata("v3.0.0", &clusterctlv1.Metadata{ 609 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 610 {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, 611 {Major: 3, Minor: 0, Contract: test.NextCAPIContractNotSupported}, 612 }, 613 }), 614 }, 615 // two providers existing in the cluster 616 proxy: test.NewFakeProxy(). 617 WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"). 618 WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 619 }, 620 args: args{ 621 coreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "", "cluster-api-system"), 622 providersToUpgrade: []UpgradeItem{ 623 { 624 Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"), 625 NextVersion: "v2.0.0", // upgrade to next release in the next contract; not supported in current clusterctl release. 626 }, 627 }, 628 }, 629 want: nil, 630 wantErr: true, 631 }, 632 { 633 name: "fail if upgrade core provider alone from previous to the current contract", 634 fields: fields{ 635 // config for two providers 636 reader: test.NewFakeReader(). 637 WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). 638 WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), 639 repository: map[string]repository.Repository{ 640 "cluster-api": repository.NewMemoryRepository(). 641 WithVersions("v1.0.0", "v2.0.0"). 642 WithMetadata("v2.0.0", &clusterctlv1.Metadata{ 643 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 644 {Major: 1, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, 645 {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, 646 }, 647 }), 648 "infra": repository.NewMemoryRepository(). 649 WithVersions("v2.0.0", "v3.0.0"). 650 WithMetadata("v3.0.0", &clusterctlv1.Metadata{ 651 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 652 {Major: 2, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, 653 {Major: 3, Minor: 0, Contract: test.CurrentCAPIContract}, 654 }, 655 }), 656 }, 657 // two providers existing in the cluster 658 proxy: test.NewFakeProxy(). 659 WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"). 660 WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 661 }, 662 args: args{ 663 coreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "", "cluster-api-system"), 664 providersToUpgrade: []UpgradeItem{ 665 { 666 Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"), 667 NextVersion: "v2.0.0", // upgrade to next release in the current contract 668 }, 669 }, 670 }, 671 want: nil, 672 wantErr: true, 673 }, 674 { 675 name: "fail if upgrade core and infra provider to the next contract", // not supported in current clusterctl release 676 fields: fields{ 677 // config for two providers 678 reader: test.NewFakeReader(). 679 WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). 680 WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), 681 repository: map[string]repository.Repository{ 682 "cluster-api": repository.NewMemoryRepository(). 683 WithVersions("v1.0.0", "v2.0.0"). 684 WithMetadata("v2.0.0", &clusterctlv1.Metadata{ 685 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 686 {Major: 1, Minor: 0, Contract: test.CurrentCAPIContract}, 687 {Major: 2, Minor: 0, Contract: test.NextCAPIContractNotSupported}, 688 }, 689 }), 690 "infra": repository.NewMemoryRepository(). 691 WithVersions("v2.0.0", "v3.0.0"). 692 WithMetadata("v3.0.0", &clusterctlv1.Metadata{ 693 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 694 {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, 695 {Major: 3, Minor: 0, Contract: test.NextCAPIContractNotSupported}, 696 }, 697 }), 698 }, 699 // two providers existing in the cluster 700 proxy: test.NewFakeProxy(). 701 WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"). 702 WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 703 }, 704 args: args{ 705 coreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "", "cluster-api-system"), 706 providersToUpgrade: []UpgradeItem{ 707 { 708 Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"), 709 NextVersion: "v2.0.0", // upgrade to next release in the next contract; not supported in current clusterctl release. 710 }, 711 { 712 Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 713 NextVersion: "v3.0.0", // upgrade to next release in the next contract; not supported in current clusterctl release. 714 }, 715 }, 716 }, 717 want: nil, 718 wantErr: true, 719 }, 720 { 721 name: "pass if upgrade core and infra provider from previous to current contract", 722 fields: fields{ 723 // config for two providers 724 reader: test.NewFakeReader(). 725 WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). 726 WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), 727 repository: map[string]repository.Repository{ 728 "cluster-api": repository.NewMemoryRepository(). 729 WithVersions("v1.0.0", "v2.0.0"). 730 WithMetadata("v2.0.0", &clusterctlv1.Metadata{ 731 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 732 {Major: 1, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, 733 {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, 734 }, 735 }), 736 "infra": repository.NewMemoryRepository(). 737 WithVersions("v2.0.0", "v3.0.0"). 738 WithMetadata("v3.0.0", &clusterctlv1.Metadata{ 739 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 740 {Major: 2, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, 741 {Major: 3, Minor: 0, Contract: test.CurrentCAPIContract}, 742 }, 743 }), 744 }, 745 // two providers existing in the cluster 746 proxy: test.NewFakeProxy(). 747 WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"). 748 WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 749 }, 750 args: args{ 751 coreProvider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "", "cluster-api-system"), 752 providersToUpgrade: []UpgradeItem{ 753 { 754 Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"), 755 NextVersion: "v2.0.0", // upgrade to next release in the next contract; not supported in current clusterctl release. 756 }, 757 { 758 Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 759 NextVersion: "v3.0.0", // upgrade to next release in the next contract; not supported in current clusterctl release. 760 }, 761 }, 762 }, 763 want: &UpgradePlan{ 764 Contract: test.CurrentCAPIContract, 765 Providers: []UpgradeItem{ 766 { 767 Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"), 768 NextVersion: "v2.0.0", 769 }, 770 { 771 Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 772 NextVersion: "v3.0.0", 773 }, 774 }, 775 }, 776 wantErr: false, 777 }, 778 } 779 for _, tt := range tests { 780 t.Run(tt.name, func(t *testing.T) { 781 g := NewWithT(t) 782 783 ctx := context.Background() 784 785 configClient, _ := config.New(ctx, "", config.InjectReader(tt.fields.reader)) 786 787 u := &providerUpgrader{ 788 configClient: configClient, 789 repositoryClientFactory: func(ctx context.Context, provider config.Provider, configClient config.Client, _ ...repository.Option) (repository.Client, error) { 790 return repository.New(ctx, provider, configClient, repository.InjectRepository(tt.fields.repository[provider.Name()])) 791 }, 792 providerInventory: newInventoryClient(tt.fields.proxy, nil), 793 } 794 got, err := u.createCustomPlan(ctx, tt.args.providersToUpgrade) 795 if tt.wantErr { 796 g.Expect(err).To(HaveOccurred()) 797 return 798 } 799 800 g.Expect(err).ToNot(HaveOccurred()) 801 g.Expect(got).To(BeComparableTo(tt.want)) 802 }) 803 } 804 } 805 806 // TODO add tests for success scenarios. 807 func Test_providerUpgrader_ApplyPlan(t *testing.T) { 808 type fields struct { 809 reader config.Reader 810 repository map[string]repository.Repository 811 proxy Proxy 812 } 813 814 tests := []struct { 815 name string 816 fields fields 817 contract string 818 wantErr bool 819 errorMsg string 820 opts UpgradeOptions 821 }{ 822 { 823 name: "fails to upgrade to current contract when there are multiple instances of the core provider", 824 fields: fields{ 825 // config for two providers 826 reader: test.NewFakeReader(). 827 WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). 828 WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), 829 // two provider repositories, with current v1alpha3 contract and new versions for v1alpha4 contract 830 repository: map[string]repository.Repository{ 831 "cluster-api": repository.NewMemoryRepository(). 832 WithVersions("v1.0.0", "v1.0.1", "v2.0.0"). 833 WithMetadata("v2.0.0", &clusterctlv1.Metadata{ 834 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 835 {Major: 1, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, 836 {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, 837 }, 838 }), 839 "infrastructure-infra": repository.NewMemoryRepository(). 840 WithVersions("v2.0.0", "v2.0.1", "v3.0.0"). 841 WithMetadata("v3.0.0", &clusterctlv1.Metadata{ 842 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 843 {Major: 2, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, 844 {Major: 3, Minor: 0, Contract: test.CurrentCAPIContract}, 845 }, 846 }), 847 }, 848 // two providers with multiple instances existing in the cluster 849 proxy: test.NewFakeProxy(). 850 WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"). 851 WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system-1"). 852 WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 853 }, 854 contract: test.CurrentCAPIContract, 855 wantErr: true, 856 errorMsg: "detected multiple instances of the same provider", 857 opts: UpgradeOptions{}, 858 }, 859 { 860 name: "fails to upgrade to current contract when there are multiple instances of the infra provider", 861 fields: fields{ 862 // config for two providers 863 reader: test.NewFakeReader(). 864 WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). 865 WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), 866 // two provider repositories, with current v1alpha3 contract and new versions for v1alpha4 contract 867 repository: map[string]repository.Repository{ 868 "cluster-api": repository.NewMemoryRepository(). 869 WithVersions("v1.0.0", "v1.0.1", "v2.0.0"). 870 WithMetadata("v2.0.0", &clusterctlv1.Metadata{ 871 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 872 {Major: 1, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, 873 {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, 874 }, 875 }), 876 "infrastructure-infra": repository.NewMemoryRepository(). 877 WithVersions("v2.0.0", "v2.0.1", "v3.0.0"). 878 WithMetadata("v3.0.0", &clusterctlv1.Metadata{ 879 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 880 {Major: 2, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, 881 {Major: 3, Minor: 0, Contract: test.CurrentCAPIContract}, 882 }, 883 }), 884 }, 885 // two providers with multiple instances existing in the cluster 886 proxy: test.NewFakeProxy(). 887 WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"). 888 WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"). 889 WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system-1"), 890 }, 891 contract: test.CurrentCAPIContract, 892 wantErr: true, 893 errorMsg: "detected multiple instances of the same provider", 894 opts: UpgradeOptions{}, 895 }, 896 } 897 898 for _, tt := range tests { 899 t.Run(tt.name, func(t *testing.T) { 900 g := NewWithT(t) 901 902 ctx := context.Background() 903 904 configClient, _ := config.New(ctx, "", config.InjectReader(tt.fields.reader)) 905 906 u := &providerUpgrader{ 907 configClient: configClient, 908 repositoryClientFactory: func(ctx context.Context, provider config.Provider, configClient config.Client, _ ...repository.Option) (repository.Client, error) { 909 return repository.New(ctx, provider, configClient, repository.InjectRepository(tt.fields.repository[provider.ManifestLabel()])) 910 }, 911 providerInventory: newInventoryClient(tt.fields.proxy, nil), 912 } 913 err := u.ApplyPlan(ctx, tt.opts, tt.contract) 914 if tt.wantErr { 915 g.Expect(err).To(HaveOccurred()) 916 g.Expect(err.Error()).Should(ContainSubstring(tt.errorMsg)) 917 return 918 } 919 920 g.Expect(err).ToNot(HaveOccurred()) 921 }) 922 } 923 } 924 925 // TODO add tests for success scenarios. 926 func Test_providerUpgrader_ApplyCustomPlan(t *testing.T) { 927 type fields struct { 928 reader config.Reader 929 repository map[string]repository.Repository 930 proxy Proxy 931 } 932 933 tests := []struct { 934 name string 935 fields fields 936 providersToUpgrade []UpgradeItem 937 wantErr bool 938 errorMsg string 939 opts UpgradeOptions 940 }{ 941 { 942 name: "fails to upgrade to v1alpha4 when there are multiple instances of the core provider", 943 fields: fields{ 944 // config for two providers 945 reader: test.NewFakeReader(). 946 WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). 947 WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), 948 // two provider repositories, with current v1alpha3 contract and new versions for v1alpha4 contract 949 repository: map[string]repository.Repository{ 950 "cluster-api": repository.NewMemoryRepository(). 951 WithVersions("v1.0.0", "v1.0.1", "v2.0.0"). 952 WithMetadata("v2.0.0", &clusterctlv1.Metadata{ 953 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 954 {Major: 1, Minor: 0, Contract: "v1alpha3"}, 955 {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, 956 }, 957 }), 958 "infrastructure-infra": repository.NewMemoryRepository(). 959 WithVersions("v2.0.0", "v2.0.1", "v3.0.0"). 960 WithMetadata("v3.0.0", &clusterctlv1.Metadata{ 961 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 962 {Major: 2, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, 963 {Major: 3, Minor: 0, Contract: test.CurrentCAPIContract}, 964 }, 965 }), 966 }, 967 // two providers with multiple instances existing in the cluster 968 proxy: test.NewFakeProxy(). 969 WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"). 970 WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system-1"). 971 WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 972 }, 973 providersToUpgrade: []UpgradeItem{ 974 { 975 Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"), 976 NextVersion: "v2.0.0", 977 }, 978 { 979 Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 980 NextVersion: "v3.0.0", 981 }, 982 }, 983 wantErr: true, 984 errorMsg: "invalid management cluster: there should a core provider, found 2", 985 opts: UpgradeOptions{}, 986 }, 987 { 988 name: "fails to upgrade to v1alpha4 when there are multiple instances of the infra provider", 989 fields: fields{ 990 // config for two providers 991 reader: test.NewFakeReader(). 992 WithProvider("cluster-api", clusterctlv1.CoreProviderType, "https://somewhere.com"). 993 WithProvider("infra", clusterctlv1.InfrastructureProviderType, "https://somewhere.com"), 994 // two provider repositories, with current v1alpha3 contract and new versions for v1alpha4 contract 995 repository: map[string]repository.Repository{ 996 "cluster-api": repository.NewMemoryRepository(). 997 WithVersions("v1.0.0", "v1.0.1", "v2.0.0"). 998 WithMetadata("v2.0.0", &clusterctlv1.Metadata{ 999 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 1000 {Major: 1, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, 1001 {Major: 2, Minor: 0, Contract: test.CurrentCAPIContract}, 1002 }, 1003 }), 1004 "infrastructure-infra": repository.NewMemoryRepository(). 1005 WithVersions("v2.0.0", "v2.0.1", "v3.0.0"). 1006 WithMetadata("v3.0.0", &clusterctlv1.Metadata{ 1007 ReleaseSeries: []clusterctlv1.ReleaseSeries{ 1008 {Major: 2, Minor: 0, Contract: test.PreviousCAPIContractNotSupported}, 1009 {Major: 3, Minor: 0, Contract: test.CurrentCAPIContract}, 1010 }, 1011 }), 1012 }, 1013 // two providers with multiple instances existing in the cluster 1014 proxy: test.NewFakeProxy(). 1015 WithProviderInventory("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"). 1016 WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"). 1017 WithProviderInventory("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system-1"), 1018 }, 1019 providersToUpgrade: []UpgradeItem{ 1020 { 1021 Provider: fakeProvider("cluster-api", clusterctlv1.CoreProviderType, "v1.0.0", "cluster-api-system"), 1022 NextVersion: "v2.0.0", 1023 }, 1024 { 1025 Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system"), 1026 NextVersion: "v3.0.0", 1027 }, 1028 { 1029 Provider: fakeProvider("infra", clusterctlv1.InfrastructureProviderType, "v2.0.0", "infra-system-1"), 1030 NextVersion: "v3.0.0", 1031 }, 1032 }, 1033 wantErr: true, 1034 errorMsg: "detected multiple instances of the same provider", 1035 opts: UpgradeOptions{}, 1036 }, 1037 } 1038 1039 for _, tt := range tests { 1040 t.Run(tt.name, func(t *testing.T) { 1041 g := NewWithT(t) 1042 1043 ctx := context.Background() 1044 1045 configClient, _ := config.New(ctx, "", config.InjectReader(tt.fields.reader)) 1046 1047 u := &providerUpgrader{ 1048 configClient: configClient, 1049 repositoryClientFactory: func(ctx context.Context, provider config.Provider, configClient config.Client, _ ...repository.Option) (repository.Client, error) { 1050 return repository.New(ctx, provider, configClient, repository.InjectRepository(tt.fields.repository[provider.ManifestLabel()])) 1051 }, 1052 providerInventory: newInventoryClient(tt.fields.proxy, nil), 1053 } 1054 err := u.ApplyCustomPlan(ctx, tt.opts, tt.providersToUpgrade...) 1055 if tt.wantErr { 1056 g.Expect(err).To(HaveOccurred()) 1057 g.Expect(err.Error()).Should(ContainSubstring(tt.errorMsg)) 1058 return 1059 } 1060 1061 g.Expect(err).ToNot(HaveOccurred()) 1062 }) 1063 } 1064 }