sigs.k8s.io/cluster-api@v1.7.1/internal/webhooks/clusterclass_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 webhooks
    18  
    19  import (
    20  	"strings"
    21  	"testing"
    22  	"time"
    23  
    24  	. "github.com/onsi/gomega"
    25  	corev1 "k8s.io/api/core/v1"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/runtime"
    28  	utilfeature "k8s.io/component-base/featuregate/testing"
    29  	"k8s.io/utils/ptr"
    30  	ctrl "sigs.k8s.io/controller-runtime"
    31  	"sigs.k8s.io/controller-runtime/pkg/client"
    32  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    33  
    34  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    35  	"sigs.k8s.io/cluster-api/api/v1beta1/index"
    36  	expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1"
    37  	"sigs.k8s.io/cluster-api/feature"
    38  	"sigs.k8s.io/cluster-api/internal/test/builder"
    39  	"sigs.k8s.io/cluster-api/internal/webhooks/util"
    40  )
    41  
    42  var (
    43  	ctx        = ctrl.SetupSignalHandler()
    44  	fakeScheme = runtime.NewScheme()
    45  )
    46  
    47  func init() {
    48  	_ = clusterv1.AddToScheme(fakeScheme)
    49  	_ = expv1.AddToScheme(fakeScheme)
    50  }
    51  
    52  func TestClusterClassDefaultNamespaces(t *testing.T) {
    53  	// NOTE: ClusterTopology feature flag is disabled by default, thus preventing to create or update ClusterClasses.
    54  	// Enabling the feature flag temporarily for this test.
    55  	defer utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.ClusterTopology, true)()
    56  
    57  	namespace := "default"
    58  
    59  	in := builder.ClusterClass(namespace, "class1").
    60  		WithInfrastructureClusterTemplate(
    61  			builder.InfrastructureClusterTemplate("", "infra1").Build()).
    62  		WithControlPlaneTemplate(
    63  			builder.ControlPlaneTemplate("", "cp1").
    64  				Build()).
    65  		WithControlPlaneInfrastructureMachineTemplate(
    66  			builder.InfrastructureMachineTemplate("", "cpInfra1").
    67  				Build()).
    68  		WithWorkerMachineDeploymentClasses(
    69  			*builder.MachineDeploymentClass("aa").
    70  				WithInfrastructureTemplate(
    71  					builder.InfrastructureMachineTemplate("", "infra1").Build()).
    72  				WithBootstrapTemplate(
    73  					builder.BootstrapTemplate("", "bootstrap1").Build()).
    74  				Build()).
    75  		WithWorkerMachinePoolClasses(
    76  			*builder.MachinePoolClass("aa").
    77  				WithInfrastructureTemplate(
    78  					builder.InfrastructureMachinePoolTemplate("", "infra1").Build()).
    79  				WithBootstrapTemplate(
    80  					builder.BootstrapTemplate("", "bootstrap1").Build()).
    81  				Build()).
    82  		Build()
    83  
    84  	fakeClient := fake.NewClientBuilder().
    85  		WithScheme(fakeScheme).
    86  		WithIndex(&clusterv1.Cluster{}, index.ClusterClassNameField, index.ClusterByClusterClassClassName).
    87  		Build()
    88  
    89  	// Create the webhook and add the fakeClient as its client.
    90  	webhook := &ClusterClass{Client: fakeClient}
    91  	t.Run("for ClusterClass", util.CustomDefaultValidateTest(ctx, in, webhook))
    92  
    93  	g := NewWithT(t)
    94  	g.Expect(webhook.Default(ctx, in)).To(Succeed())
    95  
    96  	// Namespace defaulted on references
    97  	g.Expect(in.Spec.Infrastructure.Ref.Namespace).To(Equal(namespace))
    98  	g.Expect(in.Spec.ControlPlane.Ref.Namespace).To(Equal(namespace))
    99  	g.Expect(in.Spec.ControlPlane.MachineInfrastructure.Ref.Namespace).To(Equal(namespace))
   100  	for i := range in.Spec.Workers.MachineDeployments {
   101  		g.Expect(in.Spec.Workers.MachineDeployments[i].Template.Bootstrap.Ref.Namespace).To(Equal(namespace))
   102  		g.Expect(in.Spec.Workers.MachineDeployments[i].Template.Infrastructure.Ref.Namespace).To(Equal(namespace))
   103  	}
   104  	for i := range in.Spec.Workers.MachinePools {
   105  		g.Expect(in.Spec.Workers.MachinePools[i].Template.Bootstrap.Ref.Namespace).To(Equal(namespace))
   106  		g.Expect(in.Spec.Workers.MachinePools[i].Template.Infrastructure.Ref.Namespace).To(Equal(namespace))
   107  	}
   108  }
   109  
   110  func TestClusterClassValidationFeatureGated(t *testing.T) {
   111  	// NOTE: ClusterTopology feature flag is disabled by default, thus preventing to create or update ClusterClasses.
   112  
   113  	tests := []struct {
   114  		name      string
   115  		in        *clusterv1.ClusterClass
   116  		old       *clusterv1.ClusterClass
   117  		expectErr bool
   118  	}{
   119  		{
   120  			name: "creation should fail if feature flag is disabled, no matter the ClusterClass is valid(or not)",
   121  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   122  				WithInfrastructureClusterTemplate(
   123  					builder.InfrastructureClusterTemplate("", "infra1").Build()).
   124  				WithControlPlaneTemplate(
   125  					builder.ControlPlaneTemplate("", "cp1").
   126  						Build()).
   127  				WithControlPlaneInfrastructureMachineTemplate(
   128  					builder.InfrastructureMachineTemplate("", "cpInfra1").
   129  						Build()).
   130  				WithWorkerMachineDeploymentClasses(
   131  					*builder.MachineDeploymentClass("aa").
   132  						WithInfrastructureTemplate(
   133  							builder.InfrastructureMachineTemplate("", "infra1").Build()).
   134  						WithBootstrapTemplate(
   135  							builder.BootstrapTemplate("", "bootstrap1").Build()).
   136  						Build()).
   137  				WithWorkerMachinePoolClasses(
   138  					*builder.MachinePoolClass("aa").
   139  						WithInfrastructureTemplate(
   140  							builder.InfrastructureMachinePoolTemplate("", "infra1").Build()).
   141  						WithBootstrapTemplate(
   142  							builder.BootstrapTemplate("", "bootstrap1").Build()).
   143  						Build()).
   144  				Build(),
   145  			expectErr: true,
   146  		},
   147  		{
   148  			name: "update should fail if feature flag is disabled, no matter the ClusterClass is valid(or not)",
   149  			old: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   150  				WithInfrastructureClusterTemplate(
   151  					builder.InfrastructureClusterTemplate("", "infra1").Build()).
   152  				WithControlPlaneTemplate(
   153  					builder.ControlPlaneTemplate("", "cp1").
   154  						Build()).
   155  				WithControlPlaneInfrastructureMachineTemplate(
   156  					builder.InfrastructureMachineTemplate("", "cpInfra1").
   157  						Build()).
   158  				WithWorkerMachineDeploymentClasses(
   159  					*builder.MachineDeploymentClass("aa").
   160  						WithInfrastructureTemplate(
   161  							builder.InfrastructureMachineTemplate("", "infra1").Build()).
   162  						WithBootstrapTemplate(
   163  							builder.BootstrapTemplate("", "bootstrap1").Build()).
   164  						Build()).
   165  				WithWorkerMachinePoolClasses(
   166  					*builder.MachinePoolClass("aa").
   167  						WithInfrastructureTemplate(
   168  							builder.InfrastructureMachinePoolTemplate("", "infra1").Build()).
   169  						WithBootstrapTemplate(
   170  							builder.BootstrapTemplate("", "bootstrap1").Build()).
   171  						Build()).
   172  				Build(),
   173  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   174  				WithInfrastructureClusterTemplate(
   175  					builder.InfrastructureClusterTemplate("", "infra1").Build()).
   176  				WithControlPlaneTemplate(
   177  					builder.ControlPlaneTemplate("", "cp1").
   178  						Build()).
   179  				WithControlPlaneInfrastructureMachineTemplate(
   180  					builder.InfrastructureMachineTemplate("", "cpInfra1").
   181  						Build()).
   182  				WithWorkerMachineDeploymentClasses(
   183  					*builder.MachineDeploymentClass("aa").
   184  						WithInfrastructureTemplate(
   185  							builder.InfrastructureMachineTemplate("", "infra1").Build()).
   186  						WithBootstrapTemplate(
   187  							builder.BootstrapTemplate("", "bootstrap1").Build()).
   188  						Build()).
   189  				WithWorkerMachinePoolClasses(
   190  					*builder.MachinePoolClass("aa").
   191  						WithInfrastructureTemplate(
   192  							builder.InfrastructureMachinePoolTemplate("", "infra1").Build()).
   193  						WithBootstrapTemplate(
   194  							builder.BootstrapTemplate("", "bootstrap1").Build()).
   195  						Build()).
   196  				Build(),
   197  			expectErr: true,
   198  		},
   199  	}
   200  
   201  	for _, tt := range tests {
   202  		t.Run(tt.name, func(t *testing.T) {
   203  			g := NewWithT(t)
   204  			webhook := &ClusterClass{}
   205  			err := webhook.validate(ctx, tt.old, tt.in)
   206  			if tt.expectErr {
   207  				g.Expect(err).To(HaveOccurred())
   208  				return
   209  			}
   210  			g.Expect(err).ToNot(HaveOccurred())
   211  		})
   212  	}
   213  }
   214  
   215  func TestClusterClassValidation(t *testing.T) {
   216  	// NOTE: ClusterTopology feature flag is disabled by default, thus preventing to create or update ClusterClasses.
   217  	// Enabling the feature flag temporarily for this test.
   218  	defer utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.ClusterTopology, true)()
   219  
   220  	ref := &corev1.ObjectReference{
   221  		APIVersion: "group.test.io/foo",
   222  		Kind:       "barTemplate",
   223  		Name:       "baz",
   224  		Namespace:  "default",
   225  	}
   226  	refBadTemplate := &corev1.ObjectReference{
   227  		APIVersion: "group.test.io/foo",
   228  		Kind:       "bar",
   229  		Name:       "baz",
   230  		Namespace:  "default",
   231  	}
   232  	refBadAPIVersion := &corev1.ObjectReference{
   233  		APIVersion: "group/test.io/v1/foo",
   234  		Kind:       "barTemplate",
   235  		Name:       "baz",
   236  		Namespace:  "default",
   237  	}
   238  	incompatibleRef := &corev1.ObjectReference{
   239  		APIVersion: "group.test.io/foo",
   240  		Kind:       "another-barTemplate",
   241  		Name:       "baz",
   242  		Namespace:  "default",
   243  	}
   244  	compatibleRef := &corev1.ObjectReference{
   245  		APIVersion: "group.test.io/another-foo",
   246  		Kind:       "barTemplate",
   247  		Name:       "another-baz",
   248  		Namespace:  "default",
   249  	}
   250  
   251  	tests := []struct {
   252  		name      string
   253  		in        *clusterv1.ClusterClass
   254  		old       *clusterv1.ClusterClass
   255  		expectErr bool
   256  	}{
   257  
   258  		/*
   259  			CREATE Tests
   260  		*/
   261  
   262  		{
   263  			name: "create pass",
   264  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   265  				WithInfrastructureClusterTemplate(
   266  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   267  				WithControlPlaneTemplate(
   268  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   269  						Build()).
   270  				WithControlPlaneInfrastructureMachineTemplate(
   271  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   272  						Build()).
   273  				WithWorkerMachineDeploymentClasses(
   274  					*builder.MachineDeploymentClass("aa").
   275  						WithInfrastructureTemplate(
   276  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
   277  						WithBootstrapTemplate(
   278  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
   279  						Build(),
   280  					*builder.MachineDeploymentClass("bb").
   281  						WithInfrastructureTemplate(
   282  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
   283  						WithBootstrapTemplate(
   284  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
   285  						Build()).
   286  				WithWorkerMachinePoolClasses(
   287  					*builder.MachinePoolClass("aa").
   288  						WithInfrastructureTemplate(
   289  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
   290  						WithBootstrapTemplate(
   291  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
   292  						Build(),
   293  					*builder.MachinePoolClass("bb").
   294  						WithInfrastructureTemplate(
   295  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
   296  						WithBootstrapTemplate(
   297  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
   298  						Build()).
   299  				Build(),
   300  			expectErr: false,
   301  		},
   302  
   303  		// empty name in ref tests
   304  		{
   305  			name: "create fail infrastructureCluster has empty name",
   306  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   307  				WithInfrastructureClusterTemplate(
   308  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "").Build()).
   309  				WithControlPlaneTemplate(
   310  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   311  						Build()).
   312  				Build(),
   313  			expectErr: true,
   314  		},
   315  		{
   316  			name: "create fail controlPlane class has empty name",
   317  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   318  				WithInfrastructureClusterTemplate(
   319  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   320  				WithControlPlaneTemplate(
   321  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "").
   322  						Build()).
   323  				Build(),
   324  			expectErr: true,
   325  		},
   326  		{
   327  			name: "create fail control plane class machineInfrastructure has empty name",
   328  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   329  				WithInfrastructureClusterTemplate(
   330  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   331  				WithControlPlaneTemplate(
   332  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   333  						Build()).
   334  				WithControlPlaneInfrastructureMachineTemplate(
   335  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "").
   336  						Build()).
   337  				Build(),
   338  			expectErr: true,
   339  		},
   340  		{
   341  			name: "create fail machineDeployment Bootstrap has empty name",
   342  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   343  				WithInfrastructureClusterTemplate(
   344  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   345  				WithControlPlaneTemplate(
   346  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   347  						Build()).
   348  				WithControlPlaneInfrastructureMachineTemplate(
   349  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   350  						Build()).
   351  				WithWorkerMachineDeploymentClasses(
   352  					*builder.MachineDeploymentClass("aa").
   353  						WithInfrastructureTemplate(
   354  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
   355  						WithBootstrapTemplate(
   356  							builder.BootstrapTemplate(metav1.NamespaceDefault, "").Build()).
   357  						Build()).
   358  				Build(),
   359  			expectErr: true,
   360  		},
   361  		{
   362  			name: "create fail machineDeployment Infrastructure has empty name",
   363  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   364  				WithInfrastructureClusterTemplate(
   365  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   366  				WithControlPlaneTemplate(
   367  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   368  						Build()).
   369  				WithControlPlaneInfrastructureMachineTemplate(
   370  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   371  						Build()).
   372  				WithWorkerMachineDeploymentClasses(
   373  					*builder.MachineDeploymentClass("aa").
   374  						WithInfrastructureTemplate(
   375  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "").Build()).
   376  						WithBootstrapTemplate(
   377  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap").Build()).
   378  						Build()).
   379  				Build(),
   380  			expectErr: true,
   381  		},
   382  		{
   383  			name: "create fail machinePool Bootstrap has empty name",
   384  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   385  				WithInfrastructureClusterTemplate(
   386  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   387  				WithControlPlaneTemplate(
   388  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   389  						Build()).
   390  				WithControlPlaneInfrastructureMachineTemplate(
   391  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   392  						Build()).
   393  				WithWorkerMachinePoolClasses(
   394  					*builder.MachinePoolClass("aa").
   395  						WithInfrastructureTemplate(
   396  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
   397  						WithBootstrapTemplate(
   398  							builder.BootstrapTemplate(metav1.NamespaceDefault, "").Build()).
   399  						Build()).
   400  				Build(),
   401  			expectErr: true,
   402  		},
   403  		{
   404  			name: "create fail machinePool Infrastructure has empty name",
   405  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   406  				WithInfrastructureClusterTemplate(
   407  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   408  				WithControlPlaneTemplate(
   409  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   410  						Build()).
   411  				WithControlPlaneInfrastructureMachineTemplate(
   412  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   413  						Build()).
   414  				WithWorkerMachinePoolClasses(
   415  					*builder.MachinePoolClass("aa").
   416  						WithInfrastructureTemplate(
   417  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "").Build()).
   418  						WithBootstrapTemplate(
   419  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap").Build()).
   420  						Build()).
   421  				Build(),
   422  			expectErr: true,
   423  		},
   424  
   425  		// inconsistent namespace in ref tests
   426  		{
   427  			name: "create fail if InfrastructureCluster has inconsistent namespace",
   428  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   429  				WithInfrastructureClusterTemplate(
   430  					builder.InfrastructureClusterTemplate("WrongNamespace", "infra1").Build()).
   431  				WithControlPlaneTemplate(
   432  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   433  						Build()).
   434  				WithControlPlaneInfrastructureMachineTemplate(
   435  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   436  						Build()).
   437  				Build(),
   438  			expectErr: true,
   439  		},
   440  		{
   441  			name: "create fail if controlPlane has inconsistent namespace",
   442  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   443  				WithInfrastructureClusterTemplate(
   444  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   445  				WithControlPlaneTemplate(
   446  					builder.ControlPlaneTemplate("WrongNamespace", "cp1").
   447  						Build()).
   448  				WithControlPlaneInfrastructureMachineTemplate(
   449  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   450  						Build()).
   451  				Build(),
   452  			expectErr: true,
   453  		},
   454  		{
   455  			name: "create fail if controlPlane machineInfrastructure has inconsistent namespace",
   456  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   457  				WithInfrastructureClusterTemplate(
   458  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   459  				WithControlPlaneTemplate(
   460  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   461  						Build()).
   462  				WithControlPlaneInfrastructureMachineTemplate(
   463  					builder.InfrastructureMachineTemplate("WrongNamespace", "cpInfra1").
   464  						Build()).
   465  				Build(),
   466  			expectErr: true,
   467  		},
   468  		{
   469  			name: "create fail if machineDeployment / bootstrap has inconsistent namespace",
   470  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   471  				WithInfrastructureClusterTemplate(
   472  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   473  				WithControlPlaneTemplate(
   474  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   475  						Build()).
   476  				WithControlPlaneInfrastructureMachineTemplate(
   477  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   478  						Build()).
   479  				WithWorkerMachineDeploymentClasses(
   480  					*builder.MachineDeploymentClass("aa").
   481  						WithInfrastructureTemplate(
   482  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
   483  						WithBootstrapTemplate(
   484  							builder.BootstrapTemplate("WrongNamespace", "bootstrap1").Build()).
   485  						Build()).
   486  				Build(),
   487  			expectErr: true,
   488  		},
   489  		{
   490  			name: "create fail if machineDeployment / infrastructure has inconsistent namespace",
   491  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   492  				WithInfrastructureClusterTemplate(
   493  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   494  				WithControlPlaneTemplate(
   495  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   496  						Build()).
   497  				WithControlPlaneInfrastructureMachineTemplate(
   498  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   499  						Build()).
   500  				WithWorkerMachineDeploymentClasses(
   501  					*builder.MachineDeploymentClass("aa").
   502  						WithInfrastructureTemplate(
   503  							builder.InfrastructureMachineTemplate("WrongNamespace", "infra1").Build()).
   504  						WithBootstrapTemplate(
   505  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
   506  						Build()).
   507  				Build(),
   508  			expectErr: true,
   509  		},
   510  		{
   511  			name: "create fail if machinePool / bootstrap has inconsistent namespace",
   512  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   513  				WithInfrastructureClusterTemplate(
   514  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   515  				WithControlPlaneTemplate(
   516  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   517  						Build()).
   518  				WithControlPlaneInfrastructureMachineTemplate(
   519  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   520  						Build()).
   521  				WithWorkerMachinePoolClasses(
   522  					*builder.MachinePoolClass("aa").
   523  						WithInfrastructureTemplate(
   524  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
   525  						WithBootstrapTemplate(
   526  							builder.BootstrapTemplate("WrongNamespace", "bootstrap1").Build()).
   527  						Build()).
   528  				Build(),
   529  			expectErr: true,
   530  		},
   531  		{
   532  			name: "create fail if machinePool / infrastructure has inconsistent namespace",
   533  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   534  				WithInfrastructureClusterTemplate(
   535  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   536  				WithControlPlaneTemplate(
   537  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   538  						Build()).
   539  				WithControlPlaneInfrastructureMachineTemplate(
   540  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   541  						Build()).
   542  				WithWorkerMachinePoolClasses(
   543  					*builder.MachinePoolClass("aa").
   544  						WithInfrastructureTemplate(
   545  							builder.InfrastructureMachinePoolTemplate("WrongNamespace", "infra1").Build()).
   546  						WithBootstrapTemplate(
   547  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
   548  						Build()).
   549  				Build(),
   550  			expectErr: true,
   551  		},
   552  
   553  		// bad template in ref tests
   554  		{
   555  			name: "create fail if bad template in InfrastructureCluster",
   556  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   557  				WithInfrastructureClusterTemplate(
   558  					refToUnstructured(refBadTemplate)).
   559  				WithControlPlaneTemplate(
   560  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   561  						Build()).
   562  				WithControlPlaneInfrastructureMachineTemplate(
   563  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   564  						Build()).
   565  				Build(),
   566  			old:       nil,
   567  			expectErr: true,
   568  		},
   569  		{
   570  			name: "create fail if bad template in controlPlane machineInfrastructure",
   571  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   572  				WithInfrastructureClusterTemplate(
   573  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   574  				WithControlPlaneTemplate(
   575  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   576  						Build()).
   577  				WithControlPlaneInfrastructureMachineTemplate(
   578  					refToUnstructured(refBadTemplate)).
   579  				Build(),
   580  			old:       nil,
   581  			expectErr: true,
   582  		},
   583  		{
   584  			name: "create fail if bad template in ControlPlane",
   585  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   586  				WithInfrastructureClusterTemplate(
   587  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   588  				WithControlPlaneTemplate(
   589  					refToUnstructured(refBadTemplate)).
   590  				WithControlPlaneInfrastructureMachineTemplate(
   591  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   592  						Build()).
   593  				Build(),
   594  			old:       nil,
   595  			expectErr: true,
   596  		},
   597  		{
   598  			name: "create fail if bad template in machineDeployment Bootstrap",
   599  
   600  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   601  				WithInfrastructureClusterTemplate(
   602  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   603  				WithControlPlaneTemplate(
   604  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   605  						Build()).
   606  				WithControlPlaneInfrastructureMachineTemplate(
   607  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   608  						Build()).
   609  				WithWorkerMachineDeploymentClasses(
   610  					*builder.MachineDeploymentClass("aa").
   611  						WithInfrastructureTemplate(
   612  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
   613  						WithBootstrapTemplate(
   614  							refToUnstructured(refBadTemplate)).
   615  						Build()).
   616  				Build(),
   617  			old:       nil,
   618  			expectErr: true,
   619  		},
   620  		{
   621  			name: "create fail if bad template in machineDeployment Infrastructure",
   622  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   623  				WithInfrastructureClusterTemplate(
   624  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   625  				WithControlPlaneTemplate(
   626  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   627  						Build()).
   628  				WithControlPlaneInfrastructureMachineTemplate(
   629  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   630  						Build()).
   631  				WithWorkerMachineDeploymentClasses(
   632  					*builder.MachineDeploymentClass("aa").
   633  						WithInfrastructureTemplate(
   634  							refToUnstructured(refBadTemplate)).
   635  						WithBootstrapTemplate(
   636  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
   637  						Build()).
   638  				Build(),
   639  			old:       nil,
   640  			expectErr: true,
   641  		},
   642  		{
   643  			name: "create fail if bad template in machinePool Bootstrap",
   644  
   645  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   646  				WithInfrastructureClusterTemplate(
   647  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   648  				WithControlPlaneTemplate(
   649  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   650  						Build()).
   651  				WithControlPlaneInfrastructureMachineTemplate(
   652  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   653  						Build()).
   654  				WithWorkerMachinePoolClasses(
   655  					*builder.MachinePoolClass("aa").
   656  						WithInfrastructureTemplate(
   657  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
   658  						WithBootstrapTemplate(
   659  							refToUnstructured(refBadTemplate)).
   660  						Build()).
   661  				Build(),
   662  			old:       nil,
   663  			expectErr: true,
   664  		},
   665  		{
   666  			name: "create fail if bad template in machinePool Infrastructure",
   667  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   668  				WithInfrastructureClusterTemplate(
   669  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   670  				WithControlPlaneTemplate(
   671  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   672  						Build()).
   673  				WithControlPlaneInfrastructureMachineTemplate(
   674  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   675  						Build()).
   676  				WithWorkerMachinePoolClasses(
   677  					*builder.MachinePoolClass("aa").
   678  						WithInfrastructureTemplate(
   679  							refToUnstructured(refBadTemplate)).
   680  						WithBootstrapTemplate(
   681  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
   682  						Build()).
   683  				Build(),
   684  			old:       nil,
   685  			expectErr: true,
   686  		},
   687  
   688  		// bad apiVersion in ref tests
   689  		{
   690  			name: "create fail with a bad APIVersion for template in InfrastructureCluster",
   691  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   692  				WithInfrastructureClusterTemplate(
   693  					refToUnstructured(refBadAPIVersion)).
   694  				WithControlPlaneTemplate(
   695  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   696  						Build()).
   697  				WithControlPlaneInfrastructureMachineTemplate(
   698  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   699  						Build()).
   700  				Build(),
   701  			old:       nil,
   702  			expectErr: true,
   703  		},
   704  		{
   705  			name: "create fail with a bad APIVersion for template in controlPlane machineInfrastructure",
   706  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   707  				WithInfrastructureClusterTemplate(
   708  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   709  				WithControlPlaneTemplate(
   710  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   711  						Build()).
   712  				WithControlPlaneInfrastructureMachineTemplate(
   713  					refToUnstructured(refBadAPIVersion)).
   714  				Build(),
   715  			old:       nil,
   716  			expectErr: true,
   717  		},
   718  		{
   719  			name: "create fail with a bad APIVersion for template in ControlPlane",
   720  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   721  				WithInfrastructureClusterTemplate(
   722  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   723  				WithControlPlaneTemplate(
   724  					refToUnstructured(refBadAPIVersion)).
   725  				WithControlPlaneInfrastructureMachineTemplate(
   726  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   727  						Build()).
   728  				Build(),
   729  			old:       nil,
   730  			expectErr: true,
   731  		},
   732  		{
   733  			name: "create fail with a bad APIVersion for template in machineDeployment Bootstrap",
   734  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   735  				WithInfrastructureClusterTemplate(
   736  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   737  				WithControlPlaneTemplate(
   738  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   739  						Build()).
   740  				WithControlPlaneInfrastructureMachineTemplate(
   741  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   742  						Build()).
   743  				WithWorkerMachineDeploymentClasses(
   744  					*builder.MachineDeploymentClass("aa").
   745  						WithInfrastructureTemplate(
   746  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
   747  						WithBootstrapTemplate(
   748  							refToUnstructured(refBadAPIVersion)).
   749  						Build()).
   750  				Build(),
   751  			old:       nil,
   752  			expectErr: true,
   753  		},
   754  		{
   755  			name: "create fail with a bad APIVersion for template in machineDeployment Infrastructure",
   756  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   757  				WithInfrastructureClusterTemplate(
   758  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   759  				WithControlPlaneTemplate(
   760  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   761  						Build()).
   762  				WithControlPlaneInfrastructureMachineTemplate(
   763  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   764  						Build()).
   765  				WithWorkerMachineDeploymentClasses(
   766  					*builder.MachineDeploymentClass("aa").
   767  						WithInfrastructureTemplate(
   768  							refToUnstructured(refBadAPIVersion)).
   769  						WithBootstrapTemplate(
   770  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
   771  						Build()).
   772  				Build(),
   773  			old:       nil,
   774  			expectErr: true,
   775  		},
   776  		{
   777  			name: "create fail with a bad APIVersion for template in machinePool Bootstrap",
   778  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   779  				WithInfrastructureClusterTemplate(
   780  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   781  				WithControlPlaneTemplate(
   782  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   783  						Build()).
   784  				WithControlPlaneInfrastructureMachineTemplate(
   785  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   786  						Build()).
   787  				WithWorkerMachinePoolClasses(
   788  					*builder.MachinePoolClass("aa").
   789  						WithInfrastructureTemplate(
   790  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
   791  						WithBootstrapTemplate(
   792  							refToUnstructured(refBadAPIVersion)).
   793  						Build()).
   794  				Build(),
   795  			old:       nil,
   796  			expectErr: true,
   797  		},
   798  		{
   799  			name: "create fail with a bad APIVersion for template in machinePool Infrastructure",
   800  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   801  				WithInfrastructureClusterTemplate(
   802  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   803  				WithControlPlaneTemplate(
   804  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   805  						Build()).
   806  				WithControlPlaneInfrastructureMachineTemplate(
   807  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   808  						Build()).
   809  				WithWorkerMachinePoolClasses(
   810  					*builder.MachinePoolClass("aa").
   811  						WithInfrastructureTemplate(
   812  							refToUnstructured(refBadAPIVersion)).
   813  						WithBootstrapTemplate(
   814  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
   815  						Build()).
   816  				Build(),
   817  			old:       nil,
   818  			expectErr: true,
   819  		},
   820  
   821  		// create test
   822  		{
   823  			name: "create fail if duplicated machineDeploymentClasses",
   824  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   825  				WithInfrastructureClusterTemplate(
   826  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   827  				WithControlPlaneTemplate(
   828  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   829  						Build()).
   830  				WithControlPlaneInfrastructureMachineTemplate(
   831  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   832  						Build()).
   833  				WithWorkerMachineDeploymentClasses(
   834  					*builder.MachineDeploymentClass("aa").
   835  						WithInfrastructureTemplate(
   836  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
   837  						WithBootstrapTemplate(
   838  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).Build(),
   839  					*builder.MachineDeploymentClass("aa").
   840  						WithInfrastructureTemplate(
   841  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
   842  						WithBootstrapTemplate(
   843  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
   844  						Build()).
   845  				Build(),
   846  			expectErr: true,
   847  		},
   848  		{
   849  			name: "create fail if duplicated machinePoolClasses",
   850  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   851  				WithInfrastructureClusterTemplate(
   852  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   853  				WithControlPlaneTemplate(
   854  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   855  						Build()).
   856  				WithControlPlaneInfrastructureMachineTemplate(
   857  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   858  						Build()).
   859  				WithWorkerMachinePoolClasses(
   860  					*builder.MachinePoolClass("aa").
   861  						WithInfrastructureTemplate(
   862  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
   863  						WithBootstrapTemplate(
   864  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).Build(),
   865  					*builder.MachinePoolClass("aa").
   866  						WithInfrastructureTemplate(
   867  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
   868  						WithBootstrapTemplate(
   869  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
   870  						Build()).
   871  				Build(),
   872  			expectErr: true,
   873  		},
   874  		{
   875  			name: "create pass if valid machineHealthCheck defined for ControlPlane with MachineInfrastructure set",
   876  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   877  				WithInfrastructureClusterTemplate(
   878  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   879  				WithControlPlaneTemplate(
   880  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   881  						Build()).
   882  				WithControlPlaneInfrastructureMachineTemplate(
   883  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   884  						Build()).
   885  				WithControlPlaneMachineHealthCheck(&clusterv1.MachineHealthCheckClass{
   886  					UnhealthyConditions: []clusterv1.UnhealthyCondition{
   887  						{
   888  							Type:    corev1.NodeReady,
   889  							Status:  corev1.ConditionUnknown,
   890  							Timeout: metav1.Duration{Duration: 5 * time.Minute},
   891  						},
   892  					},
   893  					NodeStartupTimeout: &metav1.Duration{
   894  						Duration: time.Duration(6000000000000)}}).
   895  				Build(),
   896  		},
   897  		{
   898  			name: "create fail if MachineHealthCheck defined for ControlPlane with MachineInfrastructure unset",
   899  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   900  				WithInfrastructureClusterTemplate(
   901  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   902  				WithControlPlaneTemplate(
   903  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   904  						Build()).
   905  				// No ControlPlaneMachineInfrastructure makes this an invalid creation request.
   906  				WithControlPlaneMachineHealthCheck(&clusterv1.MachineHealthCheckClass{
   907  					NodeStartupTimeout: &metav1.Duration{
   908  						Duration: time.Duration(6000000000000)}}).
   909  				Build(),
   910  			expectErr: true,
   911  		},
   912  		{
   913  			name: "create fail if ControlPlane MachineHealthCheck does not define UnhealthyConditions",
   914  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   915  				WithInfrastructureClusterTemplate(
   916  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   917  				WithControlPlaneTemplate(
   918  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   919  						Build()).
   920  				WithControlPlaneInfrastructureMachineTemplate(
   921  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
   922  						Build()).
   923  				WithControlPlaneMachineHealthCheck(&clusterv1.MachineHealthCheckClass{
   924  					NodeStartupTimeout: &metav1.Duration{
   925  						Duration: time.Duration(6000000000000)}}).
   926  				Build(),
   927  			expectErr: true,
   928  		},
   929  		{
   930  			name: "create pass if MachineDeployment MachineHealthCheck is valid",
   931  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   932  				WithInfrastructureClusterTemplate(
   933  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   934  				WithControlPlaneTemplate(
   935  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   936  						Build()).
   937  				WithWorkerMachineDeploymentClasses(
   938  					*builder.MachineDeploymentClass("aa").
   939  						WithInfrastructureTemplate(
   940  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
   941  						WithBootstrapTemplate(
   942  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
   943  						WithMachineHealthCheckClass(&clusterv1.MachineHealthCheckClass{
   944  							UnhealthyConditions: []clusterv1.UnhealthyCondition{
   945  								{
   946  									Type:    corev1.NodeReady,
   947  									Status:  corev1.ConditionUnknown,
   948  									Timeout: metav1.Duration{Duration: 5 * time.Minute},
   949  								},
   950  							},
   951  							NodeStartupTimeout: &metav1.Duration{
   952  								Duration: time.Duration(6000000000000)}}).
   953  						Build()).
   954  				Build(),
   955  		},
   956  		{
   957  			name: "create fail if MachineDeployment MachineHealthCheck NodeStartUpTimeout is too short",
   958  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   959  				WithInfrastructureClusterTemplate(
   960  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   961  				WithControlPlaneTemplate(
   962  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   963  						Build()).
   964  				WithWorkerMachineDeploymentClasses(
   965  					*builder.MachineDeploymentClass("aa").
   966  						WithInfrastructureTemplate(
   967  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
   968  						WithBootstrapTemplate(
   969  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
   970  						WithMachineHealthCheckClass(&clusterv1.MachineHealthCheckClass{
   971  							UnhealthyConditions: []clusterv1.UnhealthyCondition{
   972  								{
   973  									Type:    corev1.NodeReady,
   974  									Status:  corev1.ConditionUnknown,
   975  									Timeout: metav1.Duration{Duration: 5 * time.Minute},
   976  								},
   977  							},
   978  							NodeStartupTimeout: &metav1.Duration{
   979  								// nodeStartupTimeout is too short here - 600ns.
   980  								Duration: time.Duration(600)}}).
   981  						Build()).
   982  				Build(),
   983  			expectErr: true,
   984  		},
   985  		{
   986  			name: "create fail if MachineDeployment MachineHealthCheck does not define UnhealthyConditions",
   987  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
   988  				WithInfrastructureClusterTemplate(
   989  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
   990  				WithControlPlaneTemplate(
   991  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
   992  						Build()).
   993  				WithWorkerMachineDeploymentClasses(
   994  					*builder.MachineDeploymentClass("aa").
   995  						WithInfrastructureTemplate(
   996  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
   997  						WithBootstrapTemplate(
   998  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
   999  						WithMachineHealthCheckClass(&clusterv1.MachineHealthCheckClass{
  1000  							NodeStartupTimeout: &metav1.Duration{
  1001  								Duration: time.Duration(6000000000000)}}).
  1002  						Build()).
  1003  				Build(),
  1004  			expectErr: true,
  1005  		},
  1006  
  1007  		/*
  1008  			UPDATE Tests
  1009  		*/
  1010  
  1011  		{
  1012  			name: "update pass in case of no changes",
  1013  			old: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1014  				WithInfrastructureClusterTemplate(
  1015  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1016  				WithControlPlaneTemplate(
  1017  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1018  						Build()).
  1019  				WithControlPlaneInfrastructureMachineTemplate(
  1020  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1021  						Build()).
  1022  				WithWorkerMachineDeploymentClasses(
  1023  					*builder.MachineDeploymentClass("aa").
  1024  						WithInfrastructureTemplate(
  1025  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1026  						WithBootstrapTemplate(
  1027  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1028  						Build()).
  1029  				WithWorkerMachinePoolClasses(
  1030  					*builder.MachinePoolClass("aa").
  1031  						WithInfrastructureTemplate(
  1032  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1033  						WithBootstrapTemplate(
  1034  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1035  						Build()).
  1036  				Build(),
  1037  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1038  				WithInfrastructureClusterTemplate(
  1039  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1040  				WithControlPlaneTemplate(
  1041  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1042  						Build()).
  1043  				WithControlPlaneInfrastructureMachineTemplate(
  1044  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1045  						Build()).
  1046  				WithWorkerMachineDeploymentClasses(
  1047  					*builder.MachineDeploymentClass("aa").
  1048  						WithInfrastructureTemplate(
  1049  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1050  						WithBootstrapTemplate(
  1051  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1052  						Build()).
  1053  				WithWorkerMachinePoolClasses(
  1054  					*builder.MachinePoolClass("aa").
  1055  						WithInfrastructureTemplate(
  1056  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1057  						WithBootstrapTemplate(
  1058  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1059  						Build()).
  1060  				Build(),
  1061  			expectErr: false,
  1062  		},
  1063  		{
  1064  			name: "update pass if infrastructureCluster changes in a compatible way",
  1065  			old: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1066  				WithInfrastructureClusterTemplate(
  1067  					refToUnstructured(ref)).
  1068  				WithControlPlaneTemplate(
  1069  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1070  						Build()).
  1071  				WithControlPlaneInfrastructureMachineTemplate(
  1072  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1073  						Build()).
  1074  				WithWorkerMachineDeploymentClasses(
  1075  					*builder.MachineDeploymentClass("aa").
  1076  						WithInfrastructureTemplate(
  1077  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1078  						WithBootstrapTemplate(
  1079  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1080  						Build()).
  1081  				WithWorkerMachinePoolClasses(
  1082  					*builder.MachinePoolClass("aa").
  1083  						WithInfrastructureTemplate(
  1084  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1085  						WithBootstrapTemplate(
  1086  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1087  						Build()).
  1088  				Build(),
  1089  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1090  				WithInfrastructureClusterTemplate(
  1091  					refToUnstructured(compatibleRef)).
  1092  				WithControlPlaneTemplate(
  1093  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1094  						Build()).
  1095  				WithControlPlaneInfrastructureMachineTemplate(
  1096  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1097  						Build()).
  1098  				WithWorkerMachineDeploymentClasses(
  1099  					*builder.MachineDeploymentClass("aa").
  1100  						WithInfrastructureTemplate(
  1101  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1102  						WithBootstrapTemplate(
  1103  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1104  						Build()).
  1105  				WithWorkerMachinePoolClasses(
  1106  					*builder.MachinePoolClass("aa").
  1107  						WithInfrastructureTemplate(
  1108  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1109  						WithBootstrapTemplate(
  1110  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1111  						Build()).
  1112  				Build(),
  1113  			expectErr: false,
  1114  		},
  1115  		{
  1116  			name: "update fails if infrastructureCluster changes in an incompatible way",
  1117  			old: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1118  				WithInfrastructureClusterTemplate(
  1119  					refToUnstructured(ref)).
  1120  				WithControlPlaneTemplate(
  1121  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1122  						Build()).
  1123  				WithControlPlaneInfrastructureMachineTemplate(
  1124  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1125  						Build()).
  1126  				WithWorkerMachineDeploymentClasses(
  1127  					*builder.MachineDeploymentClass("aa").
  1128  						WithInfrastructureTemplate(
  1129  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1130  						WithBootstrapTemplate(
  1131  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1132  						Build()).
  1133  				Build(),
  1134  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1135  				WithInfrastructureClusterTemplate(
  1136  					refToUnstructured(incompatibleRef)).
  1137  				WithControlPlaneTemplate(
  1138  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1139  						Build()).
  1140  				WithControlPlaneInfrastructureMachineTemplate(
  1141  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1142  						Build()).
  1143  				WithWorkerMachineDeploymentClasses(
  1144  					*builder.MachineDeploymentClass("aa").
  1145  						WithInfrastructureTemplate(
  1146  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1147  						WithBootstrapTemplate(
  1148  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1149  						Build()).
  1150  				Build(),
  1151  			expectErr: true,
  1152  		},
  1153  		{
  1154  			name: "update pass if controlPlane changes in a compatible way",
  1155  			old: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1156  				WithInfrastructureClusterTemplate(
  1157  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1158  				WithControlPlaneTemplate(
  1159  					refToUnstructured(ref)).
  1160  				WithControlPlaneInfrastructureMachineTemplate(
  1161  					refToUnstructured(ref)).
  1162  				WithWorkerMachineDeploymentClasses(
  1163  					*builder.MachineDeploymentClass("aa").
  1164  						WithInfrastructureTemplate(
  1165  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1166  						WithBootstrapTemplate(
  1167  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1168  						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  				Build(),
  1177  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1178  				WithInfrastructureClusterTemplate(
  1179  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1180  				WithControlPlaneTemplate(
  1181  					refToUnstructured(compatibleRef)).
  1182  				WithControlPlaneInfrastructureMachineTemplate(
  1183  					refToUnstructured(compatibleRef)).
  1184  				WithWorkerMachineDeploymentClasses(
  1185  					*builder.MachineDeploymentClass("aa").
  1186  						WithInfrastructureTemplate(
  1187  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1188  						WithBootstrapTemplate(
  1189  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1190  						Build()).
  1191  				WithWorkerMachinePoolClasses(
  1192  					*builder.MachinePoolClass("aa").
  1193  						WithInfrastructureTemplate(
  1194  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1195  						WithBootstrapTemplate(
  1196  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1197  						Build()).
  1198  				Build(),
  1199  			expectErr: false,
  1200  		},
  1201  		{
  1202  			name: "update fails if controlPlane changes in an incompatible way (controlPlane template)",
  1203  			old: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1204  				WithInfrastructureClusterTemplate(
  1205  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1206  				WithControlPlaneTemplate(
  1207  					refToUnstructured(ref)).
  1208  				WithControlPlaneInfrastructureMachineTemplate(
  1209  					refToUnstructured(ref)).
  1210  				WithWorkerMachineDeploymentClasses(
  1211  					*builder.MachineDeploymentClass("aa").
  1212  						WithInfrastructureTemplate(
  1213  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1214  						WithBootstrapTemplate(
  1215  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1216  						Build()).
  1217  				WithWorkerMachinePoolClasses(
  1218  					*builder.MachinePoolClass("aa").
  1219  						WithInfrastructureTemplate(
  1220  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1221  						WithBootstrapTemplate(
  1222  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1223  						Build()).
  1224  				Build(),
  1225  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1226  				WithInfrastructureClusterTemplate(
  1227  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1228  				WithControlPlaneTemplate(
  1229  					refToUnstructured(incompatibleRef)).
  1230  				WithControlPlaneInfrastructureMachineTemplate(
  1231  					refToUnstructured(compatibleRef)).
  1232  				WithWorkerMachineDeploymentClasses(
  1233  					*builder.MachineDeploymentClass("aa").
  1234  						WithInfrastructureTemplate(
  1235  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1236  						WithBootstrapTemplate(
  1237  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1238  						Build()).
  1239  				WithWorkerMachinePoolClasses(
  1240  					*builder.MachinePoolClass("aa").
  1241  						WithInfrastructureTemplate(
  1242  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1243  						WithBootstrapTemplate(
  1244  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1245  						Build()).
  1246  				Build(),
  1247  			expectErr: true,
  1248  		},
  1249  		{
  1250  			name: "update fails if controlPlane changes in an incompatible way (controlPlane infrastructureMachineTemplate)",
  1251  			old: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1252  				WithInfrastructureClusterTemplate(
  1253  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1254  				WithControlPlaneTemplate(
  1255  					refToUnstructured(ref)).
  1256  				WithControlPlaneInfrastructureMachineTemplate(
  1257  					refToUnstructured(ref)).
  1258  				WithWorkerMachineDeploymentClasses(
  1259  					*builder.MachineDeploymentClass("aa").
  1260  						WithInfrastructureTemplate(
  1261  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1262  						WithBootstrapTemplate(
  1263  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1264  						Build()).
  1265  				WithWorkerMachinePoolClasses(
  1266  					*builder.MachinePoolClass("aa").
  1267  						WithInfrastructureTemplate(
  1268  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1269  						WithBootstrapTemplate(
  1270  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1271  						Build()).
  1272  				Build(),
  1273  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1274  				WithInfrastructureClusterTemplate(
  1275  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1276  				WithControlPlaneTemplate(
  1277  					refToUnstructured(compatibleRef)).
  1278  				WithControlPlaneInfrastructureMachineTemplate(
  1279  					refToUnstructured(incompatibleRef)).
  1280  				WithWorkerMachineDeploymentClasses(
  1281  					*builder.MachineDeploymentClass("aa").
  1282  						WithInfrastructureTemplate(
  1283  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1284  						WithBootstrapTemplate(
  1285  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1286  						Build()).
  1287  				WithWorkerMachinePoolClasses(
  1288  					*builder.MachinePoolClass("aa").
  1289  						WithInfrastructureTemplate(
  1290  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1291  						WithBootstrapTemplate(
  1292  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1293  						Build()).
  1294  				Build(),
  1295  			expectErr: true,
  1296  		},
  1297  		{
  1298  			name: "update pass if a machine deployment and machine pool changes in a compatible way",
  1299  			old: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1300  				WithInfrastructureClusterTemplate(
  1301  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1302  				WithControlPlaneTemplate(
  1303  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1304  						Build()).
  1305  				WithControlPlaneInfrastructureMachineTemplate(
  1306  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1307  						Build()).
  1308  				WithWorkerMachineDeploymentClasses(
  1309  					*builder.MachineDeploymentClass("aa").
  1310  						WithInfrastructureTemplate(
  1311  							refToUnstructured(ref)).
  1312  						WithBootstrapTemplate(
  1313  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1314  						Build()).
  1315  				WithWorkerMachinePoolClasses(
  1316  					*builder.MachinePoolClass("aa").
  1317  						WithInfrastructureTemplate(
  1318  							refToUnstructured(ref)).
  1319  						WithBootstrapTemplate(
  1320  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1321  						Build()).
  1322  				Build(),
  1323  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1324  				WithInfrastructureClusterTemplate(
  1325  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1326  				WithControlPlaneTemplate(
  1327  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1328  						Build()).
  1329  				WithControlPlaneInfrastructureMachineTemplate(
  1330  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1331  						Build()).
  1332  				WithWorkerMachineDeploymentClasses(
  1333  					*builder.MachineDeploymentClass("aa").
  1334  						WithInfrastructureTemplate(
  1335  							refToUnstructured(compatibleRef)).
  1336  						WithBootstrapTemplate(
  1337  							refToUnstructured(incompatibleRef)).
  1338  						Build()).
  1339  				WithWorkerMachinePoolClasses(
  1340  					*builder.MachinePoolClass("aa").
  1341  						WithInfrastructureTemplate(
  1342  							refToUnstructured(compatibleRef)).
  1343  						WithBootstrapTemplate(
  1344  							refToUnstructured(incompatibleRef)).
  1345  						Build()).
  1346  				Build(),
  1347  			expectErr: false,
  1348  		},
  1349  		{
  1350  			name: "update fails a machine deployment changes in an incompatible way",
  1351  			old: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1352  				WithInfrastructureClusterTemplate(
  1353  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1354  				WithControlPlaneTemplate(
  1355  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1356  						Build()).
  1357  				WithControlPlaneInfrastructureMachineTemplate(
  1358  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1359  						Build()).
  1360  				WithWorkerMachineDeploymentClasses(
  1361  					*builder.MachineDeploymentClass("aa").
  1362  						WithInfrastructureTemplate(
  1363  							refToUnstructured(ref)).
  1364  						WithBootstrapTemplate(
  1365  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1366  						Build()).
  1367  				Build(),
  1368  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1369  				WithInfrastructureClusterTemplate(
  1370  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1371  				WithControlPlaneTemplate(
  1372  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1373  						Build()).
  1374  				WithControlPlaneInfrastructureMachineTemplate(
  1375  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1376  						Build()).
  1377  				WithWorkerMachineDeploymentClasses(
  1378  					*builder.MachineDeploymentClass("aa").
  1379  						WithInfrastructureTemplate(
  1380  							refToUnstructured(incompatibleRef)).
  1381  						WithBootstrapTemplate(
  1382  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1383  						Build()).
  1384  				Build(),
  1385  			expectErr: true,
  1386  		},
  1387  		{
  1388  			name: "update fails a machine pool changes in an incompatible way",
  1389  			old: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1390  				WithInfrastructureClusterTemplate(
  1391  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1392  				WithControlPlaneTemplate(
  1393  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1394  						Build()).
  1395  				WithControlPlaneInfrastructureMachineTemplate(
  1396  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1397  						Build()).
  1398  				WithWorkerMachinePoolClasses(
  1399  					*builder.MachinePoolClass("aa").
  1400  						WithInfrastructureTemplate(
  1401  							refToUnstructured(ref)).
  1402  						WithBootstrapTemplate(
  1403  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1404  						Build()).
  1405  				Build(),
  1406  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1407  				WithInfrastructureClusterTemplate(
  1408  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1409  				WithControlPlaneTemplate(
  1410  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1411  						Build()).
  1412  				WithControlPlaneInfrastructureMachineTemplate(
  1413  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1414  						Build()).
  1415  				WithWorkerMachinePoolClasses(
  1416  					*builder.MachinePoolClass("aa").
  1417  						WithInfrastructureTemplate(
  1418  							refToUnstructured(incompatibleRef)).
  1419  						WithBootstrapTemplate(
  1420  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1421  						Build()).
  1422  				Build(),
  1423  			expectErr: true,
  1424  		},
  1425  		{
  1426  			name: "update pass if a machine deployment or machine pool class gets added",
  1427  			old: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1428  				WithInfrastructureClusterTemplate(
  1429  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1430  				WithControlPlaneTemplate(
  1431  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1432  						Build()).
  1433  				WithControlPlaneInfrastructureMachineTemplate(
  1434  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1435  						Build()).
  1436  				WithWorkerMachineDeploymentClasses(
  1437  					*builder.MachineDeploymentClass("aa").
  1438  						WithInfrastructureTemplate(
  1439  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1440  						WithBootstrapTemplate(
  1441  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1442  						Build()).
  1443  				WithWorkerMachinePoolClasses(
  1444  					*builder.MachinePoolClass("aa").
  1445  						WithInfrastructureTemplate(
  1446  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1447  						WithBootstrapTemplate(
  1448  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1449  						Build()).
  1450  				Build(),
  1451  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1452  				WithInfrastructureClusterTemplate(
  1453  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1454  				WithControlPlaneTemplate(
  1455  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1456  						Build()).
  1457  				WithControlPlaneInfrastructureMachineTemplate(
  1458  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1459  						Build()).
  1460  				WithWorkerMachineDeploymentClasses(
  1461  					*builder.MachineDeploymentClass("aa").
  1462  						WithInfrastructureTemplate(
  1463  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1464  						WithBootstrapTemplate(
  1465  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1466  						Build(),
  1467  					*builder.MachineDeploymentClass("BB").
  1468  						WithInfrastructureTemplate(
  1469  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1470  						WithBootstrapTemplate(
  1471  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1472  						Build()).
  1473  				WithWorkerMachinePoolClasses(
  1474  					*builder.MachinePoolClass("aa").
  1475  						WithInfrastructureTemplate(
  1476  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1477  						WithBootstrapTemplate(
  1478  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1479  						Build(),
  1480  					*builder.MachinePoolClass("BB").
  1481  						WithInfrastructureTemplate(
  1482  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1483  						WithBootstrapTemplate(
  1484  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1485  						Build()).
  1486  				Build(),
  1487  			expectErr: false,
  1488  		},
  1489  		{
  1490  			name: "update fails if a duplicated machine deployment class gets added",
  1491  			old: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1492  				WithInfrastructureClusterTemplate(
  1493  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1494  				WithControlPlaneTemplate(
  1495  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1496  						Build()).
  1497  				WithControlPlaneInfrastructureMachineTemplate(
  1498  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1499  						Build()).
  1500  				WithWorkerMachineDeploymentClasses(
  1501  					*builder.MachineDeploymentClass("aa").
  1502  						WithInfrastructureTemplate(
  1503  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1504  						WithBootstrapTemplate(
  1505  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1506  						Build()).
  1507  				Build(),
  1508  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1509  				WithInfrastructureClusterTemplate(
  1510  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1511  				WithControlPlaneTemplate(
  1512  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1513  						Build()).
  1514  				WithControlPlaneInfrastructureMachineTemplate(
  1515  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1516  						Build()).
  1517  				WithWorkerMachineDeploymentClasses(
  1518  					*builder.MachineDeploymentClass("aa").
  1519  						WithInfrastructureTemplate(
  1520  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1521  						WithBootstrapTemplate(
  1522  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).Build(),
  1523  					*builder.MachineDeploymentClass("aa").
  1524  						WithInfrastructureTemplate(
  1525  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1526  						WithBootstrapTemplate(
  1527  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1528  						Build()).
  1529  				Build(),
  1530  			expectErr: true,
  1531  		},
  1532  		{
  1533  			name: "update fails if a duplicated machine pool class gets added",
  1534  			old: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1535  				WithInfrastructureClusterTemplate(
  1536  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1537  				WithControlPlaneTemplate(
  1538  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1539  						Build()).
  1540  				WithControlPlaneInfrastructureMachineTemplate(
  1541  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1542  						Build()).
  1543  				WithWorkerMachinePoolClasses(
  1544  					*builder.MachinePoolClass("aa").
  1545  						WithInfrastructureTemplate(
  1546  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1547  						WithBootstrapTemplate(
  1548  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1549  						Build()).
  1550  				Build(),
  1551  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1552  				WithInfrastructureClusterTemplate(
  1553  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1554  				WithControlPlaneTemplate(
  1555  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1556  						Build()).
  1557  				WithControlPlaneInfrastructureMachineTemplate(
  1558  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1559  						Build()).
  1560  				WithWorkerMachinePoolClasses(
  1561  					*builder.MachinePoolClass("aa").
  1562  						WithInfrastructureTemplate(
  1563  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1564  						WithBootstrapTemplate(
  1565  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).Build(),
  1566  					*builder.MachinePoolClass("aa").
  1567  						WithInfrastructureTemplate(
  1568  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1569  						WithBootstrapTemplate(
  1570  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1571  						Build()).
  1572  				Build(),
  1573  			expectErr: true,
  1574  		},
  1575  		{
  1576  			name: "should return error for invalid machine deployment labels and annotations",
  1577  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1578  				WithInfrastructureClusterTemplate(
  1579  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1580  				WithControlPlaneTemplate(
  1581  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1582  						Build()).
  1583  				WithControlPlaneInfrastructureMachineTemplate(
  1584  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1585  						Build()).
  1586  				WithWorkerMachineDeploymentClasses(
  1587  					*builder.MachineDeploymentClass("aa").
  1588  						WithInfrastructureTemplate(
  1589  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1590  						WithBootstrapTemplate(
  1591  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1592  						WithLabels(invalidLabels()).
  1593  						WithAnnotations(invalidAnnotations()).
  1594  						Build()).
  1595  				WithControlPlaneMetadata(invalidLabels(), invalidAnnotations()).
  1596  				Build(),
  1597  			expectErr: true,
  1598  		},
  1599  		{
  1600  			name: "should return error for invalid machine pool labels and annotations",
  1601  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1602  				WithInfrastructureClusterTemplate(
  1603  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1604  				WithControlPlaneTemplate(
  1605  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1606  						Build()).
  1607  				WithControlPlaneInfrastructureMachineTemplate(
  1608  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1609  						Build()).
  1610  				WithWorkerMachinePoolClasses(
  1611  					*builder.MachinePoolClass("aa").
  1612  						WithInfrastructureTemplate(
  1613  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1614  						WithBootstrapTemplate(
  1615  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1616  						WithLabels(invalidLabels()).
  1617  						WithAnnotations(invalidAnnotations()).
  1618  						Build()).
  1619  				WithControlPlaneMetadata(invalidLabels(), invalidAnnotations()).
  1620  				Build(),
  1621  			expectErr: true,
  1622  		},
  1623  		{
  1624  			name: "should not return error for valid namingStrategy.template",
  1625  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1626  				WithInfrastructureClusterTemplate(
  1627  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1628  				WithControlPlaneTemplate(
  1629  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1630  						Build()).
  1631  				WithControlPlaneNamingStrategy(&clusterv1.ControlPlaneClassNamingStrategy{Template: ptr.To("{{ .cluster.name }}-cp-{{ .random }}")}).
  1632  				WithControlPlaneInfrastructureMachineTemplate(
  1633  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1634  						Build()).
  1635  				WithWorkerMachineDeploymentClasses(
  1636  					*builder.MachineDeploymentClass("aa").
  1637  						WithInfrastructureTemplate(
  1638  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1639  						WithBootstrapTemplate(
  1640  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1641  						WithNamingStrategy(&clusterv1.MachineDeploymentClassNamingStrategy{Template: ptr.To("{{ .cluster.name }}-md-{{ .machineDeployment.topologyName }}-{{ .random }}")}).
  1642  						Build()).
  1643  				WithWorkerMachinePoolClasses(
  1644  					*builder.MachinePoolClass("bb").
  1645  						WithInfrastructureTemplate(
  1646  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra2").Build()).
  1647  						WithBootstrapTemplate(
  1648  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap2").Build()).
  1649  						WithNamingStrategy(&clusterv1.MachinePoolClassNamingStrategy{Template: ptr.To("{{ .cluster.name }}-md-{{ .machinePool.topologyName }}-{{ .random }}")}).
  1650  						Build()).
  1651  				Build(),
  1652  			expectErr: false,
  1653  		},
  1654  		{
  1655  			name: "should return error for invalid ControlPlane namingStrategy.template",
  1656  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1657  				WithInfrastructureClusterTemplate(
  1658  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1659  				WithControlPlaneTemplate(
  1660  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1661  						Build()).
  1662  				WithControlPlaneNamingStrategy(&clusterv1.ControlPlaneClassNamingStrategy{Template: ptr.To("template-cp-{{ .invalidkey }}")}).
  1663  				WithControlPlaneInfrastructureMachineTemplate(
  1664  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1665  						Build()).
  1666  				Build(),
  1667  			expectErr: true,
  1668  		},
  1669  		{
  1670  			name: "should return error for ControlPlane namingStrategy.template when the generated name does not conform to RFC 1123",
  1671  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1672  				WithInfrastructureClusterTemplate(
  1673  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1674  				WithControlPlaneTemplate(
  1675  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1676  						Build()).
  1677  				WithControlPlaneNamingStrategy(&clusterv1.ControlPlaneClassNamingStrategy{Template: ptr.To("template-cp-{{ .cluster.name }}-")}).
  1678  				WithControlPlaneInfrastructureMachineTemplate(
  1679  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1680  						Build()).
  1681  				Build(),
  1682  			expectErr: true,
  1683  		},
  1684  		{
  1685  			name: "should return error for invalid MachineDeployment namingStrategy.template",
  1686  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1687  				WithInfrastructureClusterTemplate(
  1688  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1689  				WithControlPlaneTemplate(
  1690  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1691  						Build()).
  1692  				WithControlPlaneInfrastructureMachineTemplate(
  1693  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1694  						Build()).
  1695  				WithWorkerMachineDeploymentClasses(
  1696  					*builder.MachineDeploymentClass("aa").
  1697  						WithInfrastructureTemplate(
  1698  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1699  						WithBootstrapTemplate(
  1700  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1701  						WithNamingStrategy(&clusterv1.MachineDeploymentClassNamingStrategy{Template: ptr.To("template-md-{{ .cluster.name")}).
  1702  						Build()).
  1703  				Build(),
  1704  			expectErr: true,
  1705  		},
  1706  		{
  1707  			name: "should return error for invalid MachineDeployment namingStrategy.template when the generated name does not conform to RFC 1123",
  1708  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1709  				WithInfrastructureClusterTemplate(
  1710  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1711  				WithControlPlaneTemplate(
  1712  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1713  						Build()).
  1714  				WithControlPlaneInfrastructureMachineTemplate(
  1715  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1716  						Build()).
  1717  				WithWorkerMachineDeploymentClasses(
  1718  					*builder.MachineDeploymentClass("aa").
  1719  						WithInfrastructureTemplate(
  1720  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1721  						WithBootstrapTemplate(
  1722  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1723  						WithNamingStrategy(&clusterv1.MachineDeploymentClassNamingStrategy{Template: ptr.To("template-md-{{ .cluster.name }}-")}).
  1724  						Build()).
  1725  				Build(),
  1726  			expectErr: true,
  1727  		},
  1728  		{
  1729  			name: "should return error for invalid MachinePool namingStrategy.template",
  1730  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1731  				WithInfrastructureClusterTemplate(
  1732  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1733  				WithControlPlaneTemplate(
  1734  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1735  						Build()).
  1736  				WithControlPlaneInfrastructureMachineTemplate(
  1737  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1738  						Build()).
  1739  				WithWorkerMachinePoolClasses(
  1740  					*builder.MachinePoolClass("bb").
  1741  						WithInfrastructureTemplate(
  1742  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra2").Build()).
  1743  						WithBootstrapTemplate(
  1744  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap2").Build()).
  1745  						WithNamingStrategy(&clusterv1.MachinePoolClassNamingStrategy{Template: ptr.To("template-mp-{{ .cluster.name")}).
  1746  						Build()).
  1747  				Build(),
  1748  			expectErr: true,
  1749  		},
  1750  		{
  1751  			name: "should return error for invalid MachinePool namingStrategy.template when the generated name does not conform to RFC 1123",
  1752  			in: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1753  				WithInfrastructureClusterTemplate(
  1754  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1755  				WithControlPlaneTemplate(
  1756  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1757  						Build()).
  1758  				WithControlPlaneInfrastructureMachineTemplate(
  1759  					builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "cpInfra1").
  1760  						Build()).
  1761  				WithWorkerMachinePoolClasses(
  1762  					*builder.MachinePoolClass("bb").
  1763  						WithInfrastructureTemplate(
  1764  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra2").Build()).
  1765  						WithBootstrapTemplate(
  1766  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap2").Build()).
  1767  						WithNamingStrategy(&clusterv1.MachinePoolClassNamingStrategy{Template: ptr.To("template-mp-{{ .cluster.name }}-")}).
  1768  						Build()).
  1769  				Build(),
  1770  			expectErr: true,
  1771  		},
  1772  	}
  1773  
  1774  	for _, tt := range tests {
  1775  		t.Run(tt.name, func(t *testing.T) {
  1776  			g := NewWithT(t)
  1777  
  1778  			// Sets up the fakeClient for the test case.
  1779  			fakeClient := fake.NewClientBuilder().
  1780  				WithScheme(fakeScheme).
  1781  				WithIndex(&clusterv1.Cluster{}, index.ClusterClassNameField, index.ClusterByClusterClassClassName).
  1782  				Build()
  1783  
  1784  			// Create the webhook and add the fakeClient as its client.
  1785  			webhook := &ClusterClass{Client: fakeClient}
  1786  			err := webhook.validate(ctx, tt.old, tt.in)
  1787  			if tt.expectErr {
  1788  				g.Expect(err).To(HaveOccurred())
  1789  				return
  1790  			}
  1791  			g.Expect(err).ToNot(HaveOccurred())
  1792  		})
  1793  	}
  1794  }
  1795  
  1796  func TestClusterClassValidationWithClusterAwareChecks(t *testing.T) {
  1797  	// NOTE: ClusterTopology feature flag is disabled by default, thus preventing to create or update ClusterClasses.
  1798  	// Enabling the feature flag temporarily for this test.
  1799  	defer utilfeature.SetFeatureGateDuringTest(t, feature.Gates, feature.ClusterTopology, true)()
  1800  
  1801  	tests := []struct {
  1802  		name            string
  1803  		oldClusterClass *clusterv1.ClusterClass
  1804  		newClusterClass *clusterv1.ClusterClass
  1805  		clusters        []client.Object
  1806  		expectErr       bool
  1807  	}{
  1808  		{
  1809  			name: "pass if a MachineDeploymentClass or MachinePoolClass not in use gets removed",
  1810  			clusters: []client.Object{
  1811  				builder.Cluster(metav1.NamespaceDefault, "cluster1").
  1812  					WithLabels(map[string]string{clusterv1.ClusterTopologyOwnedLabel: ""}).
  1813  					WithTopology(
  1814  						builder.ClusterTopology().
  1815  							WithClass("class1").
  1816  							WithMachineDeployment(
  1817  								builder.MachineDeploymentTopology("workers1").
  1818  									WithClass("bb").
  1819  									Build(),
  1820  							).
  1821  							Build()).
  1822  					Build(),
  1823  			},
  1824  			oldClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1825  				WithInfrastructureClusterTemplate(
  1826  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()).
  1827  				WithControlPlaneTemplate(
  1828  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1829  						Build()).
  1830  				WithWorkerMachineDeploymentClasses(
  1831  					*builder.MachineDeploymentClass("aa").
  1832  						WithInfrastructureTemplate(
  1833  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1834  						WithBootstrapTemplate(
  1835  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1836  						Build(),
  1837  					*builder.MachineDeploymentClass("bb").
  1838  						WithInfrastructureTemplate(
  1839  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1840  						WithBootstrapTemplate(
  1841  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1842  						Build()).
  1843  				WithWorkerMachinePoolClasses(
  1844  					*builder.MachinePoolClass("aa").
  1845  						WithInfrastructureTemplate(
  1846  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1847  						WithBootstrapTemplate(
  1848  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1849  						Build(),
  1850  					*builder.MachinePoolClass("bb").
  1851  						WithInfrastructureTemplate(
  1852  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1853  						WithBootstrapTemplate(
  1854  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1855  						Build()).
  1856  				Build(),
  1857  			newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1858  				WithInfrastructureClusterTemplate(
  1859  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()).
  1860  				WithControlPlaneTemplate(
  1861  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1862  						Build()).
  1863  				WithWorkerMachineDeploymentClasses(
  1864  					*builder.MachineDeploymentClass("bb").
  1865  						WithInfrastructureTemplate(
  1866  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1867  						WithBootstrapTemplate(
  1868  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1869  						Build()).
  1870  				WithWorkerMachinePoolClasses(
  1871  					*builder.MachinePoolClass("bb").
  1872  						WithInfrastructureTemplate(
  1873  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1874  						WithBootstrapTemplate(
  1875  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1876  						Build()).
  1877  				Build(),
  1878  			expectErr: false,
  1879  		},
  1880  		{
  1881  			name: "error if a MachineDeploymentClass in use gets removed",
  1882  			clusters: []client.Object{
  1883  				builder.Cluster(metav1.NamespaceDefault, "cluster1").
  1884  					WithLabels(map[string]string{clusterv1.ClusterTopologyOwnedLabel: ""}).
  1885  					WithTopology(
  1886  						builder.ClusterTopology().
  1887  							WithClass("class1").
  1888  							WithMachineDeployment(
  1889  								builder.MachineDeploymentTopology("workers1").
  1890  									WithClass("bb").
  1891  									Build(),
  1892  							).
  1893  							Build()).
  1894  					Build(),
  1895  			},
  1896  			oldClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1897  				WithInfrastructureClusterTemplate(
  1898  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()).
  1899  				WithControlPlaneTemplate(
  1900  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1901  						Build()).
  1902  				WithWorkerMachineDeploymentClasses(
  1903  					*builder.MachineDeploymentClass("aa").
  1904  						WithInfrastructureTemplate(
  1905  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1906  						WithBootstrapTemplate(
  1907  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1908  						Build(),
  1909  					*builder.MachineDeploymentClass("bb").
  1910  						WithInfrastructureTemplate(
  1911  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1912  						WithBootstrapTemplate(
  1913  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1914  						Build()).
  1915  				Build(),
  1916  			newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1917  				WithInfrastructureClusterTemplate(
  1918  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()).
  1919  				WithControlPlaneTemplate(
  1920  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1921  						Build()).
  1922  				WithWorkerMachineDeploymentClasses(
  1923  					*builder.MachineDeploymentClass("aa").
  1924  						WithInfrastructureTemplate(
  1925  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1926  						WithBootstrapTemplate(
  1927  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1928  						Build()).
  1929  				Build(),
  1930  			expectErr: true,
  1931  		},
  1932  		{
  1933  			name: "error if a MachinePoolClass in use gets removed",
  1934  			clusters: []client.Object{
  1935  				builder.Cluster(metav1.NamespaceDefault, "cluster1").
  1936  					WithLabels(map[string]string{clusterv1.ClusterTopologyOwnedLabel: ""}).
  1937  					WithTopology(
  1938  						builder.ClusterTopology().
  1939  							WithClass("class1").
  1940  							WithMachinePool(
  1941  								builder.MachinePoolTopology("workers1").
  1942  									WithClass("bb").
  1943  									Build(),
  1944  							).
  1945  							Build()).
  1946  					Build(),
  1947  			},
  1948  			oldClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1949  				WithInfrastructureClusterTemplate(
  1950  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()).
  1951  				WithControlPlaneTemplate(
  1952  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1953  						Build()).
  1954  				WithWorkerMachinePoolClasses(
  1955  					*builder.MachinePoolClass("aa").
  1956  						WithInfrastructureTemplate(
  1957  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1958  						WithBootstrapTemplate(
  1959  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1960  						Build(),
  1961  					*builder.MachinePoolClass("bb").
  1962  						WithInfrastructureTemplate(
  1963  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1964  						WithBootstrapTemplate(
  1965  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1966  						Build()).
  1967  				Build(),
  1968  			newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  1969  				WithInfrastructureClusterTemplate(
  1970  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()).
  1971  				WithControlPlaneTemplate(
  1972  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  1973  						Build()).
  1974  				WithWorkerMachinePoolClasses(
  1975  					*builder.MachinePoolClass("aa").
  1976  						WithInfrastructureTemplate(
  1977  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  1978  						WithBootstrapTemplate(
  1979  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  1980  						Build()).
  1981  				Build(),
  1982  			expectErr: true,
  1983  		},
  1984  		{
  1985  			name: "error if many MachineDeploymentClasses, used in multiple Clusters using the modified ClusterClass, are removed",
  1986  			clusters: []client.Object{
  1987  				builder.Cluster(metav1.NamespaceDefault, "cluster1").
  1988  					WithLabels(map[string]string{clusterv1.ClusterTopologyOwnedLabel: ""}).
  1989  					WithTopology(
  1990  						builder.ClusterTopology().
  1991  							WithClass("class1").
  1992  							WithMachineDeployment(
  1993  								builder.MachineDeploymentTopology("workers1").
  1994  									WithClass("bb").
  1995  									Build(),
  1996  							).
  1997  							WithMachineDeployment(
  1998  								builder.MachineDeploymentTopology("workers2").
  1999  									WithClass("aa").
  2000  									Build(),
  2001  							).
  2002  							Build()).
  2003  					Build(),
  2004  				builder.Cluster(metav1.NamespaceDefault, "cluster2").
  2005  					WithLabels(map[string]string{clusterv1.ClusterTopologyOwnedLabel: ""}).
  2006  					WithTopology(
  2007  						builder.ClusterTopology().
  2008  							WithClass("class1").
  2009  							WithMachineDeployment(
  2010  								builder.MachineDeploymentTopology("workers1").
  2011  									WithClass("aa").
  2012  									Build(),
  2013  							).
  2014  							WithMachineDeployment(
  2015  								builder.MachineDeploymentTopology("workers2").
  2016  									WithClass("aa").
  2017  									Build(),
  2018  							).
  2019  							Build()).
  2020  					Build(),
  2021  				builder.Cluster(metav1.NamespaceDefault, "cluster3").
  2022  					WithLabels(map[string]string{clusterv1.ClusterTopologyOwnedLabel: ""}).
  2023  					WithTopology(
  2024  						builder.ClusterTopology().
  2025  							WithClass("class1").
  2026  							WithMachineDeployment(
  2027  								builder.MachineDeploymentTopology("workers1").
  2028  									WithClass("bb").
  2029  									Build(),
  2030  							).
  2031  							Build()).
  2032  					Build(),
  2033  			},
  2034  			oldClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  2035  				WithInfrastructureClusterTemplate(
  2036  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()).
  2037  				WithControlPlaneTemplate(
  2038  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  2039  						Build()).
  2040  				WithWorkerMachineDeploymentClasses(
  2041  					*builder.MachineDeploymentClass("aa").
  2042  						WithInfrastructureTemplate(
  2043  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  2044  						WithBootstrapTemplate(
  2045  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  2046  						Build(),
  2047  					*builder.MachineDeploymentClass("bb").
  2048  						WithInfrastructureTemplate(
  2049  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  2050  						WithBootstrapTemplate(
  2051  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  2052  						Build()).
  2053  				Build(),
  2054  			newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  2055  				WithInfrastructureClusterTemplate(
  2056  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()).
  2057  				WithControlPlaneTemplate(
  2058  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  2059  						Build()).
  2060  				WithWorkerMachineDeploymentClasses(
  2061  					*builder.MachineDeploymentClass("bb").
  2062  						WithInfrastructureTemplate(
  2063  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  2064  						WithBootstrapTemplate(
  2065  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  2066  						Build()).
  2067  				Build(),
  2068  			expectErr: true,
  2069  		},
  2070  		{
  2071  			name: "error if many MachinePoolClasses, used in multiple Clusters using the modified ClusterClass, are removed",
  2072  			clusters: []client.Object{
  2073  				builder.Cluster(metav1.NamespaceDefault, "cluster1").
  2074  					WithLabels(map[string]string{clusterv1.ClusterTopologyOwnedLabel: ""}).
  2075  					WithTopology(
  2076  						builder.ClusterTopology().
  2077  							WithClass("class1").
  2078  							WithMachinePool(
  2079  								builder.MachinePoolTopology("workers1").
  2080  									WithClass("bb").
  2081  									Build(),
  2082  							).
  2083  							WithMachinePool(
  2084  								builder.MachinePoolTopology("workers2").
  2085  									WithClass("aa").
  2086  									Build(),
  2087  							).
  2088  							Build()).
  2089  					Build(),
  2090  				builder.Cluster(metav1.NamespaceDefault, "cluster2").
  2091  					WithLabels(map[string]string{clusterv1.ClusterTopologyOwnedLabel: ""}).
  2092  					WithTopology(
  2093  						builder.ClusterTopology().
  2094  							WithClass("class1").
  2095  							WithMachinePool(
  2096  								builder.MachinePoolTopology("workers1").
  2097  									WithClass("aa").
  2098  									Build(),
  2099  							).
  2100  							WithMachinePool(
  2101  								builder.MachinePoolTopology("workers2").
  2102  									WithClass("aa").
  2103  									Build(),
  2104  							).
  2105  							Build()).
  2106  					Build(),
  2107  				builder.Cluster(metav1.NamespaceDefault, "cluster3").
  2108  					WithLabels(map[string]string{clusterv1.ClusterTopologyOwnedLabel: ""}).
  2109  					WithTopology(
  2110  						builder.ClusterTopology().
  2111  							WithClass("class1").
  2112  							WithMachinePool(
  2113  								builder.MachinePoolTopology("workers1").
  2114  									WithClass("bb").
  2115  									Build(),
  2116  							).
  2117  							Build()).
  2118  					Build(),
  2119  			},
  2120  			oldClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  2121  				WithInfrastructureClusterTemplate(
  2122  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()).
  2123  				WithControlPlaneTemplate(
  2124  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  2125  						Build()).
  2126  				WithWorkerMachinePoolClasses(
  2127  					*builder.MachinePoolClass("aa").
  2128  						WithInfrastructureTemplate(
  2129  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  2130  						WithBootstrapTemplate(
  2131  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  2132  						Build(),
  2133  					*builder.MachinePoolClass("bb").
  2134  						WithInfrastructureTemplate(
  2135  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  2136  						WithBootstrapTemplate(
  2137  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  2138  						Build()).
  2139  				Build(),
  2140  			newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "class1").
  2141  				WithInfrastructureClusterTemplate(
  2142  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()).
  2143  				WithControlPlaneTemplate(
  2144  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  2145  						Build()).
  2146  				WithWorkerMachinePoolClasses(
  2147  					*builder.MachinePoolClass("bb").
  2148  						WithInfrastructureTemplate(
  2149  							builder.InfrastructureMachinePoolTemplate(metav1.NamespaceDefault, "infra1").Build()).
  2150  						WithBootstrapTemplate(
  2151  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  2152  						Build()).
  2153  				Build(),
  2154  			expectErr: true,
  2155  		},
  2156  		{
  2157  			name: "error if a control plane MachineHealthCheck that is in use by a cluster is removed",
  2158  			clusters: []client.Object{
  2159  				builder.Cluster(metav1.NamespaceDefault, "cluster1").
  2160  					WithTopology(builder.ClusterTopology().
  2161  						WithClass("clusterclass1").
  2162  						WithControlPlaneMachineHealthCheck(&clusterv1.MachineHealthCheckTopology{
  2163  							Enable: ptr.To(true),
  2164  						}).
  2165  						Build()).
  2166  					Build(),
  2167  			},
  2168  			oldClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1").
  2169  				WithInfrastructureClusterTemplate(
  2170  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()).
  2171  				WithControlPlaneTemplate(
  2172  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  2173  						Build()).
  2174  				WithControlPlaneMachineHealthCheck(&clusterv1.MachineHealthCheckClass{
  2175  					UnhealthyConditions: []clusterv1.UnhealthyCondition{
  2176  						{
  2177  							Type:    corev1.NodeReady,
  2178  							Status:  corev1.ConditionUnknown,
  2179  							Timeout: metav1.Duration{Duration: 5 * time.Minute},
  2180  						},
  2181  					},
  2182  				}).
  2183  				Build(),
  2184  			newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1").
  2185  				WithInfrastructureClusterTemplate(
  2186  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()).
  2187  				WithControlPlaneTemplate(
  2188  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  2189  						Build()).
  2190  				Build(),
  2191  			expectErr: true,
  2192  		},
  2193  		{
  2194  			name: "pass if a control plane MachineHealthCheck is removed but no cluster enforces it",
  2195  			clusters: []client.Object{
  2196  				builder.Cluster(metav1.NamespaceDefault, "cluster1").
  2197  					WithTopology(builder.ClusterTopology().
  2198  						WithClass("clusterclass1").
  2199  						Build()).
  2200  					Build(),
  2201  			},
  2202  			oldClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1").
  2203  				WithInfrastructureClusterTemplate(
  2204  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()).
  2205  				WithControlPlaneTemplate(
  2206  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  2207  						Build()).
  2208  				WithControlPlaneMachineHealthCheck(&clusterv1.MachineHealthCheckClass{}).
  2209  				Build(),
  2210  			newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1").
  2211  				WithInfrastructureClusterTemplate(
  2212  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()).
  2213  				WithControlPlaneTemplate(
  2214  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  2215  						Build()).
  2216  				Build(),
  2217  			expectErr: false,
  2218  		},
  2219  		{
  2220  			name: "pass if a control plane MachineHealthCheck is removed when clusters are not using it (clusters have overrides in topology)",
  2221  			clusters: []client.Object{
  2222  				builder.Cluster(metav1.NamespaceDefault, "cluster1").
  2223  					WithTopology(builder.ClusterTopology().
  2224  						WithClass("clusterclass1").
  2225  						WithControlPlaneMachineHealthCheck(&clusterv1.MachineHealthCheckTopology{
  2226  							Enable: ptr.To(true),
  2227  							MachineHealthCheckClass: clusterv1.MachineHealthCheckClass{
  2228  								UnhealthyConditions: []clusterv1.UnhealthyCondition{
  2229  									{
  2230  										Type:    corev1.NodeReady,
  2231  										Status:  corev1.ConditionUnknown,
  2232  										Timeout: metav1.Duration{Duration: 5 * time.Minute},
  2233  									},
  2234  								},
  2235  							},
  2236  						}).
  2237  						Build()).
  2238  					Build(),
  2239  			},
  2240  			oldClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1").
  2241  				WithInfrastructureClusterTemplate(
  2242  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()).
  2243  				WithControlPlaneTemplate(
  2244  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  2245  						Build()).
  2246  				WithControlPlaneMachineHealthCheck(&clusterv1.MachineHealthCheckClass{}).
  2247  				Build(),
  2248  			newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1").
  2249  				WithInfrastructureClusterTemplate(
  2250  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()).
  2251  				WithControlPlaneTemplate(
  2252  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  2253  						Build()).
  2254  				Build(),
  2255  			expectErr: false,
  2256  		},
  2257  		{
  2258  			name: "error if a MachineDeployment MachineHealthCheck that is in use by a cluster is removed",
  2259  			clusters: []client.Object{
  2260  				builder.Cluster(metav1.NamespaceDefault, "cluster1").
  2261  					WithTopology(builder.ClusterTopology().
  2262  						WithClass("clusterclass1").
  2263  						WithMachineDeployment(builder.MachineDeploymentTopology("md1").
  2264  							WithClass("mdclass1").
  2265  							WithMachineHealthCheck(&clusterv1.MachineHealthCheckTopology{
  2266  								Enable: ptr.To(true),
  2267  							}).
  2268  							Build()).
  2269  						Build()).
  2270  					Build(),
  2271  			},
  2272  			oldClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1").
  2273  				WithInfrastructureClusterTemplate(
  2274  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()).
  2275  				WithControlPlaneTemplate(
  2276  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  2277  						Build()).
  2278  				WithWorkerMachineDeploymentClasses(
  2279  					*builder.MachineDeploymentClass("mdclass1").
  2280  						WithInfrastructureTemplate(
  2281  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  2282  						WithBootstrapTemplate(
  2283  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  2284  						WithMachineHealthCheckClass(&clusterv1.MachineHealthCheckClass{}).
  2285  						Build(),
  2286  				).
  2287  				Build(),
  2288  			newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1").
  2289  				WithInfrastructureClusterTemplate(
  2290  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()).
  2291  				WithControlPlaneTemplate(
  2292  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  2293  						Build()).
  2294  				WithWorkerMachineDeploymentClasses(
  2295  					*builder.MachineDeploymentClass("mdclass1").
  2296  						WithInfrastructureTemplate(
  2297  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  2298  						WithBootstrapTemplate(
  2299  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  2300  						Build(),
  2301  				).
  2302  				Build(),
  2303  			expectErr: true,
  2304  		},
  2305  		{
  2306  			name: "pass if a MachineDeployment MachineHealthCheck is removed but no cluster enforces it",
  2307  			clusters: []client.Object{
  2308  				builder.Cluster(metav1.NamespaceDefault, "cluster1").
  2309  					WithTopology(builder.ClusterTopology().
  2310  						WithClass("clusterclass1").
  2311  						WithMachineDeployment(builder.MachineDeploymentTopology("md1").
  2312  							WithClass("mdclass1").
  2313  							Build()).
  2314  						Build()).
  2315  					Build(),
  2316  			},
  2317  			oldClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1").
  2318  				WithInfrastructureClusterTemplate(
  2319  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()).
  2320  				WithControlPlaneTemplate(
  2321  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  2322  						Build()).
  2323  				WithWorkerMachineDeploymentClasses(
  2324  					*builder.MachineDeploymentClass("mdclass1").
  2325  						WithInfrastructureTemplate(
  2326  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  2327  						WithBootstrapTemplate(
  2328  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  2329  						WithMachineHealthCheckClass(&clusterv1.MachineHealthCheckClass{}).
  2330  						Build(),
  2331  				).
  2332  				Build(),
  2333  			newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1").
  2334  				WithInfrastructureClusterTemplate(
  2335  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()).
  2336  				WithControlPlaneTemplate(
  2337  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  2338  						Build()).
  2339  				WithWorkerMachineDeploymentClasses(
  2340  					*builder.MachineDeploymentClass("mdclass1").
  2341  						WithInfrastructureTemplate(
  2342  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  2343  						WithBootstrapTemplate(
  2344  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  2345  						Build(),
  2346  				).
  2347  				Build(),
  2348  			expectErr: false,
  2349  		},
  2350  		{
  2351  			name: "pass if a MachineDeployment MachineHealthCheck is removed when clusters are not using it (clusters have overrides in topology)",
  2352  			clusters: []client.Object{
  2353  				builder.Cluster(metav1.NamespaceDefault, "cluster1").
  2354  					WithTopology(builder.ClusterTopology().
  2355  						WithClass("clusterclass1").
  2356  						WithMachineDeployment(builder.MachineDeploymentTopology("md1").
  2357  							WithClass("mdclass1").
  2358  							WithMachineHealthCheck(&clusterv1.MachineHealthCheckTopology{
  2359  								Enable: ptr.To(true),
  2360  								MachineHealthCheckClass: clusterv1.MachineHealthCheckClass{
  2361  									UnhealthyConditions: []clusterv1.UnhealthyCondition{
  2362  										{
  2363  											Type:    corev1.NodeReady,
  2364  											Status:  corev1.ConditionUnknown,
  2365  											Timeout: metav1.Duration{Duration: 5 * time.Minute},
  2366  										},
  2367  									},
  2368  								},
  2369  							}).
  2370  							Build()).
  2371  						Build()).
  2372  					Build(),
  2373  			},
  2374  			oldClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1").
  2375  				WithInfrastructureClusterTemplate(
  2376  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()).
  2377  				WithControlPlaneTemplate(
  2378  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  2379  						Build()).
  2380  				WithWorkerMachineDeploymentClasses(
  2381  					*builder.MachineDeploymentClass("mdclass1").
  2382  						WithInfrastructureTemplate(
  2383  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  2384  						WithBootstrapTemplate(
  2385  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  2386  						WithMachineHealthCheckClass(&clusterv1.MachineHealthCheckClass{}).
  2387  						Build(),
  2388  				).
  2389  				Build(),
  2390  			newClusterClass: builder.ClusterClass(metav1.NamespaceDefault, "clusterclass1").
  2391  				WithInfrastructureClusterTemplate(
  2392  					builder.InfrastructureClusterTemplate(metav1.NamespaceDefault, "inf").Build()).
  2393  				WithControlPlaneTemplate(
  2394  					builder.ControlPlaneTemplate(metav1.NamespaceDefault, "cp1").
  2395  						Build()).
  2396  				WithWorkerMachineDeploymentClasses(
  2397  					*builder.MachineDeploymentClass("mdclass1").
  2398  						WithInfrastructureTemplate(
  2399  							builder.InfrastructureMachineTemplate(metav1.NamespaceDefault, "infra1").Build()).
  2400  						WithBootstrapTemplate(
  2401  							builder.BootstrapTemplate(metav1.NamespaceDefault, "bootstrap1").Build()).
  2402  						Build(),
  2403  				).
  2404  				Build(),
  2405  			expectErr: false,
  2406  		},
  2407  	}
  2408  
  2409  	for _, tt := range tests {
  2410  		t.Run(tt.name, func(t *testing.T) {
  2411  			g := NewWithT(t)
  2412  
  2413  			// Sets up the fakeClient for the test case.
  2414  			fakeClient := fake.NewClientBuilder().
  2415  				WithScheme(fakeScheme).
  2416  				WithObjects(tt.clusters...).
  2417  				WithIndex(&clusterv1.Cluster{}, index.ClusterClassNameField, index.ClusterByClusterClassClassName).
  2418  				Build()
  2419  
  2420  			// Create the webhook and add the fakeClient as its client.
  2421  			webhook := &ClusterClass{Client: fakeClient}
  2422  			err := webhook.validate(ctx, tt.oldClusterClass, tt.newClusterClass)
  2423  			if tt.expectErr {
  2424  				g.Expect(err).To(HaveOccurred())
  2425  				return
  2426  			}
  2427  			g.Expect(err).ToNot(HaveOccurred())
  2428  		})
  2429  	}
  2430  }
  2431  
  2432  func invalidLabels() map[string]string {
  2433  	return map[string]string{
  2434  		"foo":          "$invalid-key",
  2435  		"bar":          strings.Repeat("a", 64) + "too-long-value",
  2436  		"/invalid-key": "foo",
  2437  	}
  2438  }
  2439  
  2440  func invalidAnnotations() map[string]string {
  2441  	return map[string]string{
  2442  		"/invalid-key": "foo",
  2443  	}
  2444  }