sigs.k8s.io/cluster-api@v1.7.1/internal/topology/check/compatibility_test.go (about) 1 /* 2 Copyright 2021 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 check 18 19 import ( 20 "testing" 21 22 . "github.com/onsi/gomega" 23 corev1 "k8s.io/api/core/v1" 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 26 "k8s.io/apimachinery/pkg/util/validation/field" 27 28 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 29 "sigs.k8s.io/cluster-api/internal/test/builder" 30 ) 31 32 type referencedObjectsCompatibilityTestCase struct { 33 name string 34 current *unstructured.Unstructured 35 desired *unstructured.Unstructured 36 wantErr bool 37 } 38 39 var referencedObjectsCompatibilityTestCases = []referencedObjectsCompatibilityTestCase{ 40 { 41 name: "Fails if group changes", 42 current: &unstructured.Unstructured{ 43 Object: map[string]interface{}{ 44 "apiVersion": "foo/v1beta1", 45 }, 46 }, 47 desired: &unstructured.Unstructured{ 48 Object: map[string]interface{}{ 49 "apiVersion": "bar/v1beta1", 50 }, 51 }, 52 wantErr: true, 53 }, 54 { 55 name: "Fails if kind changes", 56 current: &unstructured.Unstructured{ 57 Object: map[string]interface{}{ 58 "kind": "foo", 59 }, 60 }, 61 desired: &unstructured.Unstructured{ 62 Object: map[string]interface{}{ 63 "kind": "bar", 64 }, 65 }, 66 wantErr: true, 67 }, 68 { 69 name: "Pass if gvk remains the same", 70 current: &unstructured.Unstructured{ 71 Object: map[string]interface{}{ 72 "apiVersion": "infrastructure.cluster.x-k8s.io/foo", 73 "kind": "foo", 74 }, 75 }, 76 desired: &unstructured.Unstructured{ 77 Object: map[string]interface{}{ 78 "apiVersion": "infrastructure.cluster.x-k8s.io/foo", 79 "kind": "foo", 80 }, 81 }, 82 wantErr: false, 83 }, 84 { 85 name: "Pass if version changes but group and kind remains the same", 86 current: &unstructured.Unstructured{ 87 Object: map[string]interface{}{ 88 "apiVersion": "infrastructure.cluster.x-k8s.io/foo", 89 "kind": "foo", 90 }, 91 }, 92 desired: &unstructured.Unstructured{ 93 Object: map[string]interface{}{ 94 "apiVersion": "infrastructure.cluster.x-k8s.io/bar", 95 "kind": "foo", 96 }, 97 }, 98 wantErr: false, 99 }, 100 { 101 name: "Fails if namespace changes", 102 current: &unstructured.Unstructured{ 103 Object: map[string]interface{}{ 104 "metadata": map[string]interface{}{ 105 "namespace": "foo", 106 }, 107 }, 108 }, 109 desired: &unstructured.Unstructured{ 110 Object: map[string]interface{}{ 111 "metadata": map[string]interface{}{ 112 "namespace": "bar", 113 }, 114 }, 115 }, 116 wantErr: true, 117 }, 118 } 119 120 func TestObjectsAreCompatible(t *testing.T) { 121 for _, tt := range referencedObjectsCompatibilityTestCases { 122 t.Run(tt.name, func(t *testing.T) { 123 g := NewWithT(t) 124 allErrs := ObjectsAreCompatible(tt.current, tt.desired) 125 if tt.wantErr { 126 g.Expect(allErrs).ToNot(BeEmpty()) 127 return 128 } 129 g.Expect(allErrs).To(BeEmpty()) 130 }) 131 } 132 } 133 134 func TestObjectsAreStrictlyCompatible(t *testing.T) { 135 referencedObjectsStrictCompatibilityTestCases := append(referencedObjectsCompatibilityTestCases, []referencedObjectsCompatibilityTestCase{ 136 { 137 name: "Fails if name changes", 138 current: &unstructured.Unstructured{ 139 Object: map[string]interface{}{ 140 "metadata": map[string]interface{}{ 141 "name": "foo", 142 }, 143 }, 144 }, 145 desired: &unstructured.Unstructured{ 146 Object: map[string]interface{}{ 147 "metadata": map[string]interface{}{ 148 "name": "bar", 149 }, 150 }, 151 }, 152 wantErr: true, 153 }, 154 { 155 name: "Pass if name remains the same", 156 current: &unstructured.Unstructured{ 157 Object: map[string]interface{}{ 158 "metadata": map[string]interface{}{ 159 "name": "foo", 160 }, 161 }, 162 }, 163 desired: &unstructured.Unstructured{ 164 Object: map[string]interface{}{ 165 "metadata": map[string]interface{}{ 166 "name": "foo", 167 }, 168 }, 169 }, 170 wantErr: false, 171 }, 172 }...) 173 174 for _, tt := range referencedObjectsStrictCompatibilityTestCases { 175 t.Run(tt.name, func(t *testing.T) { 176 g := NewWithT(t) 177 178 allErrs := ObjectsAreStrictlyCompatible(tt.current, tt.desired) 179 if tt.wantErr { 180 g.Expect(allErrs).ToNot(BeEmpty()) 181 return 182 } 183 g.Expect(allErrs).To(BeEmpty()) 184 }) 185 } 186 } 187 188 func TestLocalObjectTemplatesAreCompatible(t *testing.T) { 189 template := clusterv1.LocalObjectTemplate{ 190 Ref: &corev1.ObjectReference{ 191 Namespace: "default", 192 Name: "foo", 193 Kind: "bar", 194 APIVersion: "test.group.io/versionone", 195 }, 196 } 197 compatibleNameChangeTemplate := clusterv1.LocalObjectTemplate{ 198 Ref: &corev1.ObjectReference{ 199 Namespace: "default", 200 Name: "newFoo", 201 Kind: "bar", 202 APIVersion: "test.group.io/versionone", 203 }, 204 } 205 compatibleAPIVersionChangeTemplate := clusterv1.LocalObjectTemplate{ 206 Ref: &corev1.ObjectReference{ 207 Namespace: "default", 208 Name: "foo", 209 Kind: "bar", 210 APIVersion: "test.group.io/versiontwo", 211 }, 212 } 213 incompatibleNamespaceChangeTemplate := clusterv1.LocalObjectTemplate{ 214 Ref: &corev1.ObjectReference{ 215 Namespace: "different", 216 Name: "foo", 217 Kind: "bar", 218 APIVersion: "test.group.io/versionone", 219 }, 220 } 221 incompatibleAPIGroupChangeTemplate := clusterv1.LocalObjectTemplate{ 222 Ref: &corev1.ObjectReference{ 223 Namespace: "default", 224 Name: "foo", 225 Kind: "bar", 226 APIVersion: "production.group.io/versionone", 227 }, 228 } 229 incompatibleAPIKindChangeTemplate := clusterv1.LocalObjectTemplate{ 230 Ref: &corev1.ObjectReference{ 231 Namespace: "default", 232 Name: "foo", 233 Kind: "notabar", 234 APIVersion: "test.group.io/versionone", 235 }, 236 } 237 tests := []struct { 238 name string 239 current clusterv1.LocalObjectTemplate 240 desired clusterv1.LocalObjectTemplate 241 wantErr bool 242 }{ 243 { 244 name: "Allow change to template name", 245 current: template, 246 desired: compatibleNameChangeTemplate, 247 wantErr: false, 248 }, 249 { 250 name: "Allow change to template APIVersion", 251 current: template, 252 desired: compatibleAPIVersionChangeTemplate, 253 wantErr: false, 254 }, 255 { 256 name: "Block change to template API Group", 257 current: template, 258 desired: incompatibleAPIGroupChangeTemplate, 259 wantErr: true, 260 }, 261 { 262 name: "Block change to template namespace", 263 current: template, 264 desired: incompatibleNamespaceChangeTemplate, 265 wantErr: true, 266 }, 267 { 268 name: "Block change to template API Kind", 269 current: template, 270 desired: incompatibleAPIKindChangeTemplate, 271 wantErr: true, 272 }, 273 } 274 for _, tt := range tests { 275 t.Run(tt.name, func(t *testing.T) { 276 g := NewWithT(t) 277 allErrs := LocalObjectTemplatesAreCompatible(tt.current, tt.desired, field.NewPath("spec")) 278 if tt.wantErr { 279 g.Expect(allErrs).ToNot(BeEmpty()) 280 return 281 } 282 g.Expect(allErrs).To(BeEmpty()) 283 }) 284 } 285 } 286 287 func TestLocalObjectTemplateIsValid(t *testing.T) { 288 namespace := metav1.NamespaceDefault 289 pathPrefix := field.NewPath("this", "is", "a", "prefix") 290 291 validTemplate := &clusterv1.LocalObjectTemplate{ 292 Ref: &corev1.ObjectReference{ 293 Namespace: "default", 294 Name: "valid", 295 Kind: "barTemplate", 296 APIVersion: "test.group.io/versionone", 297 }, 298 } 299 300 nilTemplate := &clusterv1.LocalObjectTemplate{ 301 Ref: nil, 302 } 303 emptyNameTemplate := &clusterv1.LocalObjectTemplate{ 304 Ref: &corev1.ObjectReference{ 305 Namespace: "default", 306 Name: "", 307 Kind: "barTemplate", 308 APIVersion: "test.group.io/versionone", 309 }, 310 } 311 wrongNamespaceTemplate := &clusterv1.LocalObjectTemplate{ 312 Ref: &corev1.ObjectReference{ 313 Namespace: "wrongNamespace", 314 Name: "foo", 315 Kind: "barTemplate", 316 APIVersion: "test.group.io/versiontwo", 317 }, 318 } 319 notTemplateKindTemplate := &clusterv1.LocalObjectTemplate{ 320 Ref: &corev1.ObjectReference{ 321 Namespace: "default", 322 Name: "foo", 323 Kind: "bar", 324 APIVersion: "test.group.io/versionone", 325 }, 326 } 327 invalidAPIVersionTemplate := &clusterv1.LocalObjectTemplate{ 328 Ref: &corev1.ObjectReference{ 329 Namespace: "default", 330 Name: "foo", 331 Kind: "barTemplate", 332 APIVersion: "this/has/too/many/slashes", 333 }, 334 } 335 emptyAPIVersionTemplate := &clusterv1.LocalObjectTemplate{ 336 Ref: &corev1.ObjectReference{ 337 Namespace: "default", 338 Name: "foo", 339 Kind: "barTemplate", 340 APIVersion: "", 341 }, 342 } 343 344 tests := []struct { 345 template *clusterv1.LocalObjectTemplate 346 name string 347 wantErr bool 348 }{ 349 { 350 name: "No error with valid Template", 351 template: validTemplate, 352 wantErr: false, 353 }, 354 355 { 356 name: "Invalid if ref is nil", 357 template: nilTemplate, 358 wantErr: true, 359 }, 360 { 361 name: "Invalid if name is empty", 362 template: emptyNameTemplate, 363 wantErr: true, 364 }, 365 { 366 name: "Invalid if namespace doesn't match", 367 template: wrongNamespaceTemplate, 368 wantErr: true, 369 }, 370 { 371 name: "Invalid if Kind doesn't have Template suffix", 372 template: notTemplateKindTemplate, 373 wantErr: true, 374 }, 375 { 376 name: "Invalid if apiVersion is not valid", 377 template: invalidAPIVersionTemplate, 378 wantErr: true, 379 }, 380 { 381 name: "Empty apiVersion is not valid", 382 template: emptyAPIVersionTemplate, 383 wantErr: true, 384 }, 385 } 386 for _, tt := range tests { 387 t.Run(tt.name, func(t *testing.T) { 388 g := NewWithT(t) 389 allErrs := LocalObjectTemplateIsValid(tt.template, namespace, pathPrefix) 390 if tt.wantErr { 391 g.Expect(allErrs).ToNot(BeEmpty()) 392 return 393 } 394 g.Expect(allErrs).To(BeEmpty()) 395 }) 396 } 397 } 398 399 func TestClusterClassesAreCompatible(t *testing.T) { 400 ref := &corev1.ObjectReference{ 401 APIVersion: "group.test.io/foo", 402 Kind: "barTemplate", 403 Name: "baz", 404 Namespace: "default", 405 } 406 incompatibleRef := &corev1.ObjectReference{ 407 APIVersion: "group.test.io/foo", 408 Kind: "another-barTemplate", 409 Name: "baz", 410 Namespace: "default", 411 } 412 compatibleRef := &corev1.ObjectReference{ 413 APIVersion: "group.test.io/another-foo", 414 Kind: "barTemplate", 415 Name: "another-baz", 416 Namespace: "default", 417 } 418 419 tests := []struct { 420 name string 421 current *clusterv1.ClusterClass 422 desired *clusterv1.ClusterClass 423 wantErr bool 424 }{ 425 { 426 name: "error if current is nil", 427 current: nil, 428 desired: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 429 WithInfrastructureClusterTemplate( 430 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 431 WithControlPlaneTemplate( 432 refToUnstructured(ref)). 433 WithControlPlaneInfrastructureMachineTemplate( 434 refToUnstructured(ref)). 435 Build(), 436 wantErr: true, 437 }, 438 { 439 name: "error if desired is nil", 440 current: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 441 WithInfrastructureClusterTemplate( 442 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 443 WithControlPlaneTemplate( 444 refToUnstructured(ref)). 445 WithControlPlaneInfrastructureMachineTemplate( 446 refToUnstructured(ref)). 447 Build(), 448 desired: nil, 449 wantErr: true, 450 }, 451 452 { 453 name: "pass for compatible clusterClasses", 454 current: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 455 WithInfrastructureClusterTemplate( 456 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 457 WithControlPlaneTemplate( 458 refToUnstructured(ref)). 459 WithControlPlaneInfrastructureMachineTemplate( 460 refToUnstructured(ref)). 461 WithWorkerMachineDeploymentClasses( 462 *builder.MachineDeploymentClass("aa"). 463 WithInfrastructureTemplate( 464 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 465 WithBootstrapTemplate( 466 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 467 Build()). 468 WithWorkerMachinePoolClasses( 469 *builder.MachinePoolClass("bb"). 470 WithInfrastructureTemplate( 471 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 472 WithBootstrapTemplate( 473 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 474 Build()). 475 Build(), 476 desired: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 477 WithInfrastructureClusterTemplate( 478 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 479 WithControlPlaneTemplate( 480 refToUnstructured(compatibleRef)). 481 WithControlPlaneInfrastructureMachineTemplate( 482 refToUnstructured(compatibleRef)). 483 WithWorkerMachineDeploymentClasses( 484 *builder.MachineDeploymentClass("aa"). 485 WithInfrastructureTemplate( 486 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 487 WithBootstrapTemplate( 488 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 489 Build()). 490 WithWorkerMachinePoolClasses( 491 *builder.MachinePoolClass("bb"). 492 WithInfrastructureTemplate( 493 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 494 WithBootstrapTemplate( 495 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 496 Build()). 497 Build(), 498 wantErr: false, 499 }, 500 { 501 name: "error if clusterClass has incompatible ControlPlane ref", 502 current: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 503 WithInfrastructureClusterTemplate( 504 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 505 WithControlPlaneTemplate( 506 refToUnstructured(ref)). 507 WithControlPlaneInfrastructureMachineTemplate( 508 refToUnstructured(ref)). 509 WithWorkerMachineDeploymentClasses( 510 *builder.MachineDeploymentClass("aa"). 511 WithInfrastructureTemplate( 512 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 513 WithBootstrapTemplate( 514 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 515 Build()). 516 WithWorkerMachinePoolClasses( 517 *builder.MachinePoolClass("bb"). 518 WithInfrastructureTemplate( 519 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 520 WithBootstrapTemplate( 521 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 522 Build()). 523 Build(), 524 desired: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 525 WithInfrastructureClusterTemplate( 526 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 527 WithControlPlaneTemplate( 528 refToUnstructured(incompatibleRef)). 529 WithControlPlaneInfrastructureMachineTemplate( 530 refToUnstructured(ref)). 531 WithWorkerMachineDeploymentClasses( 532 *builder.MachineDeploymentClass("aa"). 533 WithInfrastructureTemplate( 534 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 535 WithBootstrapTemplate( 536 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 537 Build()). 538 WithWorkerMachinePoolClasses( 539 *builder.MachinePoolClass("bb"). 540 WithInfrastructureTemplate( 541 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 542 WithBootstrapTemplate( 543 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 544 Build()). 545 Build(), 546 wantErr: true, 547 }, 548 { 549 name: "pass for incompatible ref in MachineDeploymentClass bootstrapTemplate clusterClasses", 550 current: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 551 WithInfrastructureClusterTemplate( 552 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 553 WithControlPlaneTemplate( 554 refToUnstructured(ref)). 555 WithControlPlaneInfrastructureMachineTemplate( 556 refToUnstructured(ref)). 557 WithWorkerMachineDeploymentClasses( 558 *builder.MachineDeploymentClass("aa"). 559 WithInfrastructureTemplate( 560 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 561 WithBootstrapTemplate( 562 refToUnstructured(ref)).Build()). 563 Build(), 564 desired: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 565 WithInfrastructureClusterTemplate( 566 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 567 WithControlPlaneTemplate( 568 refToUnstructured(ref)). 569 WithControlPlaneInfrastructureMachineTemplate( 570 refToUnstructured(ref)). 571 WithWorkerMachineDeploymentClasses( 572 *builder.MachineDeploymentClass("aa"). 573 WithInfrastructureTemplate( 574 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 575 WithBootstrapTemplate( 576 refToUnstructured(incompatibleRef)).Build()). 577 Build(), 578 wantErr: false, 579 }, 580 { 581 name: "pass for incompatible ref in MachinePoolClass bootstrapTemplate clusterClasses", 582 current: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 583 WithInfrastructureClusterTemplate( 584 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 585 WithControlPlaneTemplate( 586 refToUnstructured(ref)). 587 WithControlPlaneInfrastructureMachineTemplate( 588 refToUnstructured(ref)). 589 WithWorkerMachinePoolClasses( 590 *builder.MachinePoolClass("aa"). 591 WithInfrastructureTemplate( 592 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 593 WithBootstrapTemplate( 594 refToUnstructured(ref)).Build()). 595 Build(), 596 desired: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 597 WithInfrastructureClusterTemplate( 598 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 599 WithControlPlaneTemplate( 600 refToUnstructured(ref)). 601 WithControlPlaneInfrastructureMachineTemplate( 602 refToUnstructured(ref)). 603 WithWorkerMachinePoolClasses( 604 *builder.MachinePoolClass("aa"). 605 WithInfrastructureTemplate( 606 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 607 WithBootstrapTemplate( 608 refToUnstructured(incompatibleRef)).Build()). 609 Build(), 610 wantErr: false, 611 }, 612 { 613 name: "pass if machineDeploymentClass is removed from ClusterClass", 614 current: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 615 WithInfrastructureClusterTemplate( 616 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 617 WithControlPlaneTemplate( 618 refToUnstructured(ref)). 619 WithControlPlaneInfrastructureMachineTemplate( 620 refToUnstructured(ref)). 621 WithWorkerMachineDeploymentClasses( 622 *builder.MachineDeploymentClass("aa"). 623 WithInfrastructureTemplate( 624 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 625 WithBootstrapTemplate( 626 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 627 Build(), 628 *builder.MachineDeploymentClass("bb"). 629 WithInfrastructureTemplate( 630 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 631 WithBootstrapTemplate( 632 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 633 Build()). 634 Build(), 635 desired: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 636 WithInfrastructureClusterTemplate( 637 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 638 WithControlPlaneTemplate( 639 refToUnstructured(ref)). 640 WithControlPlaneInfrastructureMachineTemplate( 641 refToUnstructured(ref)). 642 WithWorkerMachineDeploymentClasses( 643 *builder.MachineDeploymentClass("aa"). 644 WithInfrastructureTemplate( 645 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 646 WithBootstrapTemplate( 647 refToUnstructured(incompatibleRef)).Build()). 648 Build(), 649 wantErr: false, 650 }, 651 { 652 name: "pass if machinePoolClass is removed from ClusterClass", 653 current: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 654 WithInfrastructureClusterTemplate( 655 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 656 WithControlPlaneTemplate( 657 refToUnstructured(ref)). 658 WithControlPlaneInfrastructureMachineTemplate( 659 refToUnstructured(ref)). 660 WithWorkerMachinePoolClasses( 661 *builder.MachinePoolClass("aa"). 662 WithInfrastructureTemplate( 663 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 664 WithBootstrapTemplate( 665 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 666 Build(), 667 *builder.MachinePoolClass("bb"). 668 WithInfrastructureTemplate( 669 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 670 WithBootstrapTemplate( 671 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 672 Build()). 673 Build(), 674 desired: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 675 WithInfrastructureClusterTemplate( 676 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 677 WithControlPlaneTemplate( 678 refToUnstructured(ref)). 679 WithControlPlaneInfrastructureMachineTemplate( 680 refToUnstructured(ref)). 681 WithWorkerMachinePoolClasses( 682 *builder.MachinePoolClass("aa"). 683 WithInfrastructureTemplate( 684 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 685 WithBootstrapTemplate( 686 refToUnstructured(incompatibleRef)).Build()). 687 Build(), 688 wantErr: false, 689 }, 690 } 691 for _, tt := range tests { 692 g := NewWithT(t) 693 t.Run(tt.name, func(*testing.T) { 694 allErrs := ClusterClassesAreCompatible(tt.current, tt.desired) 695 if tt.wantErr { 696 g.Expect(allErrs).ToNot(BeEmpty()) 697 return 698 } 699 g.Expect(allErrs).To(BeEmpty()) 700 }) 701 } 702 } 703 704 func TestMachineDeploymentClassesAreCompatible(t *testing.T) { 705 ref := &corev1.ObjectReference{ 706 APIVersion: "group.test.io/foo", 707 Kind: "barTemplate", 708 Name: "baz", 709 Namespace: "default", 710 } 711 compatibleRef := &corev1.ObjectReference{ 712 APIVersion: "group.test.io/another-foo", 713 Kind: "barTemplate", 714 Name: "another-baz", 715 Namespace: "default", 716 } 717 incompatibleRef := &corev1.ObjectReference{ 718 APIVersion: "group.test.io/foo", 719 Kind: "another-barTemplate", 720 Name: "baz", 721 Namespace: "default", 722 } 723 724 tests := []struct { 725 name string 726 current *clusterv1.ClusterClass 727 desired *clusterv1.ClusterClass 728 wantErr bool 729 }{ 730 { 731 name: "pass if machineDeploymentClasses are compatible", 732 current: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 733 WithInfrastructureClusterTemplate( 734 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 735 WithControlPlaneTemplate( 736 refToUnstructured(ref)). 737 WithControlPlaneInfrastructureMachineTemplate( 738 refToUnstructured(ref)). 739 WithWorkerMachineDeploymentClasses( 740 *builder.MachineDeploymentClass("aa"). 741 WithInfrastructureTemplate( 742 refToUnstructured(ref)). 743 WithBootstrapTemplate( 744 refToUnstructured(ref)). 745 Build()). 746 Build(), 747 desired: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 748 WithInfrastructureClusterTemplate( 749 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 750 WithControlPlaneTemplate( 751 refToUnstructured(ref)). 752 WithControlPlaneInfrastructureMachineTemplate( 753 refToUnstructured(ref)). 754 WithWorkerMachineDeploymentClasses( 755 *builder.MachineDeploymentClass("aa"). 756 WithInfrastructureTemplate( 757 refToUnstructured(compatibleRef)). 758 WithBootstrapTemplate( 759 refToUnstructured(incompatibleRef)).Build()). 760 Build(), 761 wantErr: false, 762 }, 763 { 764 name: "pass if machineDeploymentClass is removed from ClusterClass", 765 current: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 766 WithInfrastructureClusterTemplate( 767 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 768 WithControlPlaneTemplate( 769 refToUnstructured(ref)). 770 WithControlPlaneInfrastructureMachineTemplate( 771 refToUnstructured(ref)). 772 WithWorkerMachineDeploymentClasses( 773 *builder.MachineDeploymentClass("aa"). 774 WithInfrastructureTemplate( 775 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 776 WithBootstrapTemplate( 777 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 778 Build(), 779 *builder.MachineDeploymentClass("bb"). 780 WithInfrastructureTemplate( 781 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 782 WithBootstrapTemplate( 783 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 784 Build()). 785 Build(), 786 desired: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 787 WithInfrastructureClusterTemplate( 788 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 789 WithControlPlaneTemplate( 790 refToUnstructured(ref)). 791 WithControlPlaneInfrastructureMachineTemplate( 792 refToUnstructured(ref)). 793 WithWorkerMachineDeploymentClasses( 794 *builder.MachineDeploymentClass("aa"). 795 WithInfrastructureTemplate( 796 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 797 WithBootstrapTemplate( 798 refToUnstructured(incompatibleRef)).Build()). 799 Build(), 800 wantErr: false, 801 }, 802 { 803 name: "error if machineDeploymentClass has multiple incompatible references", 804 current: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 805 WithInfrastructureClusterTemplate( 806 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 807 WithControlPlaneTemplate( 808 refToUnstructured(ref)). 809 WithControlPlaneInfrastructureMachineTemplate( 810 refToUnstructured(ref)). 811 WithWorkerMachineDeploymentClasses( 812 *builder.MachineDeploymentClass("aa"). 813 WithInfrastructureTemplate( 814 refToUnstructured(ref)). 815 WithBootstrapTemplate( 816 refToUnstructured(ref)). 817 Build(), 818 ). 819 Build(), 820 desired: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 821 WithInfrastructureClusterTemplate( 822 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 823 WithControlPlaneTemplate( 824 refToUnstructured(incompatibleRef)). 825 WithControlPlaneInfrastructureMachineTemplate( 826 refToUnstructured(incompatibleRef)). 827 WithWorkerMachineDeploymentClasses( 828 *builder.MachineDeploymentClass("aa"). 829 WithInfrastructureTemplate( 830 refToUnstructured(incompatibleRef)). 831 WithBootstrapTemplate( 832 refToUnstructured(compatibleRef)).Build()). 833 Build(), 834 wantErr: true, 835 }, 836 } 837 for _, tt := range tests { 838 t.Run(tt.name, func(t *testing.T) { 839 g := NewWithT(t) 840 allErrs := MachineDeploymentClassesAreCompatible(tt.current, tt.desired) 841 if tt.wantErr { 842 g.Expect(allErrs).ToNot(BeEmpty()) 843 return 844 } 845 g.Expect(allErrs).To(BeEmpty()) 846 }) 847 } 848 } 849 850 func TestMachinePoolClassesAreCompatible(t *testing.T) { 851 ref := &corev1.ObjectReference{ 852 APIVersion: "group.test.io/foo", 853 Kind: "barTemplate", 854 Name: "baz", 855 Namespace: "default", 856 } 857 compatibleRef := &corev1.ObjectReference{ 858 APIVersion: "group.test.io/another-foo", 859 Kind: "barTemplate", 860 Name: "another-baz", 861 Namespace: "default", 862 } 863 incompatibleRef := &corev1.ObjectReference{ 864 APIVersion: "group.test.io/foo", 865 Kind: "another-barTemplate", 866 Name: "baz", 867 Namespace: "default", 868 } 869 870 tests := []struct { 871 name string 872 current *clusterv1.ClusterClass 873 desired *clusterv1.ClusterClass 874 wantErr bool 875 }{ 876 { 877 name: "pass if MachinePoolClasses are compatible", 878 current: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 879 WithInfrastructureClusterTemplate( 880 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 881 WithControlPlaneTemplate( 882 refToUnstructured(ref)). 883 WithControlPlaneInfrastructureMachineTemplate( 884 refToUnstructured(ref)). 885 WithWorkerMachinePoolClasses( 886 *builder.MachinePoolClass("aa"). 887 WithInfrastructureTemplate( 888 refToUnstructured(ref)). 889 WithBootstrapTemplate( 890 refToUnstructured(ref)). 891 Build()). 892 Build(), 893 desired: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 894 WithInfrastructureClusterTemplate( 895 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 896 WithControlPlaneTemplate( 897 refToUnstructured(ref)). 898 WithControlPlaneInfrastructureMachineTemplate( 899 refToUnstructured(ref)). 900 WithWorkerMachinePoolClasses( 901 *builder.MachinePoolClass("aa"). 902 WithInfrastructureTemplate( 903 refToUnstructured(compatibleRef)). 904 WithBootstrapTemplate( 905 refToUnstructured(incompatibleRef)).Build()). 906 Build(), 907 wantErr: false, 908 }, 909 { 910 name: "pass if MachinePoolClass is removed from ClusterClass", 911 current: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 912 WithInfrastructureClusterTemplate( 913 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 914 WithControlPlaneTemplate( 915 refToUnstructured(ref)). 916 WithControlPlaneInfrastructureMachineTemplate( 917 refToUnstructured(ref)). 918 WithWorkerMachinePoolClasses( 919 *builder.MachinePoolClass("aa"). 920 WithInfrastructureTemplate( 921 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 922 WithBootstrapTemplate( 923 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 924 Build(), 925 *builder.MachinePoolClass("bb"). 926 WithInfrastructureTemplate( 927 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 928 WithBootstrapTemplate( 929 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 930 Build()). 931 Build(), 932 desired: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 933 WithInfrastructureClusterTemplate( 934 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 935 WithControlPlaneTemplate( 936 refToUnstructured(ref)). 937 WithControlPlaneInfrastructureMachineTemplate( 938 refToUnstructured(ref)). 939 WithWorkerMachinePoolClasses( 940 *builder.MachinePoolClass("aa"). 941 WithInfrastructureTemplate( 942 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 943 WithBootstrapTemplate( 944 refToUnstructured(incompatibleRef)).Build()). 945 Build(), 946 wantErr: false, 947 }, 948 { 949 name: "error if MachinePoolClass has multiple incompatible references", 950 current: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 951 WithInfrastructureClusterTemplate( 952 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 953 WithControlPlaneTemplate( 954 refToUnstructured(ref)). 955 WithControlPlaneInfrastructureMachineTemplate( 956 refToUnstructured(ref)). 957 WithWorkerMachinePoolClasses( 958 *builder.MachinePoolClass("aa"). 959 WithInfrastructureTemplate( 960 refToUnstructured(ref)). 961 WithBootstrapTemplate( 962 refToUnstructured(ref)). 963 Build(), 964 ). 965 Build(), 966 desired: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 967 WithInfrastructureClusterTemplate( 968 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 969 WithControlPlaneTemplate( 970 refToUnstructured(incompatibleRef)). 971 WithControlPlaneInfrastructureMachineTemplate( 972 refToUnstructured(incompatibleRef)). 973 WithWorkerMachinePoolClasses( 974 *builder.MachinePoolClass("aa"). 975 WithInfrastructureTemplate( 976 refToUnstructured(incompatibleRef)). 977 WithBootstrapTemplate( 978 refToUnstructured(compatibleRef)).Build()). 979 Build(), 980 wantErr: true, 981 }, 982 } 983 for _, tt := range tests { 984 t.Run(tt.name, func(t *testing.T) { 985 g := NewWithT(t) 986 allErrs := MachinePoolClassesAreCompatible(tt.current, tt.desired) 987 if tt.wantErr { 988 g.Expect(allErrs).ToNot(BeEmpty()) 989 return 990 } 991 g.Expect(allErrs).To(BeEmpty()) 992 }) 993 } 994 } 995 996 func TestMachineDeploymentClassesAreUnique(t *testing.T) { 997 tests := []struct { 998 name string 999 clusterClass *clusterv1.ClusterClass 1000 wantErr bool 1001 }{ 1002 { 1003 name: "pass if MachineDeploymentClasses are unique", 1004 clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1005 WithInfrastructureClusterTemplate( 1006 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1007 WithControlPlaneTemplate( 1008 builder.ControlPlane(metav1.NamespaceDefault, "cp1").Build()). 1009 WithControlPlaneInfrastructureMachineTemplate( 1010 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpinfra1").Build()). 1011 WithWorkerMachineDeploymentClasses( 1012 *builder.MachineDeploymentClass("aa"). 1013 WithInfrastructureTemplate( 1014 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1015 WithBootstrapTemplate( 1016 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1017 Build(), 1018 *builder.MachineDeploymentClass("bb"). 1019 WithInfrastructureTemplate( 1020 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1021 WithBootstrapTemplate( 1022 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1023 Build()). 1024 Build(), 1025 wantErr: false, 1026 }, 1027 { 1028 name: "fail if MachineDeploymentClasses are duplicated", 1029 clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1030 WithInfrastructureClusterTemplate( 1031 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1032 WithControlPlaneTemplate( 1033 builder.ControlPlane(metav1.NamespaceDefault, "cp1").Build()). 1034 WithControlPlaneInfrastructureMachineTemplate( 1035 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpinfra1").Build()). 1036 WithWorkerMachineDeploymentClasses( 1037 *builder.MachineDeploymentClass("aa"). 1038 WithInfrastructureTemplate( 1039 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1040 WithBootstrapTemplate( 1041 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1042 Build(), 1043 *builder.MachineDeploymentClass("aa"). 1044 WithInfrastructureTemplate( 1045 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1046 WithBootstrapTemplate( 1047 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1048 Build()). 1049 Build(), 1050 wantErr: true, 1051 }, 1052 { 1053 name: "fail if multiple MachineDeploymentClasses are identical", 1054 clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1055 WithInfrastructureClusterTemplate( 1056 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1057 WithControlPlaneTemplate( 1058 builder.ControlPlane(metav1.NamespaceDefault, "cp1").Build()). 1059 WithControlPlaneInfrastructureMachineTemplate( 1060 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpinfra1").Build()). 1061 WithWorkerMachineDeploymentClasses( 1062 *builder.MachineDeploymentClass("aa"). 1063 WithInfrastructureTemplate( 1064 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1065 WithBootstrapTemplate( 1066 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1067 Build(), 1068 *builder.MachineDeploymentClass("aa"). 1069 WithInfrastructureTemplate( 1070 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1071 WithBootstrapTemplate( 1072 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1073 Build(), 1074 *builder.MachineDeploymentClass("aa"). 1075 WithInfrastructureTemplate( 1076 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1077 WithBootstrapTemplate( 1078 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1079 Build(), 1080 *builder.MachineDeploymentClass("aa"). 1081 WithInfrastructureTemplate( 1082 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1083 WithBootstrapTemplate( 1084 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1085 Build(), 1086 ). 1087 Build(), 1088 wantErr: true, 1089 }, 1090 } 1091 for _, tt := range tests { 1092 t.Run(tt.name, func(t *testing.T) { 1093 g := NewWithT(t) 1094 allErrs := MachineDeploymentClassesAreUnique(tt.clusterClass) 1095 if tt.wantErr { 1096 g.Expect(allErrs).ToNot(BeEmpty()) 1097 return 1098 } 1099 g.Expect(allErrs).To(BeEmpty()) 1100 }) 1101 } 1102 } 1103 1104 func TestMachinePoolClassesAreUnique(t *testing.T) { 1105 tests := []struct { 1106 name string 1107 clusterClass *clusterv1.ClusterClass 1108 wantErr bool 1109 }{ 1110 { 1111 name: "pass if MachinePoolClasses are unique", 1112 clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1113 WithInfrastructureClusterTemplate( 1114 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1115 WithControlPlaneTemplate( 1116 builder.ControlPlane(metav1.NamespaceDefault, "cp1").Build()). 1117 WithControlPlaneInfrastructureMachineTemplate( 1118 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "cpinfra1").Build()). 1119 WithWorkerMachinePoolClasses( 1120 *builder.MachinePoolClass("aa"). 1121 WithInfrastructureTemplate( 1122 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 1123 WithBootstrapTemplate( 1124 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1125 Build(), 1126 *builder.MachinePoolClass("bb"). 1127 WithInfrastructureTemplate( 1128 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 1129 WithBootstrapTemplate( 1130 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1131 Build()). 1132 Build(), 1133 wantErr: false, 1134 }, 1135 { 1136 name: "fail if MachinePoolClasses are duplicated", 1137 clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1138 WithInfrastructureClusterTemplate( 1139 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1140 WithControlPlaneTemplate( 1141 builder.ControlPlane(metav1.NamespaceDefault, "cp1").Build()). 1142 WithControlPlaneInfrastructureMachineTemplate( 1143 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "cpinfra1").Build()). 1144 WithWorkerMachinePoolClasses( 1145 *builder.MachinePoolClass("aa"). 1146 WithInfrastructureTemplate( 1147 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 1148 WithBootstrapTemplate( 1149 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1150 Build(), 1151 *builder.MachinePoolClass("aa"). 1152 WithInfrastructureTemplate( 1153 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 1154 WithBootstrapTemplate( 1155 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1156 Build()). 1157 Build(), 1158 wantErr: true, 1159 }, 1160 { 1161 name: "fail if multiple MachinePoolClasses are identical", 1162 clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1163 WithInfrastructureClusterTemplate( 1164 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1165 WithControlPlaneTemplate( 1166 builder.ControlPlane(metav1.NamespaceDefault, "cp1").Build()). 1167 WithControlPlaneInfrastructureMachineTemplate( 1168 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "cpinfra1").Build()). 1169 WithWorkerMachinePoolClasses( 1170 *builder.MachinePoolClass("aa"). 1171 WithInfrastructureTemplate( 1172 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 1173 WithBootstrapTemplate( 1174 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1175 Build(), 1176 *builder.MachinePoolClass("aa"). 1177 WithInfrastructureTemplate( 1178 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 1179 WithBootstrapTemplate( 1180 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1181 Build(), 1182 *builder.MachinePoolClass("aa"). 1183 WithInfrastructureTemplate( 1184 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 1185 WithBootstrapTemplate( 1186 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1187 Build(), 1188 *builder.MachinePoolClass("aa"). 1189 WithInfrastructureTemplate( 1190 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 1191 WithBootstrapTemplate( 1192 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1193 Build(), 1194 ). 1195 Build(), 1196 wantErr: true, 1197 }, 1198 } 1199 for _, tt := range tests { 1200 t.Run(tt.name, func(t *testing.T) { 1201 g := NewWithT(t) 1202 allErrs := MachinePoolClassesAreUnique(tt.clusterClass) 1203 if tt.wantErr { 1204 g.Expect(allErrs).ToNot(BeEmpty()) 1205 return 1206 } 1207 g.Expect(allErrs).To(BeEmpty()) 1208 }) 1209 } 1210 } 1211 1212 func TestMachineDeploymentTopologiesAreUniqueAndDefinedInClusterClass(t *testing.T) { 1213 tests := []struct { 1214 name string 1215 clusterClass *clusterv1.ClusterClass 1216 cluster *clusterv1.Cluster 1217 wantErr bool 1218 }{ 1219 { 1220 name: "fail if MachineDeploymentTopologies name is empty", 1221 clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1222 WithInfrastructureClusterTemplate( 1223 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1224 WithControlPlaneTemplate( 1225 builder.ControlPlane(metav1.NamespaceDefault, "cp1").Build()). 1226 WithWorkerMachineDeploymentClasses( 1227 *builder.MachineDeploymentClass("aa"). 1228 WithInfrastructureTemplate( 1229 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1230 WithBootstrapTemplate( 1231 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1232 Build()). 1233 Build(), 1234 cluster: builder.Cluster("fooboo", "cluster1"). 1235 WithTopology(builder.ClusterTopology(). 1236 WithClass("foo"). 1237 WithVersion("v1.19.1"). 1238 WithMachineDeployment( 1239 // The name should not be empty. 1240 builder.MachineDeploymentTopology(""). 1241 WithClass("aa"). 1242 Build()). 1243 Build()). 1244 Build(), 1245 wantErr: true, 1246 }, 1247 { 1248 name: "pass if MachineDeploymentTopologies are unique and defined in ClusterClass", 1249 clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1250 WithInfrastructureClusterTemplate( 1251 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1252 WithControlPlaneTemplate( 1253 builder.ControlPlane(metav1.NamespaceDefault, "cp1").Build()). 1254 WithControlPlaneInfrastructureMachineTemplate( 1255 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpinfra1").Build()). 1256 WithWorkerMachineDeploymentClasses( 1257 *builder.MachineDeploymentClass("aa"). 1258 WithInfrastructureTemplate( 1259 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1260 WithBootstrapTemplate( 1261 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1262 Build()). 1263 Build(), 1264 cluster: builder.Cluster(metav1.NamespaceDefault, "cluster1"). 1265 WithTopology( 1266 builder.ClusterTopology(). 1267 WithClass("class1"). 1268 WithVersion("v1.22.2"). 1269 WithMachineDeployment( 1270 builder.MachineDeploymentTopology("workers1"). 1271 WithClass("aa"). 1272 Build()). 1273 Build()). 1274 Build(), 1275 wantErr: false, 1276 }, 1277 { 1278 name: "fail if MachineDeploymentTopologies are unique but not defined in ClusterClass", 1279 clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1280 WithInfrastructureClusterTemplate( 1281 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1282 WithControlPlaneTemplate( 1283 builder.ControlPlane(metav1.NamespaceDefault, "cp1").Build()). 1284 WithControlPlaneInfrastructureMachineTemplate( 1285 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpinfra1").Build()). 1286 WithWorkerMachineDeploymentClasses( 1287 *builder.MachineDeploymentClass("aa"). 1288 WithInfrastructureTemplate( 1289 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1290 WithBootstrapTemplate( 1291 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1292 Build()). 1293 Build(), 1294 cluster: builder.Cluster(metav1.NamespaceDefault, "cluster1"). 1295 WithTopology( 1296 builder.ClusterTopology(). 1297 WithClass("class1"). 1298 WithVersion("v1.22.2"). 1299 WithMachineDeployment( 1300 builder.MachineDeploymentTopology("workers1"). 1301 WithClass("bb"). 1302 Build()). 1303 Build()). 1304 Build(), 1305 wantErr: true, 1306 }, 1307 { 1308 name: "fail if MachineDeploymentTopologies are not unique but is defined in ClusterClass", 1309 clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1310 WithInfrastructureClusterTemplate( 1311 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1312 WithControlPlaneTemplate( 1313 builder.ControlPlane(metav1.NamespaceDefault, "cp1").Build()). 1314 WithControlPlaneInfrastructureMachineTemplate( 1315 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpinfra1").Build()). 1316 WithWorkerMachineDeploymentClasses( 1317 *builder.MachineDeploymentClass("aa"). 1318 WithInfrastructureTemplate( 1319 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1320 WithBootstrapTemplate( 1321 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1322 Build()). 1323 Build(), 1324 cluster: builder.Cluster(metav1.NamespaceDefault, "cluster1"). 1325 WithTopology( 1326 builder.ClusterTopology(). 1327 WithClass("class1"). 1328 WithVersion("v1.22.2"). 1329 WithMachineDeployment( 1330 builder.MachineDeploymentTopology("workers1"). 1331 WithClass("aa"). 1332 Build()). 1333 WithMachineDeployment( 1334 builder.MachineDeploymentTopology("workers1"). 1335 WithClass("aa"). 1336 Build()). 1337 Build()). 1338 Build(), 1339 wantErr: true, 1340 }, 1341 { 1342 name: "pass if MachineDeploymentTopologies are unique and share a class that is defined in ClusterClass", 1343 clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1344 WithInfrastructureClusterTemplate( 1345 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1346 WithControlPlaneTemplate( 1347 builder.ControlPlane(metav1.NamespaceDefault, "cp1").Build()). 1348 WithControlPlaneInfrastructureMachineTemplate( 1349 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpinfra1").Build()). 1350 WithWorkerMachineDeploymentClasses( 1351 *builder.MachineDeploymentClass("aa"). 1352 WithInfrastructureTemplate( 1353 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1354 WithBootstrapTemplate( 1355 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1356 Build()). 1357 Build(), 1358 cluster: builder.Cluster(metav1.NamespaceDefault, "cluster1"). 1359 WithTopology( 1360 builder.ClusterTopology(). 1361 WithClass("class1"). 1362 WithVersion("v1.22.2"). 1363 WithMachineDeployment( 1364 builder.MachineDeploymentTopology("workers1"). 1365 WithClass("aa"). 1366 Build()). 1367 WithMachineDeployment( 1368 builder.MachineDeploymentTopology("workers2"). 1369 WithClass("aa"). 1370 Build()). 1371 Build()). 1372 Build(), 1373 wantErr: false, 1374 }, 1375 { 1376 name: "fail if MachineDeploymentTopology name is longer than 63 characters", 1377 clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1378 WithInfrastructureClusterTemplate( 1379 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1380 WithControlPlaneTemplate( 1381 builder.ControlPlane(metav1.NamespaceDefault, "cp1").Build()). 1382 WithControlPlaneInfrastructureMachineTemplate( 1383 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpinfra1").Build()). 1384 WithWorkerMachineDeploymentClasses( 1385 *builder.MachineDeploymentClass("aa"). 1386 WithInfrastructureTemplate( 1387 builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()). 1388 WithBootstrapTemplate( 1389 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1390 Build()). 1391 Build(), 1392 cluster: builder.Cluster(metav1.NamespaceDefault, "cluster1"). 1393 WithTopology( 1394 builder.ClusterTopology(). 1395 WithClass("class1"). 1396 WithVersion("v1.22.2"). 1397 WithMachineDeployment( 1398 builder.MachineDeploymentTopology("machine-deployment-topology-name-that-has-longerthan63characterlooooooooooooooooooooooongname"). 1399 WithClass("aa"). 1400 Build()). 1401 Build()). 1402 Build(), 1403 wantErr: true, 1404 }, 1405 } 1406 for _, tt := range tests { 1407 t.Run(tt.name, func(t *testing.T) { 1408 g := NewWithT(t) 1409 allErrs := MachineDeploymentTopologiesAreValidAndDefinedInClusterClass(tt.cluster, tt.clusterClass) 1410 if tt.wantErr { 1411 g.Expect(allErrs).ToNot(BeEmpty()) 1412 return 1413 } 1414 g.Expect(allErrs).To(BeEmpty()) 1415 }) 1416 } 1417 } 1418 1419 func TestMachinePoolTopologiesAreUniqueAndDefinedInClusterClass(t *testing.T) { 1420 tests := []struct { 1421 name string 1422 clusterClass *clusterv1.ClusterClass 1423 cluster *clusterv1.Cluster 1424 wantErr bool 1425 }{ 1426 { 1427 name: "fail if MachinePoolTopologies name is empty", 1428 clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1429 WithInfrastructureClusterTemplate( 1430 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1431 WithControlPlaneTemplate( 1432 builder.ControlPlane(metav1.NamespaceDefault, "cp1").Build()). 1433 WithWorkerMachinePoolClasses( 1434 *builder.MachinePoolClass("aa"). 1435 WithInfrastructureTemplate( 1436 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 1437 WithBootstrapTemplate( 1438 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1439 Build()). 1440 Build(), 1441 cluster: builder.Cluster("fooboo", "cluster1"). 1442 WithTopology(builder.ClusterTopology(). 1443 WithClass("foo"). 1444 WithVersion("v1.19.1"). 1445 WithMachinePool( 1446 // The name should not be empty. 1447 builder.MachinePoolTopology(""). 1448 WithClass("aa"). 1449 Build()). 1450 Build()). 1451 Build(), 1452 wantErr: true, 1453 }, 1454 { 1455 name: "pass if MachinePoolTopologies are unique and defined in ClusterClass", 1456 clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1457 WithInfrastructureClusterTemplate( 1458 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1459 WithControlPlaneTemplate( 1460 builder.ControlPlane(metav1.NamespaceDefault, "cp1").Build()). 1461 WithControlPlaneInfrastructureMachineTemplate( 1462 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "cpinfra1").Build()). 1463 WithWorkerMachinePoolClasses( 1464 *builder.MachinePoolClass("aa"). 1465 WithInfrastructureTemplate( 1466 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 1467 WithBootstrapTemplate( 1468 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1469 Build()). 1470 Build(), 1471 cluster: builder.Cluster(metav1.NamespaceDefault, "cluster1"). 1472 WithTopology( 1473 builder.ClusterTopology(). 1474 WithClass("class1"). 1475 WithVersion("v1.22.2"). 1476 WithMachinePool( 1477 builder.MachinePoolTopology("workers1"). 1478 WithClass("aa"). 1479 Build()). 1480 Build()). 1481 Build(), 1482 wantErr: false, 1483 }, 1484 { 1485 name: "fail if MachinePoolTopologies are unique but not defined in ClusterClass", 1486 clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1487 WithInfrastructureClusterTemplate( 1488 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1489 WithControlPlaneTemplate( 1490 builder.ControlPlane(metav1.NamespaceDefault, "cp1").Build()). 1491 WithControlPlaneInfrastructureMachineTemplate( 1492 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "cpinfra1").Build()). 1493 WithWorkerMachinePoolClasses( 1494 *builder.MachinePoolClass("aa"). 1495 WithInfrastructureTemplate( 1496 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 1497 WithBootstrapTemplate( 1498 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1499 Build()). 1500 Build(), 1501 cluster: builder.Cluster(metav1.NamespaceDefault, "cluster1"). 1502 WithTopology( 1503 builder.ClusterTopology(). 1504 WithClass("class1"). 1505 WithVersion("v1.22.2"). 1506 WithMachinePool( 1507 builder.MachinePoolTopology("workers1"). 1508 WithClass("bb"). 1509 Build()). 1510 Build()). 1511 Build(), 1512 wantErr: true, 1513 }, 1514 { 1515 name: "fail if MachinePoolTopologies are not unique but is defined in ClusterClass", 1516 clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1517 WithInfrastructureClusterTemplate( 1518 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1519 WithControlPlaneTemplate( 1520 builder.ControlPlane(metav1.NamespaceDefault, "cp1").Build()). 1521 WithControlPlaneInfrastructureMachineTemplate( 1522 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "cpinfra1").Build()). 1523 WithWorkerMachinePoolClasses( 1524 *builder.MachinePoolClass("aa"). 1525 WithInfrastructureTemplate( 1526 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 1527 WithBootstrapTemplate( 1528 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1529 Build()). 1530 Build(), 1531 cluster: builder.Cluster(metav1.NamespaceDefault, "cluster1"). 1532 WithTopology( 1533 builder.ClusterTopology(). 1534 WithClass("class1"). 1535 WithVersion("v1.22.2"). 1536 WithMachinePool( 1537 builder.MachinePoolTopology("workers1"). 1538 WithClass("aa"). 1539 Build()). 1540 WithMachinePool( 1541 builder.MachinePoolTopology("workers1"). 1542 WithClass("aa"). 1543 Build()). 1544 Build()). 1545 Build(), 1546 wantErr: true, 1547 }, 1548 { 1549 name: "pass if MachinePoolTopologies are unique and share a class that is defined in ClusterClass", 1550 clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1551 WithInfrastructureClusterTemplate( 1552 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1553 WithControlPlaneTemplate( 1554 builder.ControlPlane(metav1.NamespaceDefault, "cp1").Build()). 1555 WithControlPlaneInfrastructureMachineTemplate( 1556 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "cpinfra1").Build()). 1557 WithWorkerMachinePoolClasses( 1558 *builder.MachinePoolClass("aa"). 1559 WithInfrastructureTemplate( 1560 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 1561 WithBootstrapTemplate( 1562 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1563 Build()). 1564 Build(), 1565 cluster: builder.Cluster(metav1.NamespaceDefault, "cluster1"). 1566 WithTopology( 1567 builder.ClusterTopology(). 1568 WithClass("class1"). 1569 WithVersion("v1.22.2"). 1570 WithMachinePool( 1571 builder.MachinePoolTopology("workers1"). 1572 WithClass("aa"). 1573 Build()). 1574 WithMachinePool( 1575 builder.MachinePoolTopology("workers2"). 1576 WithClass("aa"). 1577 Build()). 1578 Build()). 1579 Build(), 1580 wantErr: false, 1581 }, 1582 { 1583 name: "fail if MachinePoolTopology name is longer than 63 characters", 1584 clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1585 WithInfrastructureClusterTemplate( 1586 builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()). 1587 WithControlPlaneTemplate( 1588 builder.ControlPlane(metav1.NamespaceDefault, "cp1").Build()). 1589 WithControlPlaneInfrastructureMachineTemplate( 1590 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "cpinfra1").Build()). 1591 WithWorkerMachinePoolClasses( 1592 *builder.MachinePoolClass("aa"). 1593 WithInfrastructureTemplate( 1594 builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()). 1595 WithBootstrapTemplate( 1596 builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()). 1597 Build()). 1598 Build(), 1599 cluster: builder.Cluster(metav1.NamespaceDefault, "cluster1"). 1600 WithTopology( 1601 builder.ClusterTopology(). 1602 WithClass("class1"). 1603 WithVersion("v1.22.2"). 1604 WithMachinePool( 1605 builder.MachinePoolTopology("machine-pool-topology-name-that-has-longerthan63characterlooooooooooooooooooooooongname"). 1606 WithClass("aa"). 1607 Build()). 1608 Build()). 1609 Build(), 1610 wantErr: true, 1611 }, 1612 } 1613 for _, tt := range tests { 1614 t.Run(tt.name, func(t *testing.T) { 1615 g := NewWithT(t) 1616 allErrs := MachinePoolTopologiesAreValidAndDefinedInClusterClass(tt.cluster, tt.clusterClass) 1617 if tt.wantErr { 1618 g.Expect(allErrs).ToNot(BeEmpty()) 1619 return 1620 } 1621 g.Expect(allErrs).To(BeEmpty()) 1622 }) 1623 } 1624 } 1625 1626 func TestClusterClassReferencesAreValid(t *testing.T) { 1627 ref := &corev1.ObjectReference{ 1628 APIVersion: "group.test.io/foo", 1629 Kind: "barTemplate", 1630 Name: "baz", 1631 Namespace: "default", 1632 } 1633 invalidRef := &corev1.ObjectReference{ 1634 APIVersion: "group.test.io/foo", 1635 Kind: "another-barTemplate", 1636 Name: "baz", 1637 Namespace: "", 1638 } 1639 1640 tests := []struct { 1641 name string 1642 clusterClass *clusterv1.ClusterClass 1643 wantErr bool 1644 }{ 1645 { 1646 name: "pass for clusterClass with valid references", 1647 clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1648 WithInfrastructureClusterTemplate( 1649 refToUnstructured(ref)). 1650 WithControlPlaneTemplate( 1651 refToUnstructured(ref)). 1652 WithControlPlaneInfrastructureMachineTemplate( 1653 refToUnstructured(ref)). 1654 WithWorkerMachineDeploymentClasses( 1655 *builder.MachineDeploymentClass("aa"). 1656 WithInfrastructureTemplate( 1657 refToUnstructured(ref)). 1658 WithBootstrapTemplate( 1659 refToUnstructured(ref)). 1660 Build()). 1661 WithWorkerMachinePoolClasses( 1662 *builder.MachinePoolClass("aa"). 1663 WithInfrastructureTemplate( 1664 refToUnstructured(ref)). 1665 WithBootstrapTemplate( 1666 refToUnstructured(ref)). 1667 Build()). 1668 Build(), 1669 wantErr: false, 1670 }, 1671 { 1672 name: "error if clusterClass has multiple invalid md refs", 1673 clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1674 WithInfrastructureClusterTemplate( 1675 refToUnstructured(invalidRef)). 1676 WithControlPlaneTemplate( 1677 refToUnstructured(invalidRef)). 1678 WithControlPlaneInfrastructureMachineTemplate( 1679 refToUnstructured(invalidRef)). 1680 WithWorkerMachineDeploymentClasses( 1681 *builder.MachineDeploymentClass("a"). 1682 WithInfrastructureTemplate( 1683 refToUnstructured(invalidRef)). 1684 WithBootstrapTemplate( 1685 refToUnstructured(invalidRef)). 1686 Build(), 1687 *builder.MachineDeploymentClass("b"). 1688 WithInfrastructureTemplate( 1689 refToUnstructured(invalidRef)). 1690 WithBootstrapTemplate( 1691 refToUnstructured(invalidRef)). 1692 Build(), 1693 *builder.MachineDeploymentClass("c"). 1694 WithInfrastructureTemplate( 1695 refToUnstructured(invalidRef)). 1696 WithBootstrapTemplate( 1697 refToUnstructured(invalidRef)). 1698 Build()). 1699 Build(), 1700 wantErr: true, 1701 }, 1702 { 1703 name: "error if clusterClass has multiple invalid mp refs", 1704 clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1705 WithInfrastructureClusterTemplate( 1706 refToUnstructured(invalidRef)). 1707 WithControlPlaneTemplate( 1708 refToUnstructured(invalidRef)). 1709 WithControlPlaneInfrastructureMachineTemplate( 1710 refToUnstructured(invalidRef)). 1711 WithWorkerMachinePoolClasses( 1712 *builder.MachinePoolClass("a"). 1713 WithInfrastructureTemplate( 1714 refToUnstructured(invalidRef)). 1715 WithBootstrapTemplate( 1716 refToUnstructured(invalidRef)). 1717 Build(), 1718 *builder.MachinePoolClass("b"). 1719 WithInfrastructureTemplate( 1720 refToUnstructured(invalidRef)). 1721 WithBootstrapTemplate( 1722 refToUnstructured(invalidRef)). 1723 Build(), 1724 *builder.MachinePoolClass("c"). 1725 WithInfrastructureTemplate( 1726 refToUnstructured(invalidRef)). 1727 WithBootstrapTemplate( 1728 refToUnstructured(invalidRef)). 1729 Build()). 1730 Build(), 1731 wantErr: true, 1732 }, 1733 { 1734 name: "error if clusterClass has invalid ControlPlane ref", 1735 clusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1"). 1736 WithInfrastructureClusterTemplate( 1737 refToUnstructured(ref)). 1738 WithControlPlaneTemplate( 1739 refToUnstructured(invalidRef)). 1740 WithControlPlaneInfrastructureMachineTemplate( 1741 refToUnstructured(ref)). 1742 WithWorkerMachineDeploymentClasses( 1743 *builder.MachineDeploymentClass("aa"). 1744 WithInfrastructureTemplate( 1745 refToUnstructured(ref)). 1746 WithBootstrapTemplate( 1747 refToUnstructured(ref)). 1748 Build()). 1749 WithWorkerMachinePoolClasses( 1750 *builder.MachinePoolClass("aa"). 1751 WithInfrastructureTemplate( 1752 refToUnstructured(ref)). 1753 WithBootstrapTemplate( 1754 refToUnstructured(ref)). 1755 Build()). 1756 Build(), 1757 wantErr: true, 1758 }, 1759 } 1760 for _, tt := range tests { 1761 t.Run(tt.name, func(t *testing.T) { 1762 g := NewWithT(t) 1763 allErrs := ClusterClassReferencesAreValid(tt.clusterClass) 1764 if tt.wantErr { 1765 g.Expect(allErrs).ToNot(BeEmpty()) 1766 return 1767 } 1768 g.Expect(allErrs).To(BeEmpty()) 1769 }) 1770 } 1771 } 1772 1773 func refToUnstructured(ref *corev1.ObjectReference) *unstructured.Unstructured { 1774 gvk := ref.GetObjectKind().GroupVersionKind() 1775 output := &unstructured.Unstructured{} 1776 output.SetKind(gvk.Kind) 1777 output.SetAPIVersion(gvk.GroupVersion().String()) 1778 output.SetName(ref.Name) 1779 output.SetNamespace(ref.Namespace) 1780 return output 1781 }