Skip to content

Commit b1fc872

Browse files
Merge pull request #118 from kuudori/HYPERFLEET-1180
HYPERFLEET-1180 - feat: add cluster and nodepool lifecycle smoke tests
2 parents c797537 + 507be10 commit b1fc872

2 files changed

Lines changed: 147 additions & 0 deletions

File tree

e2e/cluster/lifecycle_smoke.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package cluster
2+
3+
import (
4+
"context"
5+
"net/http"
6+
7+
"github.com/onsi/ginkgo/v2"
8+
. "github.com/onsi/gomega" //nolint:staticcheck // dot import for test readability
9+
10+
"github.com/openshift-hyperfleet/hyperfleet-e2e/pkg/api/openapi"
11+
"github.com/openshift-hyperfleet/hyperfleet-e2e/pkg/client"
12+
"github.com/openshift-hyperfleet/hyperfleet-e2e/pkg/helper"
13+
"github.com/openshift-hyperfleet/hyperfleet-e2e/pkg/labels"
14+
)
15+
16+
var _ = ginkgo.Describe("[Suite: cluster][baseline] Cluster Full Lifecycle Smoke",
17+
ginkgo.Label(labels.Tier0),
18+
func() {
19+
ginkgo.It("should complete create → Reconciled → delete → hard-delete → K8s cleanup in a single pass",
20+
func(ctx context.Context) {
21+
h := helper.New()
22+
23+
ginkgo.By("creating a cluster")
24+
cluster, err := h.Client.CreateClusterFromPayload(ctx, h.TestDataPath("payloads/clusters/cluster-request.json"))
25+
Expect(err).NotTo(HaveOccurred(), "create should succeed")
26+
Expect(cluster).NotTo(BeNil(), "create should return a cluster object")
27+
Expect(cluster.Id).NotTo(BeNil(), "cluster ID should be assigned")
28+
clusterID := *cluster.Id
29+
30+
ginkgo.DeferCleanup(func(ctx context.Context) {
31+
if err := h.CleanupTestCluster(ctx, clusterID); err != nil {
32+
ginkgo.GinkgoWriter.Printf("Warning: cleanup failed for cluster %s: %v\n", clusterID, err)
33+
}
34+
})
35+
36+
ginkgo.By("waiting for Reconciled=True")
37+
Eventually(h.PollCluster(ctx, clusterID), h.Cfg.Timeouts.Cluster.Reconciled, h.Cfg.Polling.Interval).
38+
Should(helper.HaveResourceCondition(client.ConditionTypeReconciled, openapi.ResourceConditionStatusTrue))
39+
40+
ginkgo.By("confirming reconciled state via GET")
41+
reconciledCluster, err := h.Client.GetCluster(ctx, clusterID)
42+
Expect(err).NotTo(HaveOccurred())
43+
Expect(reconciledCluster).NotTo(BeNil(), "GET should return cluster object")
44+
Expect(reconciledCluster.Status).NotTo(BeNil())
45+
Expect(h.HasResourceCondition(reconciledCluster.Status.Conditions,
46+
client.ConditionTypeReconciled, openapi.ResourceConditionStatusTrue)).To(BeTrue())
47+
48+
ginkgo.By("soft-deleting the cluster")
49+
deletedCluster, err := h.Client.DeleteCluster(ctx, clusterID)
50+
Expect(err).NotTo(HaveOccurred(), "DELETE should return 202")
51+
Expect(deletedCluster).NotTo(BeNil(), "DELETE should return cluster object")
52+
Expect(deletedCluster.DeletedTime).NotTo(BeNil())
53+
54+
ginkgo.By("waiting for hard-delete (404)")
55+
Eventually(h.PollClusterHTTPStatus(ctx, clusterID), h.Cfg.Timeouts.Adapter.Processing, h.Cfg.Polling.Interval).
56+
Should(Equal(http.StatusNotFound))
57+
58+
ginkgo.By("confirming K8s namespace is cleaned up")
59+
Eventually(h.PollNamespacesByPrefix(ctx, clusterID), h.Cfg.Timeouts.Adapter.Processing, h.Cfg.Polling.Interval).
60+
Should(BeEmpty())
61+
})
62+
},
63+
)

e2e/nodepool/lifecycle_smoke.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package nodepool
2+
3+
import (
4+
"context"
5+
"net/http"
6+
7+
"github.com/onsi/ginkgo/v2"
8+
. "github.com/onsi/gomega" //nolint:staticcheck // dot import for test readability
9+
10+
"github.com/openshift-hyperfleet/hyperfleet-e2e/pkg/api/openapi"
11+
"github.com/openshift-hyperfleet/hyperfleet-e2e/pkg/client"
12+
"github.com/openshift-hyperfleet/hyperfleet-e2e/pkg/helper"
13+
"github.com/openshift-hyperfleet/hyperfleet-e2e/pkg/labels"
14+
)
15+
16+
var _ = ginkgo.Describe("[Suite: nodepool][baseline] NodePool Full Lifecycle Smoke",
17+
ginkgo.Label(labels.Tier0),
18+
func() {
19+
ginkgo.It("should complete create → Reconciled → update → re-Reconciled → delete → hard-delete in a single pass",
20+
func(ctx context.Context) {
21+
h := helper.New()
22+
23+
ginkgo.By("creating a parent cluster and waiting for Reconciled")
24+
clusterID, err := h.GetTestCluster(ctx, h.TestDataPath("payloads/clusters/cluster-request.json"))
25+
Expect(err).NotTo(HaveOccurred(), "failed to create cluster")
26+
27+
ginkgo.DeferCleanup(func(ctx context.Context) {
28+
if err := h.CleanupTestCluster(ctx, clusterID); err != nil {
29+
ginkgo.GinkgoWriter.Printf("Warning: cleanup failed for cluster %s: %v\n", clusterID, err)
30+
}
31+
})
32+
33+
Eventually(h.PollCluster(ctx, clusterID), h.Cfg.Timeouts.Cluster.Reconciled, h.Cfg.Polling.Interval).
34+
Should(helper.HaveResourceCondition(client.ConditionTypeReconciled, openapi.ResourceConditionStatusTrue))
35+
36+
ginkgo.By("creating a nodepool")
37+
np, err := h.Client.CreateNodePoolFromPayload(ctx, clusterID, h.TestDataPath("payloads/nodepools/nodepool-request.json"))
38+
Expect(err).NotTo(HaveOccurred(), "create should succeed")
39+
Expect(np).NotTo(BeNil(), "create should return nodepool object")
40+
Expect(np.Id).NotTo(BeNil(), "nodepool ID should be assigned")
41+
nodepoolID := *np.Id
42+
43+
ginkgo.By("waiting for Reconciled=True at generation 1")
44+
Eventually(h.PollNodePool(ctx, clusterID, nodepoolID), h.Cfg.Timeouts.NodePool.Reconciled, h.Cfg.Polling.Interval).
45+
Should(helper.HaveResourceCondition(client.ConditionTypeReconciled, openapi.ResourceConditionStatusTrue))
46+
47+
ginkgo.By("PATCHing nodepool spec to trigger generation bump")
48+
patched, err := h.Client.PatchNodePool(ctx, clusterID, nodepoolID, openapi.NodePoolPatchRequest{
49+
Spec: &openapi.NodePoolSpec{"lifecycle-test": "updated"},
50+
})
51+
Expect(err).NotTo(HaveOccurred(), "PATCH should succeed")
52+
Expect(patched).NotTo(BeNil(), "PATCH should return nodepool object")
53+
Expect(patched.Generation).To(Equal(int32(2)), "generation should increment after PATCH")
54+
55+
ginkgo.By("waiting for Reconciled=True at generation 2")
56+
Eventually(h.PollNodePoolAdapterStatuses(ctx, clusterID, nodepoolID),
57+
h.Cfg.Timeouts.Adapter.Processing, h.Cfg.Polling.Interval).
58+
Should(helper.HaveAllAdaptersAtGeneration(h.Cfg.Adapters.NodePool, int32(2)))
59+
60+
Eventually(h.PollNodePool(ctx, clusterID, nodepoolID), h.Cfg.Timeouts.NodePool.Reconciled, h.Cfg.Polling.Interval).
61+
Should(helper.HaveResourceCondition(client.ConditionTypeReconciled, openapi.ResourceConditionStatusTrue))
62+
63+
ginkgo.By("soft-deleting the nodepool")
64+
deletedNP, err := h.Client.DeleteNodePool(ctx, clusterID, nodepoolID)
65+
Expect(err).NotTo(HaveOccurred(), "DELETE should return 202")
66+
Expect(deletedNP).NotTo(BeNil(), "DELETE should return nodepool object")
67+
Expect(deletedNP.DeletedTime).NotTo(BeNil())
68+
69+
ginkgo.By("waiting for hard-delete (404)")
70+
Eventually(h.PollNodePoolHTTPStatus(ctx, clusterID, nodepoolID),
71+
h.Cfg.Timeouts.Adapter.Processing, h.Cfg.Polling.Interval).
72+
Should(Equal(http.StatusNotFound))
73+
74+
ginkgo.By("verifying parent cluster is unaffected")
75+
parentCluster, err := h.Client.GetCluster(ctx, clusterID)
76+
Expect(err).NotTo(HaveOccurred(), "parent cluster should still exist")
77+
Expect(parentCluster).NotTo(BeNil(), "GET should return parent cluster object")
78+
Expect(parentCluster.DeletedTime).To(BeNil(), "parent cluster should not be deleted")
79+
Expect(parentCluster).To(helper.HaveResourceCondition(
80+
client.ConditionTypeReconciled, openapi.ResourceConditionStatusTrue),
81+
"parent cluster should remain Reconciled=True")
82+
})
83+
},
84+
)

0 commit comments

Comments
 (0)