Skip to content

Commit

Permalink
migrate more test to test CRD
Browse files Browse the repository at this point in the history
  • Loading branch information
fabriziopandini committed Jun 22, 2022
1 parent 607d267 commit 78df6a6
Show file tree
Hide file tree
Showing 6 changed files with 475 additions and 281 deletions.
22 changes: 11 additions & 11 deletions internal/controllers/topology/cluster/cluster_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -547,19 +547,19 @@ func setupTestEnvForIntegrationTests(ns *corev1.Namespace) (func() error, error)
// Cluster given a skeletal Cluster object and a ClusterClass. The objects include:

// 1) Templates for Machine, Cluster, ControlPlane and Bootstrap.
infrastructureMachineTemplate1 := builder.InfrastructureMachineTemplate(ns.Name, infrastructureMachineTemplateName1).Build()
infrastructureMachineTemplate2 := builder.InfrastructureMachineTemplate(ns.Name, infrastructureMachineTemplateName2).
infrastructureMachineTemplate1 := builder.TestInfrastructureMachineTemplate(ns.Name, infrastructureMachineTemplateName1).Build()
infrastructureMachineTemplate2 := builder.TestInfrastructureMachineTemplate(ns.Name, infrastructureMachineTemplateName2).
WithSpecFields(map[string]interface{}{"spec.template.spec.fakeSetting": true}).
Build()
infrastructureClusterTemplate1 := builder.InfrastructureClusterTemplate(ns.Name, "infraclustertemplate1").
infrastructureClusterTemplate1 := builder.TestInfrastructureClusterTemplate(ns.Name, "infraclustertemplate1").
Build()
infrastructureClusterTemplate2 := builder.InfrastructureClusterTemplate(ns.Name, "infraclustertemplate2").
infrastructureClusterTemplate2 := builder.TestInfrastructureClusterTemplate(ns.Name, "infraclustertemplate2").
WithSpecFields(map[string]interface{}{"spec.template.spec.alteredSetting": true}).
Build()
controlPlaneTemplate := builder.ControlPlaneTemplate(ns.Name, "cp1").
controlPlaneTemplate := builder.TestControlPlaneTemplate(ns.Name, "cp1").
WithInfrastructureMachineTemplate(infrastructureMachineTemplate1).
Build()
bootstrapTemplate := builder.BootstrapTemplate(ns.Name, "bootstraptemplate").Build()
bootstrapTemplate := builder.TestBootstrapTemplate(ns.Name, "bootstraptemplate").Build()

// 2) ClusterClass definitions including definitions of MachineDeploymentClasses used inside the ClusterClass.
machineDeploymentClass1 := builder.MachineDeploymentClass(workerClassName1).
Expand Down Expand Up @@ -676,14 +676,14 @@ func assertClusterReconcile(cluster *clusterv1.Cluster) error {

// Check if InfrastructureRef exists and is of the expected Kind and APIVersion.
if err := referenceExistsWithCorrectKindAndAPIVersion(cluster.Spec.InfrastructureRef,
builder.GenericInfrastructureClusterKind,
builder.TestInfrastructureClusterKind,
builder.InfrastructureGroupVersion); err != nil {
return err
}

// Check if ControlPlaneRef exists is of the expected Kind and APIVersion.
if err := referenceExistsWithCorrectKindAndAPIVersion(cluster.Spec.ControlPlaneRef,
builder.GenericControlPlaneKind,
builder.TestControlPlaneKind,
builder.ControlPlaneGroupVersion); err != nil {
return err
}
Expand Down Expand Up @@ -742,7 +742,7 @@ func assertControlPlaneReconcile(cluster *clusterv1.Cluster) error {
return err
}
if err := referenceExistsWithCorrectKindAndAPIVersion(cpInfra,
builder.GenericInfrastructureMachineTemplateKind,
builder.TestInfrastructureMachineTemplateKind,
builder.InfrastructureGroupVersion); err != nil {
return err
}
Expand Down Expand Up @@ -824,7 +824,7 @@ func assertMachineDeploymentsReconcile(cluster *clusterv1.Cluster) error {

// Check if the InfrastructureReference exists.
if err := referenceExistsWithCorrectKindAndAPIVersion(&md.Spec.Template.Spec.InfrastructureRef,
builder.GenericInfrastructureMachineTemplateKind,
builder.TestInfrastructureMachineTemplateKind,
builder.InfrastructureGroupVersion); err != nil {
return err
}
Expand All @@ -836,7 +836,7 @@ func assertMachineDeploymentsReconcile(cluster *clusterv1.Cluster) error {

// Check if the Bootstrap reference has the expected Kind and APIVersion.
if err := referenceExistsWithCorrectKindAndAPIVersion(md.Spec.Template.Spec.Bootstrap.ConfigRef,
builder.GenericBootstrapConfigTemplateKind,
builder.TestBootstrapConfigTemplateKind,
builder.BootstrapGroupVersion); err != nil {
return err
}
Expand Down
124 changes: 67 additions & 57 deletions internal/test/builder/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,78 +17,88 @@ limitations under the License.
package builder

import (
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)

var (
// BootstrapGroupVersion is group version used for bootstrap objects.
BootstrapGroupVersion = schema.GroupVersion{Group: "bootstrap.cluster.x-k8s.io", Version: "v1beta1"}
// BootstrapGroupVersion is group version used for bootstrap objects.
BootstrapGroupVersion = schema.GroupVersion{Group: "bootstrap.cluster.x-k8s.io", Version: "v1beta1"}

// GenericBootstrapConfigKind is the Kind for the GenericBootstrapConfig.
GenericBootstrapConfigKind = "GenericBootstrapConfig"
// GenericBootstrapConfigCRD is a generic boostrap CRD.
GenericBootstrapConfigCRD = untypedCRD(BootstrapGroupVersion.WithKind(GenericBootstrapConfigKind))
// GenericBootstrapConfigKind is the Kind for the GenericBootstrapConfig.
GenericBootstrapConfigKind = "GenericBootstrapConfig"
// GenericBootstrapConfigCRD is a generic boostrap CRD.
GenericBootstrapConfigCRD = untypedCRD(BootstrapGroupVersion.WithKind(GenericBootstrapConfigKind))

// GenericBootstrapConfigTemplateKind is the Kind for the GenericBoostrapConfigTemplate.
GenericBootstrapConfigTemplateKind = "GenericBootstrapConfigTemplate"
// GenericBootstrapConfigTemplateCRD is a generic boostrap template CRD.
GenericBootstrapConfigTemplateCRD = untypedCRD(BootstrapGroupVersion.WithKind(GenericBootstrapConfigTemplateKind))
// GenericBootstrapConfigTemplateKind is the Kind for the GenericBoostrapConfigTemplate.
GenericBootstrapConfigTemplateKind = "GenericBootstrapConfigTemplate"
// GenericBootstrapConfigTemplateCRD is a generic boostrap template CRD.
GenericBootstrapConfigTemplateCRD = untypedCRD(BootstrapGroupVersion.WithKind(GenericBootstrapConfigTemplateKind))

// TODO: drop generic CRDs in favour of typed test CRDs.
// TODO: drop generic CRDs in favour of typed test CRDs.

// TestBootstrapConfigTemplateKind is the kind for the TestBootstrapConfigTemplate type.
TestBootstrapConfigTemplateKind = "TestBootstrapConfigTemplate"
// TestBootstrapConfigTemplateCRD is a test bootstrap config template CRD.
TestBootstrapConfigTemplateCRD = testBootstrapConfigTemplateCRD(BootstrapGroupVersion.WithKind(TestBootstrapConfigTemplateKind))
// TestBootstrapConfigTemplateKind is the kind for the TestBootstrapConfigTemplate type.
TestBootstrapConfigTemplateKind = "TestBootstrapConfigTemplate"
// TestBootstrapConfigTemplateCRD is a test bootstrap config template CRD.
TestBootstrapConfigTemplateCRD = testBootstrapConfigTemplateCRD(BootstrapGroupVersion.WithKind(TestBootstrapConfigTemplateKind))

// TestBootstrapConfigKind is the kind for the TestBootstrapConfig type.
TestBootstrapConfigKind = "TestBootstrapConfig"
// TestBootstrapConfigCRD is a test bootstrap config CRD.
TestBootstrapConfigCRD = testBootstrapConfigCRD(BootstrapGroupVersion.WithKind(TestBootstrapConfigKind))
// TestBootstrapConfigKind is the kind for the TestBootstrapConfig type.
TestBootstrapConfigKind = "TestBootstrapConfig"
// TestBootstrapConfigCRD is a test bootstrap config CRD.
TestBootstrapConfigCRD = testBootstrapConfigCRD(BootstrapGroupVersion.WithKind(TestBootstrapConfigKind))
)

func testBootstrapConfigTemplateCRD(gvk schema.GroupVersionKind) *apiextensionsv1.CustomResourceDefinition {
return generateCRD(gvk, map[string]apiextensionsv1.JSONSchemaProps{
"spec": {
Type: "object",
Properties: map[string]apiextensionsv1.JSONSchemaProps{
// Mandatory field from the Cluster API contract
"template": {
Type: "object",
Properties: map[string]apiextensionsv1.JSONSchemaProps{
"spec": bootstrapConfigSpecSchema,
},
},
},
},
})
return generateCRD(gvk, map[string]apiextensionsv1.JSONSchemaProps{
"metadata": {
// NOTE: in CRD there is only a partial definition of metadata schema.
// Ref https://github.com/kubernetes-sigs/controller-tools/blob/59485af1c1f6a664655dad49543c474bb4a0d2a2/pkg/crd/gen.go#L185
Type: "object",
},
"spec": {
Type: "object",
Properties: map[string]apiextensionsv1.JSONSchemaProps{
// Mandatory field from the Cluster API contract
"template": {
Type: "object",
Properties: map[string]apiextensionsv1.JSONSchemaProps{
"spec": bootstrapConfigSpecSchema,
},
},
},
},
})
}

func testBootstrapConfigCRD(gvk schema.GroupVersionKind) *apiextensionsv1.CustomResourceDefinition {
return generateCRD(gvk, map[string]apiextensionsv1.JSONSchemaProps{
"spec": bootstrapConfigSpecSchema,
"status": {
Type: "object",
Properties: map[string]apiextensionsv1.JSONSchemaProps{
// mandatory field from the Cluster API contract
"ready": {Type: "boolean"},
"dataSecretName": {Type: "string"},
// General purpose fields to be used in different test scenario.
"foo": {Type: "string"},
"bar": {Type: "string"},
},
},
})
return generateCRD(gvk, map[string]apiextensionsv1.JSONSchemaProps{
"metadata": {
// NOTE: in CRD there is only a partial definition of metadata schema.
// Ref https://github.com/kubernetes-sigs/controller-tools/blob/59485af1c1f6a664655dad49543c474bb4a0d2a2/pkg/crd/gen.go#L185
Type: "object",
},
"spec": bootstrapConfigSpecSchema,
"status": {
Type: "object",
Properties: map[string]apiextensionsv1.JSONSchemaProps{
// mandatory field from the Cluster API contract
"ready": {Type: "boolean"},
"dataSecretName": {Type: "string"},
// General purpose fields to be used in different test scenario.
"foo": {Type: "string"},
"bar": {Type: "string"},
},
},
})
}

var (
bootstrapConfigSpecSchema = apiextensionsv1.JSONSchemaProps{
Type: "object",
Properties: map[string]apiextensionsv1.JSONSchemaProps{
// General purpose fields to be used in different test scenario.
"foo": {Type: "string"},
"bar": {Type: "string"},
},
}
bootstrapConfigSpecSchema = apiextensionsv1.JSONSchemaProps{
Type: "object",
Properties: map[string]apiextensionsv1.JSONSchemaProps{
// General purpose fields to be used in different test scenario.
"foo": {Type: "string"},
"bar": {Type: "string"},
},
}
)
102 changes: 102 additions & 0 deletions internal/test/builder/builders.go
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,51 @@ func (i *InfrastructureClusterTemplateBuilder) Build() *unstructured.Unstructure
return obj
}

// TestInfrastructureClusterTemplateBuilder holds the variables needed to build a generic TestInfrastructureClusterTemplate.
// +kubebuilder:object:generate=false
type TestInfrastructureClusterTemplateBuilder struct {
namespace string
name string
specFields map[string]interface{}
}

// TestInfrastructureClusterTemplate returns an TestInfrastructureClusterTemplateBuilder with the given name and namespace.
func TestInfrastructureClusterTemplate(namespace, name string) *TestInfrastructureClusterTemplateBuilder {
return &TestInfrastructureClusterTemplateBuilder{
namespace: namespace,
name: name,
}
}

// WithSpecFields sets a map of spec fields on the unstructured object. The keys in the map represent the path and the value corresponds
// to the value of the spec field.
//
// Note: all the paths should start with "spec."; the path should correspond to a field defined in the CRD.
//
// Example map: map[string]interface{}{
// "spec.version": "v1.2.3",
// }.
func (i *TestInfrastructureClusterTemplateBuilder) WithSpecFields(fields map[string]interface{}) *TestInfrastructureClusterTemplateBuilder {
i.specFields = fields
return i
}

// Build creates a new Unstructured object with the variables passed to the InfrastructureClusterTemplateBuilder.
func (i *TestInfrastructureClusterTemplateBuilder) Build() *unstructured.Unstructured {
obj := &unstructured.Unstructured{}
obj.SetAPIVersion(InfrastructureGroupVersion.String())
obj.SetKind(TestInfrastructureClusterTemplateKind)
obj.SetNamespace(i.namespace)
obj.SetName(i.name)

// Initialize the spec.template.spec to make the object valid in reconciliation.
setSpecFields(obj, map[string]interface{}{"spec.template.spec": map[string]interface{}{}})

setSpecFields(obj, i.specFields)

return obj
}

// ControlPlaneTemplateBuilder holds the variables and objects needed to build a generic ControlPlane template.
// +kubebuilder:object:generate=false
type ControlPlaneTemplateBuilder struct {
Expand Down Expand Up @@ -670,6 +715,63 @@ func (c *ControlPlaneTemplateBuilder) Build() *unstructured.Unstructured {
return obj
}

// TestControlPlaneTemplateBuilder holds the variables and objects needed to build a generic ControlPlane template.
// +kubebuilder:object:generate=false
type TestControlPlaneTemplateBuilder struct {
namespace string
name string
infrastructureMachineTemplate *unstructured.Unstructured
specFields map[string]interface{}
}

// TestControlPlaneTemplate creates a NewControlPlaneTemplate builder with the given name and namespace.
func TestControlPlaneTemplate(namespace, name string) *TestControlPlaneTemplateBuilder {
return &TestControlPlaneTemplateBuilder{
namespace: namespace,
name: name,
}
}

// WithSpecFields sets a map of spec fields on the unstructured object. The keys in the map represent the path and the value corresponds
// to the value of the spec field.
//
// Note: all the paths should start with "spec."; the path should correspond to a field defined in the CRD.
//
// Example map: map[string]interface{}{
// "spec.version": "v1.2.3",
// }.
func (c *TestControlPlaneTemplateBuilder) WithSpecFields(fields map[string]interface{}) *TestControlPlaneTemplateBuilder {
c.specFields = fields
return c
}

// WithInfrastructureMachineTemplate adds the given Unstructured object to the ControlPlaneTemplateBuilder as its InfrastructureMachineTemplate.
func (c *TestControlPlaneTemplateBuilder) WithInfrastructureMachineTemplate(t *unstructured.Unstructured) *TestControlPlaneTemplateBuilder {
c.infrastructureMachineTemplate = t
return c
}

// Build creates an Unstructured object from the variables passed to the ControlPlaneTemplateBuilder.
func (c *TestControlPlaneTemplateBuilder) Build() *unstructured.Unstructured {
obj := &unstructured.Unstructured{}
obj.SetAPIVersion(ControlPlaneGroupVersion.String())
obj.SetKind(TestControlPlaneTemplateKind)
obj.SetNamespace(c.namespace)
obj.SetName(c.name)

// Initialize the spec.template.spec to make the object valid in reconciliation.
setSpecFields(obj, map[string]interface{}{"spec.template.spec": map[string]interface{}{}})

setSpecFields(obj, c.specFields)

if c.infrastructureMachineTemplate != nil {
if err := setNestedRef(obj, c.infrastructureMachineTemplate, "spec", "template", "spec", "machineTemplate", "infrastructureRef"); err != nil {
panic(err)
}
}
return obj
}

// InfrastructureClusterBuilder holds the variables and objects needed to build a generic InfrastructureCluster.
// +kubebuilder:object:generate=false
type InfrastructureClusterBuilder struct {
Expand Down
Loading

0 comments on commit 78df6a6

Please sign in to comment.