github.com/openshift/installer@v1.4.17/pkg/asset/installconfig/powervs/validation_test.go (about) 1 package powervs_test 2 3 import ( 4 "fmt" 5 "os" 6 "testing" 7 8 "github.com/IBM/vpc-go-sdk/vpcv1" 9 "github.com/golang/mock/gomock" 10 "github.com/stretchr/testify/assert" 11 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 12 "k8s.io/apimachinery/pkg/runtime" 13 14 machinev1 "github.com/openshift/api/machine/v1" 15 machinev1beta1 "github.com/openshift/api/machine/v1beta1" 16 "github.com/openshift/installer/pkg/asset/installconfig/powervs" 17 "github.com/openshift/installer/pkg/asset/installconfig/powervs/mock" 18 "github.com/openshift/installer/pkg/ipnet" 19 "github.com/openshift/installer/pkg/types" 20 powervstypes "github.com/openshift/installer/pkg/types/powervs" 21 ) 22 23 type editFunctions []func(ic *types.InstallConfig) 24 25 var ( 26 validRegion = "dal" 27 validCIDR = "192.168.0.0/24" 28 validCISInstanceCRN = "crn:v1:bluemix:public:internet-svcs:global:a/valid-account-id:valid-instance-id::" 29 validClusterName = "valid-cluster-name" 30 validDNSZoneID = "valid-zone-id" 31 validBaseDomain = "valid.base.domain" 32 validPowerVSResourceGroup = "valid-resource-group" 33 validPublicSubnetUSSouth1ID = "public-subnet-us-south-1-id" 34 validPublicSubnetUSSouth2ID = "public-subnet-us-south-2-id" 35 validPrivateSubnetUSSouth1ID = "private-subnet-us-south-1-id" 36 validPrivateSubnetUSSouth2ID = "private-subnet-us-south-2-id" 37 validSubnets = []string{ 38 validPublicSubnetUSSouth1ID, 39 validPublicSubnetUSSouth2ID, 40 validPrivateSubnetUSSouth1ID, 41 validPrivateSubnetUSSouth2ID, 42 } 43 validUserID = "valid-user@example.com" 44 validZone = "dal10" 45 46 existingDNSRecordsResponse = []powervs.DNSRecordResponse{ 47 { 48 Name: "valid-dns-record-name-1", 49 Type: "valid-dns-record-type", 50 }, 51 { 52 Name: "valid-dns-record-name-2", 53 Type: "valid-dns-record-type", 54 }, 55 } 56 noDNSRecordsResponse = []powervs.DNSRecordResponse{} 57 invalidArchitecture = func(ic *types.InstallConfig) { ic.ControlPlane.Architecture = "ppc64" } 58 cidrInvalid, _ = ipnet.ParseCIDR("192.168.0.0/16") 59 invalidMachinePoolCIDR = func(ic *types.InstallConfig) { ic.Networking.MachineNetwork[0].CIDR = *cidrInvalid } 60 cidrValid, _ = ipnet.ParseCIDR("192.168.0.0/24") 61 validMachinePoolCIDR = func(ic *types.InstallConfig) { ic.Networking.MachineNetwork[0].CIDR = *cidrValid } 62 validVPCRegion = "us-south" 63 invalidVPCRegion = "foo-bah" 64 setValidVPCRegion = func(ic *types.InstallConfig) { ic.Platform.PowerVS.VPCRegion = validVPCRegion } 65 validRG = "valid-resource-group" 66 anotherValidRG = "another-valid-resource-group" 67 validVPCID = "valid-id" 68 anotherValidVPCID = "another-valid-id" 69 validVPC = "valid-vpc" 70 setValidVPCName = func(ic *types.InstallConfig) { ic.Platform.PowerVS.VPCName = validVPC } 71 anotherValidVPC = "another-valid-vpc" 72 invalidVPC = "bogus-vpc" 73 validVPCs = []vpcv1.VPC{ 74 { 75 Name: &validVPC, 76 ID: &validVPCID, 77 ResourceGroup: &vpcv1.ResourceGroupReference{ 78 Name: &validRG, 79 ID: &validRG, 80 }, 81 }, 82 { 83 Name: &anotherValidVPC, 84 ID: &anotherValidVPCID, 85 ResourceGroup: &vpcv1.ResourceGroupReference{ 86 Name: &anotherValidRG, 87 ID: &anotherValidRG, 88 }, 89 }, 90 } 91 validVPCSubnet = "valid-vpc-subnet" 92 invalidVPCSubnet = "invalid-vpc-subnet" 93 wrongVPCSubnet = "wrong-vpc-subnet" 94 validSubnet = &vpcv1.Subnet{ 95 Name: &validRG, 96 VPC: &vpcv1.VPCReference{ 97 Name: &validVPC, 98 ID: &validVPCID, 99 }, 100 ResourceGroup: &vpcv1.ResourceGroupReference{ 101 Name: &validRG, 102 ID: &validRG, 103 }, 104 } 105 wrongSubnet = &vpcv1.Subnet{ 106 Name: &validRG, 107 VPC: &vpcv1.VPCReference{ 108 Name: &anotherValidVPC, 109 ID: &anotherValidVPCID, 110 }, 111 ResourceGroup: &vpcv1.ResourceGroupReference{ 112 Name: &validRG, 113 ID: &validRG, 114 }, 115 } 116 regionWithPER = "dal10" 117 regionWithoutPER = "foo99" 118 regionPERUnknown = "bah77" 119 mapWithPERFalse = map[string]bool{ 120 "disaster-recover-site": true, 121 "power-edge-router": false, 122 "vpn-connections": true, 123 } 124 mapWithPERTrue = map[string]bool{ 125 "disaster-recover-site": true, 126 "power-edge-router": true, 127 "vpn-connections": true, 128 } 129 mapPERUnknown = map[string]bool{ 130 "disaster-recover-site": true, 131 "power-vpn-connections": false, 132 } 133 defaultSysType = "s922" 134 newSysType = "s1022" 135 invalidRegion = "foo" 136 validServiceInstanceGUID = "" 137 ) 138 139 func validInstallConfig() *types.InstallConfig { 140 return &types.InstallConfig{ 141 ObjectMeta: metav1.ObjectMeta{ 142 Name: validClusterName, 143 }, 144 BaseDomain: validBaseDomain, 145 Networking: &types.Networking{ 146 MachineNetwork: []types.MachineNetworkEntry{ 147 {CIDR: *ipnet.MustParseCIDR(validCIDR)}, 148 }, 149 }, 150 Publish: types.ExternalPublishingStrategy, 151 Platform: types.Platform{ 152 PowerVS: validMinimalPlatform(), 153 }, 154 ControlPlane: &types.MachinePool{ 155 Architecture: "ppc64le", 156 }, 157 Compute: []types.MachinePool{{ 158 Architecture: "ppc64le", 159 }}, 160 } 161 } 162 163 func validMinimalPlatform() *powervstypes.Platform { 164 return &powervstypes.Platform{ 165 PowerVSResourceGroup: validPowerVSResourceGroup, 166 Region: validRegion, 167 ServiceInstanceGUID: validServiceInstanceGUID, 168 UserID: validUserID, 169 Zone: validZone, 170 } 171 } 172 173 func validMachinePool() *powervstypes.MachinePool { 174 return &powervstypes.MachinePool{} 175 } 176 177 func TestValidate(t *testing.T) { 178 cases := []struct { 179 name string 180 edits editFunctions 181 errorMsg string 182 }{ 183 { 184 name: "valid install config", 185 edits: editFunctions{}, 186 errorMsg: "", 187 }, 188 { 189 name: "invalid architecture", 190 edits: editFunctions{invalidArchitecture}, 191 errorMsg: `^controlPlane.architecture\: Unsupported value\: \"ppc64\"\: supported values: \"ppc64le\"`, 192 }, 193 { 194 name: "invalid machine pool CIDR", 195 edits: editFunctions{invalidMachinePoolCIDR}, 196 errorMsg: `Networking.MachineNetwork.CIDR: Invalid value: "192.168.0.0/16": Machine Pool CIDR must be /24.`, 197 }, 198 { 199 name: "valid machine pool CIDR", 200 edits: editFunctions{validMachinePoolCIDR}, 201 errorMsg: "", 202 }, 203 } 204 205 mockCtrl := gomock.NewController(t) 206 defer mockCtrl.Finish() 207 208 for _, tc := range cases { 209 t.Run(tc.name, func(t *testing.T) { 210 editedInstallConfig := validInstallConfig() 211 for _, edit := range tc.edits { 212 edit(editedInstallConfig) 213 } 214 215 aggregatedErrors := powervs.Validate(editedInstallConfig) 216 if tc.errorMsg != "" { 217 assert.Regexp(t, tc.errorMsg, aggregatedErrors) 218 } else { 219 assert.NoError(t, aggregatedErrors) 220 } 221 }) 222 } 223 } 224 225 func TestValidatePreExistingPublicDNS(t *testing.T) { 226 cases := []struct { 227 name string 228 edits editFunctions 229 errorMsg string 230 }{ 231 { 232 name: "no pre-existing DNS records", 233 errorMsg: "", 234 }, 235 { 236 name: "pre-existing DNS records", 237 errorMsg: `^\[baseDomain\: Duplicate value\: \"record api\.valid-cluster-name\.valid\.base\.domain already exists in CIS zone \(valid-zone-id\) and might be in use by another cluster, please remove it to continue\", baseDomain\: Duplicate value\: \"record api-int\.valid-cluster-name\.valid\.base\.domain already exists in CIS zone \(valid-zone-id\) and might be in use by another cluster, please remove it to continue\"\]$`, 238 }, 239 { 240 name: "cannot get zone ID", 241 errorMsg: `^baseDomain: Internal error$`, 242 }, 243 { 244 name: "cannot get DNS records", 245 errorMsg: `^baseDomain: Internal error$`, 246 }, 247 } 248 setMockEnvVars() 249 250 mockCtrl := gomock.NewController(t) 251 defer mockCtrl.Finish() 252 253 powervsClient := mock.NewMockAPI(mockCtrl) 254 metadata := mock.NewMockMetadataAPI(mockCtrl) 255 256 dnsRecordNames := [...]string{fmt.Sprintf("api.%s.%s", validClusterName, validBaseDomain), fmt.Sprintf("api-int.%s.%s", validClusterName, validBaseDomain)} 257 258 // Mock common to all tests 259 metadata.EXPECT().CISInstanceCRN(gomock.Any()).Return(validCISInstanceCRN, nil).AnyTimes() 260 261 // Mocks: no pre-existing DNS records 262 powervsClient.EXPECT().GetDNSZoneIDByName(gomock.Any(), validBaseDomain, types.ExternalPublishingStrategy).Return(validDNSZoneID, nil) 263 for _, dnsRecordName := range dnsRecordNames { 264 powervsClient.EXPECT().GetDNSRecordsByName(gomock.Any(), validCISInstanceCRN, validDNSZoneID, dnsRecordName, types.ExternalPublishingStrategy).Return(noDNSRecordsResponse, nil) 265 } 266 267 // Mocks: pre-existing DNS records 268 powervsClient.EXPECT().GetDNSZoneIDByName(gomock.Any(), validBaseDomain, types.ExternalPublishingStrategy).Return(validDNSZoneID, nil) 269 for _, dnsRecordName := range dnsRecordNames { 270 powervsClient.EXPECT().GetDNSRecordsByName(gomock.Any(), validCISInstanceCRN, validDNSZoneID, dnsRecordName, types.ExternalPublishingStrategy).Return(existingDNSRecordsResponse, nil) 271 } 272 273 // Mocks: cannot get zone ID 274 powervsClient.EXPECT().GetDNSZoneIDByName(gomock.Any(), validBaseDomain, types.ExternalPublishingStrategy).Return("", fmt.Errorf("")) 275 276 // Mocks: cannot get DNS records 277 powervsClient.EXPECT().GetDNSZoneIDByName(gomock.Any(), validBaseDomain, types.ExternalPublishingStrategy).Return(validDNSZoneID, nil) 278 for _, dnsRecordName := range dnsRecordNames { 279 powervsClient.EXPECT().GetDNSRecordsByName(gomock.Any(), validCISInstanceCRN, validDNSZoneID, dnsRecordName, types.ExternalPublishingStrategy).Return(nil, fmt.Errorf("")) 280 } 281 282 // Run tests 283 for _, tc := range cases { 284 t.Run(tc.name, func(t *testing.T) { 285 aggregatedErrors := powervs.ValidatePreExistingDNS(powervsClient, validInstallConfig(), metadata) 286 if tc.errorMsg != "" { 287 assert.Regexp(t, tc.errorMsg, aggregatedErrors) 288 } else { 289 assert.NoError(t, aggregatedErrors) 290 } 291 }) 292 } 293 } 294 295 func TestValidateCustomVPCSettings(t *testing.T) { 296 cases := []struct { 297 name string 298 edits editFunctions 299 errorMsg string 300 }{ 301 { 302 name: "invalid VPC region supplied alone", 303 edits: editFunctions{ 304 func(ic *types.InstallConfig) { 305 ic.Platform.PowerVS.VPCRegion = invalidVPCRegion 306 }, 307 }, 308 errorMsg: fmt.Sprintf(`VPC.vpcRegion: Not found: "%s"`, invalidVPCRegion), 309 }, 310 { 311 name: "valid VPC region supplied alone", 312 edits: editFunctions{ 313 func(ic *types.InstallConfig) { 314 ic.Platform.PowerVS.VPCRegion = validVPCRegion 315 }, 316 }, 317 errorMsg: "", 318 }, 319 { 320 name: "invalid VPC name supplied, without VPC region, not found near PowerVS region", 321 edits: editFunctions{ 322 func(ic *types.InstallConfig) { 323 ic.Platform.PowerVS.VPCName = invalidVPC 324 }, 325 }, 326 errorMsg: fmt.Sprintf(`VPC.vpcName: Not found: "%s"`, invalidVPC), 327 }, 328 { 329 name: "valid VPC name supplied, without VPC region, but found close to PowerVS region", 330 edits: editFunctions{ 331 setValidVPCName, 332 }, 333 errorMsg: "", 334 }, 335 { 336 name: "valid VPC name, with invalid VPC region", 337 edits: editFunctions{ 338 setValidVPCName, 339 func(ic *types.InstallConfig) { 340 ic.Platform.PowerVS.VPCRegion = invalidVPCRegion 341 }, 342 }, 343 errorMsg: "VPC.vpcRegion: Internal error: unknown region", 344 }, 345 { 346 name: "valid VPC name, valid VPC region", 347 edits: editFunctions{ 348 setValidVPCName, 349 setValidVPCRegion, 350 }, 351 errorMsg: "", 352 }, 353 { 354 name: "VPC subnet supplied, without vpcName", 355 edits: editFunctions{ 356 func(ic *types.InstallConfig) { 357 ic.Platform.PowerVS.VPCSubnets = []string{validVPCSubnet} 358 }, 359 }, 360 errorMsg: `VPC.vpcSubnets: Invalid value: "null": invalid without vpcName`, 361 }, 362 { 363 name: "VPC found, but not subnet", 364 edits: editFunctions{ 365 setValidVPCName, 366 func(ic *types.InstallConfig) { 367 ic.Platform.PowerVS.VPCSubnets = []string{invalidVPCSubnet} 368 }, 369 }, 370 errorMsg: "VPC.vpcSubnets: Internal error", 371 }, 372 { 373 name: "VPC found, subnet found as well, but not attached to the VPC", 374 edits: editFunctions{ 375 setValidVPCName, 376 func(ic *types.InstallConfig) { 377 ic.Platform.PowerVS.VPCSubnets = []string{wrongVPCSubnet} 378 }, 379 }, 380 errorMsg: `VPC.vpcSubnets: Invalid value: "null": not attached to VPC`, 381 }, 382 { 383 name: "region specified, VPC found, subnet found, and properly attached", 384 edits: editFunctions{ 385 setValidVPCName, 386 setValidVPCRegion, 387 func(ic *types.InstallConfig) { 388 ic.Platform.PowerVS.VPCSubnets = []string{validVPCSubnet} 389 }, 390 }, 391 errorMsg: "", 392 }, 393 } 394 setMockEnvVars() 395 396 mockCtrl := gomock.NewController(t) 397 defer mockCtrl.Finish() 398 399 powervsClient := mock.NewMockAPI(mockCtrl) 400 401 // Mocks: invalid VPC region only 402 // nothing to mock 403 404 // Mocks: valid VPC region only 405 // nothing to mock 406 407 // Mocks: invalid VPC name results in error 408 powervsClient.EXPECT().GetVPCs(gomock.Any(), validVPCRegion).Return(validVPCs, nil) 409 410 // Mocks: valid VPC name only, no issues 411 powervsClient.EXPECT().GetVPCs(gomock.Any(), validVPCRegion).Return(validVPCs, nil) 412 413 // Mocks: valid VPC name, invalid VPC region 414 powervsClient.EXPECT().GetVPCs(gomock.Any(), invalidVPCRegion).Return(nil, fmt.Errorf("unknown region")) 415 416 // Mocks: valid VPC name, valid VPC region, all good 417 powervsClient.EXPECT().GetVPCs(gomock.Any(), validVPCRegion).Return(validVPCs, nil) 418 419 // Mocks: subnet specified, without vpcName, invalid 420 // nothing to mock 421 422 // Mocks: valid VPC name, but Subnet not found 423 powervsClient.EXPECT().GetVPCs(gomock.Any(), validVPCRegion).Return(validVPCs, nil) 424 powervsClient.EXPECT().GetSubnetByName(gomock.Any(), invalidVPCSubnet, validVPCRegion).Return(nil, fmt.Errorf("")) 425 426 // Mocks: valid VPC name, but wrong Subnet (present, but not attached) 427 powervsClient.EXPECT().GetVPCs(gomock.Any(), validVPCRegion).Return(validVPCs, nil) 428 powervsClient.EXPECT().GetSubnetByName(gomock.Any(), wrongVPCSubnet, validVPCRegion).Return(wrongSubnet, nil) 429 430 // Mocks: region specified, valid VPC, valid region, valid Subnet, all good 431 powervsClient.EXPECT().GetVPCs(gomock.Any(), validVPCRegion).Return(validVPCs, nil) 432 powervsClient.EXPECT().GetSubnetByName(gomock.Any(), validVPCSubnet, validVPCRegion).Return(validSubnet, nil) 433 434 // Run tests 435 for _, tc := range cases { 436 t.Run(tc.name, func(t *testing.T) { 437 editedInstallConfig := validInstallConfig() 438 for _, edit := range tc.edits { 439 edit(editedInstallConfig) 440 } 441 442 aggregatedErrors := powervs.ValidateCustomVPCSetup(powervsClient, editedInstallConfig) 443 if tc.errorMsg != "" { 444 assert.Regexp(t, tc.errorMsg, aggregatedErrors) 445 } else { 446 assert.NoError(t, aggregatedErrors) 447 } 448 }) 449 } 450 } 451 452 func createControlPlanes(numControlPlanes int, controlPlane *machinev1.PowerVSMachineProviderConfig) []machinev1beta1.Machine { 453 controlPlanes := make([]machinev1beta1.Machine, numControlPlanes) 454 455 for i := range controlPlanes { 456 masterName := fmt.Sprintf("rdr-hamzy-test3-syd04-zwmgs-master-%d", i) 457 controlPlanes[i].TypeMeta = metav1.TypeMeta{ 458 Kind: "Machine", 459 APIVersion: "machine.openshift.io/v1beta1", 460 } 461 controlPlanes[i].ObjectMeta = metav1.ObjectMeta{ 462 Name: masterName, 463 Namespace: "openshift-machine-api", 464 Labels: make(map[string]string), 465 } 466 controlPlanes[i].Labels["machine.openshift.io/cluster-api-cluster"] = "rdr-hamzy-test3-syd04-zwmgs" 467 controlPlanes[i].Labels["machine.openshift.io/cluster-api-machine-role"] = "master" 468 controlPlanes[i].Labels["machine.openshift.io/cluster-api-machine-type"] = "master" 469 470 controlPlanes[i].Spec.ProviderSpec = machinev1beta1.ProviderSpec{ 471 Value: &runtime.RawExtension{ 472 Raw: nil, 473 Object: controlPlane, 474 }, 475 } 476 } 477 478 return controlPlanes 479 } 480 481 func createComputes(numComputes int32, compute *machinev1.PowerVSMachineProviderConfig) []machinev1beta1.MachineSet { 482 computes := make([]machinev1beta1.MachineSet, 1) 483 484 computes[0].Spec.Replicas = &numComputes 485 486 computes[0].Spec.Template.Spec.ProviderSpec = machinev1beta1.ProviderSpec{ 487 Value: &runtime.RawExtension{ 488 Raw: nil, 489 Object: compute, 490 }, 491 } 492 493 return computes 494 } 495 496 func TestValidatePERAvailability(t *testing.T) { 497 cases := []struct { 498 name string 499 edits editFunctions 500 errorMsg string 501 }{ 502 { 503 name: "Region without PER", 504 edits: editFunctions{ 505 func(ic *types.InstallConfig) { 506 ic.Platform.PowerVS.Zone = regionWithoutPER 507 }, 508 }, 509 errorMsg: fmt.Sprintf("power-edge-router is not available at: %s", regionWithoutPER), 510 }, 511 { 512 name: "Region with PER", 513 edits: editFunctions{ 514 func(ic *types.InstallConfig) { 515 ic.Platform.PowerVS.Zone = regionWithPER 516 }, 517 }, 518 errorMsg: "", 519 }, 520 { 521 name: "Region with no PER availability info", 522 edits: editFunctions{ 523 func(ic *types.InstallConfig) { 524 ic.Platform.PowerVS.Zone = regionPERUnknown 525 }, 526 }, 527 errorMsg: fmt.Sprintf("power-edge-router capability unknown at: %s", regionPERUnknown), 528 }, 529 } 530 setMockEnvVars() 531 532 mockCtrl := gomock.NewController(t) 533 defer mockCtrl.Finish() 534 535 powervsClient := mock.NewMockAPI(mockCtrl) 536 537 // Mocks: PER-absent region results in false 538 powervsClient.EXPECT().GetDatacenterCapabilities(gomock.Any(), regionWithoutPER).Return(mapWithPERFalse, nil) 539 540 // Mocks: PER-enabled region results in true 541 powervsClient.EXPECT().GetDatacenterCapabilities(gomock.Any(), regionWithPER).Return(mapWithPERTrue, nil) 542 543 // Mocks: PER-unknown region results in false 544 powervsClient.EXPECT().GetDatacenterCapabilities(gomock.Any(), regionPERUnknown).Return(mapPERUnknown, nil) 545 546 // Run tests 547 for _, tc := range cases { 548 t.Run(tc.name, func(t *testing.T) { 549 editedInstallConfig := validInstallConfig() 550 for _, edit := range tc.edits { 551 edit(editedInstallConfig) 552 } 553 554 aggregatedErrors := powervs.ValidatePERAvailability(powervsClient, editedInstallConfig) 555 if tc.errorMsg != "" { 556 assert.Regexp(t, tc.errorMsg, aggregatedErrors) 557 } else { 558 assert.NoError(t, aggregatedErrors) 559 } 560 }) 561 } 562 } 563 564 func TestValidateSystemTypeForRegion(t *testing.T) { 565 cases := []struct { 566 name string 567 edits editFunctions 568 errorMsg string 569 }{ 570 { 571 name: "Unknown Region specified", 572 edits: editFunctions{ 573 func(ic *types.InstallConfig) { 574 ic.Platform.PowerVS.Region = invalidRegion 575 ic.ControlPlane.Platform.PowerVS = validMachinePool() 576 ic.ControlPlane.Platform.PowerVS.SysType = defaultSysType 577 }, 578 }, 579 errorMsg: fmt.Sprintf("failed to obtain available SysTypes for: %s", invalidRegion), 580 }, 581 { 582 name: "No Platform block", 583 edits: editFunctions{ 584 func(ic *types.InstallConfig) { 585 ic.ControlPlane.Platform.PowerVS = nil 586 }, 587 }, 588 errorMsg: "", 589 }, 590 { 591 name: "Structure present, but no SysType specified", 592 edits: editFunctions{ 593 func(ic *types.InstallConfig) { 594 ic.ControlPlane.Platform.PowerVS = validMachinePool() 595 }, 596 }, 597 errorMsg: "", 598 }, 599 { 600 name: "Unavailable SysType specified for Dallas Region", 601 edits: editFunctions{ 602 func(ic *types.InstallConfig) { 603 ic.Platform.PowerVS.Region = validRegion 604 ic.ControlPlane.Platform.PowerVS = validMachinePool() 605 ic.ControlPlane.Platform.PowerVS.SysType = newSysType 606 }, 607 }, 608 errorMsg: fmt.Sprintf("%s is not available in: %s", newSysType, validRegion), 609 }, 610 { 611 name: "Good Region/SysType combo specified", 612 edits: editFunctions{ 613 func(ic *types.InstallConfig) { 614 ic.Platform.PowerVS.Region = validRegion 615 ic.ControlPlane.Platform.PowerVS = validMachinePool() 616 ic.ControlPlane.Platform.PowerVS.SysType = defaultSysType 617 }, 618 }, 619 errorMsg: "", 620 }, 621 } 622 setMockEnvVars() 623 624 mockCtrl := gomock.NewController(t) 625 defer mockCtrl.Finish() 626 627 powervsClient := mock.NewMockAPI(mockCtrl) 628 629 // Run tests 630 for _, tc := range cases { 631 t.Run(tc.name, func(t *testing.T) { 632 editedInstallConfig := validInstallConfig() 633 for _, edit := range tc.edits { 634 edit(editedInstallConfig) 635 } 636 637 aggregatedErrors := powervs.ValidateSystemTypeForRegion(powervsClient, editedInstallConfig) 638 if tc.errorMsg != "" { 639 assert.Regexp(t, tc.errorMsg, aggregatedErrors) 640 } else { 641 assert.NoError(t, aggregatedErrors) 642 } 643 }) 644 } 645 } 646 647 func TestValidateServiceInstance(t *testing.T) { 648 cases := []struct { 649 name string 650 edits editFunctions 651 errorMsg string 652 }{ 653 { 654 name: "valid install config", 655 edits: editFunctions{}, 656 errorMsg: "", 657 }, 658 { 659 name: "invalid install config", 660 edits: editFunctions{ 661 func(ic *types.InstallConfig) { 662 ic.Platform.PowerVS.ServiceInstanceGUID = "invalid-uuid" 663 }, 664 }, 665 errorMsg: "platform:powervs:serviceInstanceGUID has an invalid guid", 666 }, 667 } 668 setMockEnvVars() 669 670 mockCtrl := gomock.NewController(t) 671 defer mockCtrl.Finish() 672 673 powervsClient := mock.NewMockAPI(mockCtrl) 674 675 // FIX: Unexpected call to *mock.MockAPI.ListServiceInstances([context.TODO.WithDeadline(2023-12-02 08:38:15.542340268 -0600 CST m=+300.012357408 [4m59.999979046s])]) at validation.go:289 because: there are no expected calls of the method "ListServiceInstances" for that receiver 676 powervsClient.EXPECT().ListServiceInstances(gomock.Any()).AnyTimes() 677 678 // Run tests 679 for _, tc := range cases { 680 t.Run(tc.name, func(t *testing.T) { 681 editedInstallConfig := validInstallConfig() 682 for _, edit := range tc.edits { 683 edit(editedInstallConfig) 684 } 685 686 aggregatedErrors := powervs.ValidateServiceInstance(powervsClient, editedInstallConfig) 687 if tc.errorMsg != "" { 688 assert.Regexp(t, tc.errorMsg, aggregatedErrors) 689 } else { 690 assert.NoError(t, aggregatedErrors) 691 } 692 }) 693 } 694 } 695 696 func setMockEnvVars() { 697 os.Setenv("POWERVS_AUTH_FILEPATH", "./tmp/powervs/config.json") 698 os.Setenv("IBMID", "foo") 699 os.Setenv("IC_API_KEY", "foo") 700 os.Setenv("IBMCLOUD_REGION", "foo") 701 os.Setenv("IBMCLOUD_ZONE", "foo") 702 }