Skip to content

Commit

Permalink
Add composable matchers to internal/testtypes
Browse files Browse the repository at this point in the history
This commit adds composable matching objects to the internal
testtypes package. These types can be used for advanced comparison
between objects in the Cluster API unit and integration tests.
A simple integration test is included to show the basic working of
the matchers.
  • Loading branch information
killianmuldoon committed Sep 17, 2021
1 parent 0065d5c commit d24e1f4
Show file tree
Hide file tree
Showing 6 changed files with 476 additions and 228 deletions.
78 changes: 33 additions & 45 deletions controllers/topology/blueprint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,47 +19,41 @@ package topology
import (
"testing"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha4"
"sigs.k8s.io/cluster-api/controllers/topology/internal/scope"
"sigs.k8s.io/cluster-api/internal/testtypes"
. "sigs.k8s.io/cluster-api/internal/testtypes"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
)

func TestGetBlueprint(t *testing.T) {
crds := []client.Object{
testtypes.GenericInfrastructureClusterTemplateCRD,
testtypes.GenericInfrastructureMachineTemplateCRD,
testtypes.GenericInfrastructureMachineCRD,
testtypes.GenericControlPlaneTemplateCRD,
testtypes.GenericBootstrapConfigTemplateCRD,
GenericInfrastructureClusterTemplateCRD,
GenericInfrastructureMachineTemplateCRD,
GenericInfrastructureMachineCRD,
GenericControlPlaneTemplateCRD,
GenericBootstrapConfigTemplateCRD,
}

// ignoreResourceVersion is an option to pass to cmpopts to ignore this field which is set by the fakeClient
// TODO: Make composable version of these options in the builder package to reuse these filters across tests.
ignoreResourceVersion := cmpopts.IgnoreFields(metav1.ObjectMeta{}, "ResourceVersion")

// Create objects used across test cases.
infraClusterTemplate := testtypes.NewInfrastructureClusterTemplateBuilder(metav1.NamespaceDefault, "infraclustertemplate1").
infraClusterTemplate := NewInfrastructureClusterTemplateBuilder(metav1.NamespaceDefault, "infraclustertemplate1").
Build()
controlPlaneTemplate := testtypes.NewControlPlaneTemplateBuilder(metav1.NamespaceDefault, "controlplanetemplate1").
controlPlaneTemplate := NewControlPlaneTemplateBuilder(metav1.NamespaceDefault, "controlplanetemplate1").
Build()

controlPlaneInfrastructureMachineTemplate := testtypes.NewInfrastructureMachineTemplateBuilder(metav1.NamespaceDefault, "controlplaneinframachinetemplate1").
controlPlaneInfrastructureMachineTemplate := NewInfrastructureMachineTemplateBuilder(metav1.NamespaceDefault, "controlplaneinframachinetemplate1").
Build()
controlPlaneTemplateWithInfrastructureMachine := testtypes.NewControlPlaneTemplateBuilder(metav1.NamespaceDefault, "controlplanetempaltewithinfrastructuremachine1").
controlPlaneTemplateWithInfrastructureMachine := NewControlPlaneTemplateBuilder(metav1.NamespaceDefault, "controlplanetempaltewithinfrastructuremachine1").
WithInfrastructureMachineTemplate(controlPlaneInfrastructureMachineTemplate).
Build()

workerInfrastructureMachineTemplate := testtypes.NewInfrastructureMachineTemplateBuilder(metav1.NamespaceDefault, "workerinframachinetemplate1").
workerInfrastructureMachineTemplate := NewInfrastructureMachineTemplateBuilder(metav1.NamespaceDefault, "workerinframachinetemplate1").
Build()
workerBootstrapTemplate := testtypes.NewBootstrapTemplateBuilder(metav1.NamespaceDefault, "workerbootstraptemplate1").
workerBootstrapTemplate := NewBootstrapTemplateBuilder(metav1.NamespaceDefault, "workerbootstraptemplate1").
Build()
machineDeployment := testtypes.NewMachineDeploymentClassBuilder(metav1.NamespaceDefault, "machinedeployment1").
machineDeployment := NewMachineDeploymentClassBuilder(metav1.NamespaceDefault, "machinedeployment1").
WithClass("workerclass1").
WithLabels(map[string]string{"foo": "bar"}).
WithAnnotations(map[string]string{"a": "b"}).
Expand All @@ -82,14 +76,14 @@ func TestGetBlueprint(t *testing.T) {
},
{
name: "Fails if ClusterClass does not have reference to the InfrastructureClusterTemplate",
clusterClass: testtypes.NewClusterClassBuilder(metav1.NamespaceDefault, "clusterclass1").
clusterClass: NewClusterClassBuilder(metav1.NamespaceDefault, "clusterclass1").
// No InfrastructureClusterTemplate reference!
Build(),
wantErr: true,
},
{
name: "Fails if ClusterClass references an InfrastructureClusterTemplate that does not exist",
clusterClass: testtypes.NewClusterClassBuilder(metav1.NamespaceDefault, "clusterclass1").
clusterClass: NewClusterClassBuilder(metav1.NamespaceDefault, "clusterclass1").
WithInfrastructureClusterTemplate(infraClusterTemplate).
Build(),
objects: []client.Object{
Expand All @@ -99,7 +93,7 @@ func TestGetBlueprint(t *testing.T) {
},
{
name: "Fails if ClusterClass does not have reference to the ControlPlaneTemplate",
clusterClass: testtypes.NewClusterClassBuilder(metav1.NamespaceDefault, "class1").
clusterClass: NewClusterClassBuilder(metav1.NamespaceDefault, "class1").
WithInfrastructureClusterTemplate(infraClusterTemplate).
// No ControlPlaneTemplate reference!
Build(),
Expand All @@ -110,7 +104,7 @@ func TestGetBlueprint(t *testing.T) {
},
{
name: "Fails if ClusterClass does not have reference to the ControlPlaneTemplate",
clusterClass: testtypes.NewClusterClassBuilder(metav1.NamespaceDefault, "class1").
clusterClass: NewClusterClassBuilder(metav1.NamespaceDefault, "class1").
WithInfrastructureClusterTemplate(infraClusterTemplate).
WithControlPlaneTemplate(controlPlaneTemplate).
Build(),
Expand All @@ -122,7 +116,7 @@ func TestGetBlueprint(t *testing.T) {
},
{
name: "Should read a ClusterClass without worker classes",
clusterClass: testtypes.NewClusterClassBuilder(metav1.NamespaceDefault, "class1").
clusterClass: NewClusterClassBuilder(metav1.NamespaceDefault, "class1").
WithInfrastructureClusterTemplate(infraClusterTemplate).
WithControlPlaneTemplate(controlPlaneTemplate).
Build(),
Expand All @@ -131,7 +125,7 @@ func TestGetBlueprint(t *testing.T) {
controlPlaneTemplate,
},
want: &scope.ClusterBlueprint{
ClusterClass: testtypes.NewClusterClassBuilder(metav1.NamespaceDefault, "class1").
ClusterClass: NewClusterClassBuilder(metav1.NamespaceDefault, "class1").
WithInfrastructureClusterTemplate(infraClusterTemplate).
WithControlPlaneTemplate(controlPlaneTemplate).
Build(),
Expand All @@ -144,7 +138,7 @@ func TestGetBlueprint(t *testing.T) {
},
{
name: "Should read a ClusterClass referencing an InfrastructureMachineTemplate for the ControlPlane (but without any worker class)",
clusterClass: testtypes.NewClusterClassBuilder(metav1.NamespaceDefault, "class1").
clusterClass: NewClusterClassBuilder(metav1.NamespaceDefault, "class1").
WithInfrastructureClusterTemplate(infraClusterTemplate).
WithControlPlaneTemplate(controlPlaneTemplateWithInfrastructureMachine).
WithControlPlaneInfrastructureMachineTemplate(controlPlaneInfrastructureMachineTemplate).
Expand All @@ -155,7 +149,7 @@ func TestGetBlueprint(t *testing.T) {
controlPlaneInfrastructureMachineTemplate,
},
want: &scope.ClusterBlueprint{
ClusterClass: testtypes.NewClusterClassBuilder(metav1.NamespaceDefault, "class1").
ClusterClass: NewClusterClassBuilder(metav1.NamespaceDefault, "class1").
WithInfrastructureClusterTemplate(infraClusterTemplate).
WithControlPlaneTemplate(controlPlaneTemplateWithInfrastructureMachine).
WithControlPlaneInfrastructureMachineTemplate(controlPlaneInfrastructureMachineTemplate).
Expand All @@ -170,7 +164,7 @@ func TestGetBlueprint(t *testing.T) {
},
{
name: "Fails if ClusterClass references an InfrastructureMachineTemplate for the ControlPlane that does not exist",
clusterClass: testtypes.NewClusterClassBuilder(metav1.NamespaceDefault, "class1").
clusterClass: NewClusterClassBuilder(metav1.NamespaceDefault, "class1").
WithInfrastructureClusterTemplate(infraClusterTemplate).
WithControlPlaneTemplate(controlPlaneTemplate).
WithControlPlaneInfrastructureMachineTemplate(controlPlaneInfrastructureMachineTemplate).
Expand All @@ -184,7 +178,7 @@ func TestGetBlueprint(t *testing.T) {
},
{
name: "Should read a ClusterClass with a MachineDeploymentClass",
clusterClass: testtypes.NewClusterClassBuilder(metav1.NamespaceDefault, "class1").
clusterClass: NewClusterClassBuilder(metav1.NamespaceDefault, "class1").
WithInfrastructureClusterTemplate(infraClusterTemplate).
WithControlPlaneTemplate(controlPlaneTemplate).
WithWorkerMachineDeploymentClasses(mds).
Expand All @@ -196,7 +190,7 @@ func TestGetBlueprint(t *testing.T) {
workerBootstrapTemplate,
},
want: &scope.ClusterBlueprint{
ClusterClass: testtypes.NewClusterClassBuilder(metav1.NamespaceDefault, "class1").
ClusterClass: NewClusterClassBuilder(metav1.NamespaceDefault, "class1").
WithInfrastructureClusterTemplate(infraClusterTemplate).
WithControlPlaneTemplate(controlPlaneTemplate).
WithWorkerMachineDeploymentClasses(mds).
Expand All @@ -219,7 +213,7 @@ func TestGetBlueprint(t *testing.T) {
},
{
name: "Fails if ClusterClass has a MachineDeploymentClass referencing a BootstrapTemplate that does not exist",
clusterClass: testtypes.NewClusterClassBuilder(metav1.NamespaceDefault, "class1").
clusterClass: NewClusterClassBuilder(metav1.NamespaceDefault, "class1").
WithInfrastructureClusterTemplate(infraClusterTemplate).
WithControlPlaneTemplate(controlPlaneTemplate).
WithWorkerMachineDeploymentClasses(mds).
Expand All @@ -234,7 +228,7 @@ func TestGetBlueprint(t *testing.T) {
},
{
name: "Fails if ClusterClass has a MachineDeploymentClass referencing a InfrastructureMachineTemplate that does not exist",
clusterClass: testtypes.NewClusterClassBuilder(metav1.NamespaceDefault, "class1").
clusterClass: NewClusterClassBuilder(metav1.NamespaceDefault, "class1").
WithInfrastructureClusterTemplate(infraClusterTemplate).
WithControlPlaneTemplate(controlPlaneTemplate).
WithWorkerMachineDeploymentClasses(mds).
Expand All @@ -253,7 +247,7 @@ func TestGetBlueprint(t *testing.T) {
g := NewWithT(t)

// Set up a cluster using the ClusterClass, if any.
cluster := testtypes.NewClusterBuilder(metav1.NamespaceDefault, "cluster1").Build()
cluster := NewClusterBuilder(metav1.NamespaceDefault, "cluster1").Build()
if tt.clusterClass != nil {
cluster.Spec.Topology = &clusterv1.Topology{
Class: tt.clusterClass.Name,
Expand Down Expand Up @@ -294,19 +288,13 @@ func TestGetBlueprint(t *testing.T) {
g.Expect(got).To(BeNil())
return
}
// Use EqualObject where an object is created and passed through the fake client. Elsewhere the Equal method
// is enough to establish inequality.
g.Expect(tt.want.ClusterClass).To(EqualObject(got.ClusterClass, IgnoreAutogeneratedMetadata))
g.Expect(tt.want.InfrastructureClusterTemplate).To(EqualObject(got.InfrastructureClusterTemplate))
g.Expect(got.ControlPlane).To(Equal(tt.want.ControlPlane))
g.Expect(tt.want.MachineDeployments).To(Equal(got.MachineDeployments))

// Checks the blueprint content.

// Expect the Diff resulting from each object comparison to be empty when ignoring ObjectMeta.ResourceVersion
// This is necessary as the FakeClient adds its own ResourceVersion on object creation.
g.Expect(cmp.Diff(tt.want.ClusterClass, got.ClusterClass, ignoreResourceVersion)).To(Equal(""),
cmp.Diff(tt.want.ClusterClass, got.ClusterClass, ignoreResourceVersion))
g.Expect(cmp.Diff(tt.want.InfrastructureClusterTemplate, got.InfrastructureClusterTemplate, ignoreResourceVersion)).To(Equal(""),
cmp.Diff(tt.want.InfrastructureClusterTemplate, got.InfrastructureClusterTemplate, ignoreResourceVersion))
g.Expect(cmp.Diff(tt.want.ControlPlane, got.ControlPlane, ignoreResourceVersion)).To(Equal(""),
cmp.Diff(tt.want.ControlPlane, got.ControlPlane, ignoreResourceVersion))
g.Expect(cmp.Diff(tt.want.MachineDeployments, got.MachineDeployments, ignoreResourceVersion)).To(Equal(""),
cmp.Diff(tt.want.MachineDeployments, got.MachineDeployments, ignoreResourceVersion))
})
}
}
Loading

0 comments on commit d24e1f4

Please sign in to comment.