|
| 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