From 2c6bd54c1e3e99ad9ace144b5c49306f29fbc0c5 Mon Sep 17 00:00:00 2001 From: Roman Hros Date: Fri, 19 Jan 2024 10:24:44 +0100 Subject: [PATCH 1/2] Add unit tests for the openstackclusterstackrelease controller Signed-off-by: Roman Hros --- ...tackclusterstackrelease_controller_test.go | 188 +++++++++++++++++- .../metadata.yaml | 7 + .../node-images.yaml | 3 + .../openstack-ferrol-1-27-v4/metadata.yaml | 7 + .../openstack-ferrol-1-27-v4/node-images.yaml | 8 + 5 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 test/releases/cluster-stacks/openstack-ferrol-1-27-v4-wrong-node-images/metadata.yaml create mode 100644 test/releases/cluster-stacks/openstack-ferrol-1-27-v4-wrong-node-images/node-images.yaml create mode 100644 test/releases/cluster-stacks/openstack-ferrol-1-27-v4/metadata.yaml create mode 100644 test/releases/cluster-stacks/openstack-ferrol-1-27-v4/node-images.yaml diff --git a/internal/controller/openstackclusterstackrelease_controller_test.go b/internal/controller/openstackclusterstackrelease_controller_test.go index 40ffccff..b6e8c14c 100644 --- a/internal/controller/openstackclusterstackrelease_controller_test.go +++ b/internal/controller/openstackclusterstackrelease_controller_test.go @@ -17,20 +17,206 @@ limitations under the License. package controller import ( + "context" "testing" + "time" + "github.com/gophercloud/gophercloud/openstack/imageservice/v2/images" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + apiv1alpha1 "github.com/sovereignCloudStack/cluster-stack-provider-openstack/api/v1alpha1" "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + capoapiv1alpha7 "sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha7" +) + +const ( + timeout = time.Second * 2 + interval = 100 * time.Millisecond ) func TestCutOpenStackClusterStackReleaseVersionFromReleaseTag(t *testing.T) { + // correct release tag releaseTag := "openstack-ferrol-1-27-v2" nameWithoutVersion, err := cutOpenStackClusterStackReleaseVersionFromReleaseTag(releaseTag) assert.NoError(t, err) assert.Equal(t, nameWithoutVersion, "openstack-ferrol-1-27") + // incorrect release tag releaseTag = "openstack-ferrol-1-27" - _, err = cutOpenStackClusterStackReleaseVersionFromReleaseTag(releaseTag) + nameWithoutVersion, err = cutOpenStackClusterStackReleaseVersionFromReleaseTag(releaseTag) + + assert.Error(t, err) + assert.Empty(t, nameWithoutVersion) +} + +func TestGenerateOwnerReference(t *testing.T) { + oscsr := &apiv1alpha1.OpenStackClusterStackRelease{ + TypeMeta: metav1.TypeMeta{ + APIVersion: apiv1alpha1.GroupVersion.String(), + Kind: "OpenStackClusterStackRelease", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "openstack-ferrol-1-27-v1", + Namespace: "cluster", + UID: "fb686e33-01a6-42c9-a210-2c26ec8cb331", + }, + Spec: apiv1alpha1.OpenStackClusterStackReleaseSpec{ + CloudName: "openstack", + IdentityRef: &capoapiv1alpha7.OpenStackIdentityReference{ + Kind: "Secret", + Name: "supersecret", + }, + }, + } + + ownerRef := generateOwnerReference(oscsr) + + assert.Equal(t, ownerRef, &metav1.OwnerReference{ + APIVersion: oscsr.APIVersion, + Kind: oscsr.Kind, + Name: oscsr.Name, + UID: oscsr.UID, + }) +} + +func TestMatchOwnerReference(t *testing.T) { + // wrong APIVersion + oscsr1 := &apiv1alpha1.OpenStackClusterStackRelease{ + TypeMeta: metav1.TypeMeta{ + APIVersion: apiv1alpha1.GroupVersion.String() + "/" + apiv1alpha1.GroupVersion.Version, + Kind: "OpenStackClusterStackRelease", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "openstack-ferrol-1-27-v1", + }, + Spec: apiv1alpha1.OpenStackClusterStackReleaseSpec{ + CloudName: "openstack", + IdentityRef: &capoapiv1alpha7.OpenStackIdentityReference{ + Kind: "Secret", + Name: "supersecret1", + }, + }, + } + assert.False(t, matchOwnerReference(generateOwnerReference(oscsr1), oscsr1)) + + // match owner reference + oscsr2 := &apiv1alpha1.OpenStackClusterStackRelease{ + TypeMeta: metav1.TypeMeta{ + APIVersion: apiv1alpha1.GroupVersion.String(), + Kind: "OpenStackClusterStackRelease", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "openstack-ferrol-1-27-v2", + }, + Spec: apiv1alpha1.OpenStackClusterStackReleaseSpec{ + CloudName: "openstack", + IdentityRef: &capoapiv1alpha7.OpenStackIdentityReference{ + Kind: "Secret", + Name: "supersecret2", + }, + }, + } + assert.True(t, matchOwnerReference(generateOwnerReference(oscsr2), oscsr2)) + + // name is different + ownerRef := &metav1.OwnerReference{ + APIVersion: oscsr2.APIVersion, + Kind: oscsr2.Kind, + Name: "openstack-ferrol-1-27-v3", + UID: oscsr2.UID, + } + assert.False(t, matchOwnerReference(ownerRef, oscsr2)) +} +func TestGetNodeImagesFromLocal(t *testing.T) { + // wrong path + nodeImages, err := getNodeImagesFromLocal("../../test/releases/cluster-stacks/openstack-ferrol-1-27-4v") assert.Error(t, err) + assert.Nil(t, nodeImages) + + // wrong node-images file + nodeImages, err = getNodeImagesFromLocal("../../test/releases/cluster-stacks/openstack-ferrol-1-27-v4-wrong-node-images") + assert.Error(t, err) + assert.Nil(t, nodeImages) + + // correct node-images file + nodeImages, err = getNodeImagesFromLocal("../../test/releases/cluster-stacks/openstack-ferrol-1-27-v4") + var visibility images.ImageVisibility = "shared" + assert.NoError(t, err) + assert.Equal(t, nodeImages, &NodeImages{ + []*apiv1alpha1.OpenStackNodeImage{ + { + URL: "https://swift.services.a.regiocloud.tech/swift/v1/AUTH_b182637428444b9aa302bb8d5a5a418c/openstack-k8s-capi-images/ubuntu-2204-kube-v1.27/ubuntu-2204-kube-v1.27.8.qcow2", + CreateOpts: &apiv1alpha1.CreateOpts{ + Name: "ubuntu-capi-image-v1.27.8", + DiskFormat: "qcow2", + ContainerFormat: "bare", + Visibility: &visibility, + }, + }, + }, + }) } + +var _ = Describe("OpenStackClusterStackRelease controller", func() { + Context("OpenStackClusterStackRelease controller test", func() { + const openstackclusterstackreleasename = "test-ocsr" + + ctx := context.Background() + + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: openstackclusterstackreleasename, + Namespace: openstackclusterstackreleasename, + }, + } + + typeNamespaceName := types.NamespacedName{Name: openstackclusterstackreleasename, Namespace: openstackclusterstackreleasename} + + BeforeEach(func() { + By("Creating the Namespace to perform the tests") + err := k8sClient.Create(ctx, namespace) + Expect(err).To(Not(HaveOccurred())) + }) + + AfterEach(func() { + By("Deleting the Namespace to perform the tests") + _ = k8sClient.Delete(ctx, namespace) + }) + + It("should successfully create the OpenStackClusterStackRelease custom resource", func() { + By("Creating the custom resource for the Kind OpenStackClusterStackRelease") + openstackclusterstackrelease := &apiv1alpha1.OpenStackClusterStackRelease{} + err := k8sClient.Get(ctx, typeNamespaceName, openstackclusterstackrelease) + if err != nil && apierrors.IsNotFound(err) { + openstackclusterstackrelease := &apiv1alpha1.OpenStackClusterStackRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: openstackclusterstackreleasename, + Namespace: namespace.Name, + }, + Spec: apiv1alpha1.OpenStackClusterStackReleaseSpec{ + CloudName: "openstack", + IdentityRef: &capoapiv1alpha7.OpenStackIdentityReference{ + Kind: "Secret", + Name: "supersecret", + }, + }, + } + + err = k8sClient.Create(ctx, openstackclusterstackrelease) + Expect(err).To(Not(HaveOccurred())) + } + + By("Checking if the custom resource was successfully created") + Eventually(func() error { + found := &apiv1alpha1.OpenStackClusterStackRelease{} + return k8sClient.Get(ctx, typeNamespaceName, found) + }, timeout, interval).Should(Succeed()) + }) + }) +}) diff --git a/test/releases/cluster-stacks/openstack-ferrol-1-27-v4-wrong-node-images/metadata.yaml b/test/releases/cluster-stacks/openstack-ferrol-1-27-v4-wrong-node-images/metadata.yaml new file mode 100644 index 00000000..525ac226 --- /dev/null +++ b/test/releases/cluster-stacks/openstack-ferrol-1-27-v4-wrong-node-images/metadata.yaml @@ -0,0 +1,7 @@ +apiVersion: metadata.clusterstack.x-k8s.io/v1alpha1 +versions: + clusterStack: v4 + kubernetes: v1.27.8 + components: + clusterAddon: v2 + nodeImage: v2 diff --git a/test/releases/cluster-stacks/openstack-ferrol-1-27-v4-wrong-node-images/node-images.yaml b/test/releases/cluster-stacks/openstack-ferrol-1-27-v4-wrong-node-images/node-images.yaml new file mode 100644 index 00000000..a65bf51c --- /dev/null +++ b/test/releases/cluster-stacks/openstack-ferrol-1-27-v4-wrong-node-images/node-images.yaml @@ -0,0 +1,3 @@ +apiVersion: openstack.infrastructure.clusterstack.x-k8s.io/v1alpha1 +openStackNodeImages: + - https://swift.services.a.regiocloud.tech/swift/v1/AUTH_b182637428444b9aa302bb8d5a5a418c/openstack-k8s-capi-images/ubuntu-2204-kube-v1.27/ubuntu-2204-kube-v1.27.8.qcow2 diff --git a/test/releases/cluster-stacks/openstack-ferrol-1-27-v4/metadata.yaml b/test/releases/cluster-stacks/openstack-ferrol-1-27-v4/metadata.yaml new file mode 100644 index 00000000..525ac226 --- /dev/null +++ b/test/releases/cluster-stacks/openstack-ferrol-1-27-v4/metadata.yaml @@ -0,0 +1,7 @@ +apiVersion: metadata.clusterstack.x-k8s.io/v1alpha1 +versions: + clusterStack: v4 + kubernetes: v1.27.8 + components: + clusterAddon: v2 + nodeImage: v2 diff --git a/test/releases/cluster-stacks/openstack-ferrol-1-27-v4/node-images.yaml b/test/releases/cluster-stacks/openstack-ferrol-1-27-v4/node-images.yaml new file mode 100644 index 00000000..08f7b4b0 --- /dev/null +++ b/test/releases/cluster-stacks/openstack-ferrol-1-27-v4/node-images.yaml @@ -0,0 +1,8 @@ +apiVersion: openstack.infrastructure.clusterstack.x-k8s.io/v1alpha1 +openStackNodeImages: + - url: https://swift.services.a.regiocloud.tech/swift/v1/AUTH_b182637428444b9aa302bb8d5a5a418c/openstack-k8s-capi-images/ubuntu-2204-kube-v1.27/ubuntu-2204-kube-v1.27.8.qcow2 + createOpts: + name: ubuntu-capi-image-v1.27.8 + disk_format: qcow2 + container_format: bare + visibility: shared From 18c9ee9df411f693d0979189f005f58ad7b8a8f1 Mon Sep 17 00:00:00 2001 From: Roman Hros Date: Fri, 26 Jan 2024 08:49:34 +0100 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Michal Gubricky Signed-off-by: Roman Hros --- .../openstackclusterstackrelease_controller_test.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/internal/controller/openstackclusterstackrelease_controller_test.go b/internal/controller/openstackclusterstackrelease_controller_test.go index b6e8c14c..06720556 100644 --- a/internal/controller/openstackclusterstackrelease_controller_test.go +++ b/internal/controller/openstackclusterstackrelease_controller_test.go @@ -18,6 +18,7 @@ package controller import ( "context" + "fmt" "testing" "time" @@ -51,6 +52,7 @@ func TestCutOpenStackClusterStackReleaseVersionFromReleaseTag(t *testing.T) { nameWithoutVersion, err = cutOpenStackClusterStackReleaseVersionFromReleaseTag(releaseTag) assert.Error(t, err) + assert.EqualError(t, err, fmt.Sprintf("invalid release tag %s", releaseTag)) assert.Empty(t, nameWithoutVersion) } @@ -135,13 +137,16 @@ func TestMatchOwnerReference(t *testing.T) { func TestGetNodeImagesFromLocal(t *testing.T) { // wrong path - nodeImages, err := getNodeImagesFromLocal("../../test/releases/cluster-stacks/openstack-ferrol-1-27-4v") + wrongPath := "../../test/releases/cluster-stacks/openstack-ferrol-1-27-4v" + nodeImages, err := getNodeImagesFromLocal(wrongPath) assert.Error(t, err) + assert.ErrorContains(t, err, fmt.Sprintf("failed to read node-images file %s/node-images.yaml", wrongPath)) assert.Nil(t, nodeImages) // wrong node-images file nodeImages, err = getNodeImagesFromLocal("../../test/releases/cluster-stacks/openstack-ferrol-1-27-v4-wrong-node-images") assert.Error(t, err) + assert.ErrorContains(t, err, "failed to unmarshal node-images") assert.Nil(t, nodeImages) // correct node-images file