diff --git a/test/e2e/README.md b/test/e2e/README.md index 59adc1c..bc1e929 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -474,8 +474,9 @@ It("should reload when SecretProviderClassPodStatus changes", func() { utils.NewSPCPSObjects("secret1", "v2")) Expect(err).NotTo(HaveOccurred()) - // Verify reload - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + // Verify reload using adapter + adapter := utils.NewDeploymentAdapter(kubeClient) + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue()) @@ -489,6 +490,7 @@ Verify that something does NOT trigger a reload: ```go It("should NOT reload when only labels change", func() { // Setup... + adapter := utils.NewDeploymentAdapter(kubeClient) // Make a change that shouldn't trigger reload err = utils.UpdateConfigMapLabels(ctx, kubeClient, testNamespace, configMapName, @@ -497,7 +499,7 @@ It("should NOT reload when only labels change", func() { // Wait briefly, then verify NO reload time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "Should NOT have reloaded") diff --git a/test/e2e/advanced/job_reload_test.go b/test/e2e/advanced/job_reload_test.go index b003475..4bffebe 100644 --- a/test/e2e/advanced/job_reload_test.go +++ b/test/e2e/advanced/job_reload_test.go @@ -17,6 +17,7 @@ var _ = Describe("Job Workload Recreation Tests", func() { secretName string spcName string vaultSecretPath string + jobAdapter *utils.JobAdapter ) BeforeEach(func() { @@ -25,6 +26,7 @@ var _ = Describe("Job Workload Recreation Tests", func() { secretName = utils.RandName("secret") spcName = utils.RandName("spc") vaultSecretPath = fmt.Sprintf("secret/%s", utils.RandName("vault")) + jobAdapter = utils.NewJobAdapter(kubeClient) }) AfterEach(func() { @@ -50,7 +52,7 @@ var _ = Describe("Job Workload Recreation Tests", func() { originalUID := string(job.UID) By("Waiting for Job to be ready") - err = utils.WaitForJobReady(ctx, kubeClient, testNamespace, jobName, utils.DeploymentReady) + err = jobAdapter.WaitReady(ctx, testNamespace, jobName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap") @@ -58,8 +60,7 @@ var _ = Describe("Job Workload Recreation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Job to be recreated (new UID)") - _, recreated, err := utils.WaitForJobRecreated(ctx, kubeClient, testNamespace, jobName, originalUID, - utils.ReloadTimeout) + _, recreated, err := jobAdapter.WaitRecreated(ctx, testNamespace, jobName, originalUID, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(recreated).To(BeTrue(), "Job should be recreated with new UID when ConfigMap changes") }) @@ -79,7 +80,7 @@ var _ = Describe("Job Workload Recreation Tests", func() { originalUID := string(job.UID) By("Waiting for Job to be ready") - err = utils.WaitForJobReady(ctx, kubeClient, testNamespace, jobName, utils.DeploymentReady) + err = jobAdapter.WaitReady(ctx, testNamespace, jobName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the Secret") @@ -87,8 +88,7 @@ var _ = Describe("Job Workload Recreation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Job to be recreated (new UID)") - _, recreated, err := utils.WaitForJobRecreated(ctx, kubeClient, testNamespace, jobName, originalUID, - utils.ReloadTimeout) + _, recreated, err := jobAdapter.WaitRecreated(ctx, testNamespace, jobName, originalUID, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(recreated).To(BeTrue(), "Job should be recreated with new UID when Secret changes") }) @@ -109,7 +109,7 @@ var _ = Describe("Job Workload Recreation Tests", func() { originalUID := string(job.UID) By("Waiting for Job to be ready") - err = utils.WaitForJobReady(ctx, kubeClient, testNamespace, jobName, utils.DeploymentReady) + err = jobAdapter.WaitReady(ctx, testNamespace, jobName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap") @@ -117,8 +117,7 @@ var _ = Describe("Job Workload Recreation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Job to be recreated (new UID)") - _, recreated, err := utils.WaitForJobRecreated(ctx, kubeClient, testNamespace, jobName, originalUID, - utils.ReloadTimeout) + _, recreated, err := jobAdapter.WaitRecreated(ctx, testNamespace, jobName, originalUID, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(recreated).To(BeTrue(), "Job with auto=true should be recreated when ConfigMap changes") }) @@ -139,7 +138,7 @@ var _ = Describe("Job Workload Recreation Tests", func() { originalUID := string(job.UID) By("Waiting for Job to be ready") - err = utils.WaitForJobReady(ctx, kubeClient, testNamespace, jobName, utils.DeploymentReady) + err = jobAdapter.WaitReady(ctx, testNamespace, jobName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap") @@ -147,8 +146,7 @@ var _ = Describe("Job Workload Recreation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Job to be recreated (new UID)") - _, recreated, err := utils.WaitForJobRecreated(ctx, kubeClient, testNamespace, jobName, originalUID, - utils.ReloadTimeout) + _, recreated, err := jobAdapter.WaitRecreated(ctx, testNamespace, jobName, originalUID, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(recreated).To(BeTrue(), "Job with valueFrom.configMapKeyRef should be recreated when ConfigMap changes") @@ -170,7 +168,7 @@ var _ = Describe("Job Workload Recreation Tests", func() { originalUID := string(job.UID) By("Waiting for Job to be ready") - err = utils.WaitForJobReady(ctx, kubeClient, testNamespace, jobName, utils.DeploymentReady) + err = jobAdapter.WaitReady(ctx, testNamespace, jobName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the Secret") @@ -178,8 +176,7 @@ var _ = Describe("Job Workload Recreation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Job to be recreated (new UID)") - _, recreated, err := utils.WaitForJobRecreated(ctx, kubeClient, testNamespace, jobName, originalUID, - utils.ReloadTimeout) + _, recreated, err := jobAdapter.WaitRecreated(ctx, testNamespace, jobName, originalUID, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(recreated).To(BeTrue(), "Job with valueFrom.secretKeyRef should be recreated when Secret changes") }) @@ -218,7 +215,7 @@ var _ = Describe("Job Workload Recreation Tests", func() { originalUID := string(job.UID) By("Waiting for Job to be ready") - err = utils.WaitForJobReady(ctx, kubeClient, testNamespace, jobName, utils.DeploymentReady) + err = jobAdapter.WaitReady(ctx, testNamespace, jobName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Finding the SPCPS created by CSI driver") @@ -244,8 +241,7 @@ var _ = Describe("Job Workload Recreation Tests", func() { GinkgoWriter.Println("CSI driver synced new secret version") By("Waiting for Job to be recreated (new UID)") - _, recreated, err := utils.WaitForJobRecreated(ctx, kubeClient, testNamespace, jobName, originalUID, - utils.ReloadTimeout) + _, recreated, err := jobAdapter.WaitRecreated(ctx, testNamespace, jobName, originalUID, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(recreated).To(BeTrue(), "Job should be recreated with new UID when Vault secret changes") }) diff --git a/test/e2e/advanced/multi_container_test.go b/test/e2e/advanced/multi_container_test.go index ac4a3a5..003fd64 100644 --- a/test/e2e/advanced/multi_container_test.go +++ b/test/e2e/advanced/multi_container_test.go @@ -15,12 +15,14 @@ var _ = Describe("Multi-Container Tests", func() { deploymentName string configMapName string configMapName2 string + adapter *utils.DeploymentAdapter ) BeforeEach(func() { deploymentName = utils.RandName("deploy") configMapName = utils.RandName("cm") configMapName2 = utils.RandName("cm2") + adapter = utils.NewDeploymentAdapter(kubeClient) }) AfterEach(func() { @@ -45,7 +47,7 @@ var _ = Describe("Multi-Container Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap") @@ -53,7 +55,7 @@ var _ = Describe("Multi-Container Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment with multiple containers should be reloaded") @@ -79,7 +81,7 @@ var _ = Describe("Multi-Container Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the first ConfigMap") @@ -87,7 +89,7 @@ var _ = Describe("Multi-Container Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should be reloaded when first container's ConfigMap changes") @@ -139,7 +141,7 @@ var _ = Describe("Multi-Container Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Finding the SPCPS created by CSI driver") @@ -161,7 +163,7 @@ var _ = Describe("Multi-Container Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment with init container using CSI volume should be reloaded") @@ -186,7 +188,7 @@ var _ = Describe("Multi-Container Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Finding the SPCPS created by CSI driver") @@ -208,7 +210,7 @@ var _ = Describe("Multi-Container Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment with init container CSI volume and auto=true should be reloaded") diff --git a/test/e2e/advanced/regex_test.go b/test/e2e/advanced/regex_test.go index 40b8044..c6165e6 100644 --- a/test/e2e/advanced/regex_test.go +++ b/test/e2e/advanced/regex_test.go @@ -15,6 +15,7 @@ var _ = Describe("Regex Pattern Tests", func() { matchingCM string nonMatchingCM string matchingSecret string + adapter *utils.DeploymentAdapter ) BeforeEach(func() { @@ -22,6 +23,7 @@ var _ = Describe("Regex Pattern Tests", func() { matchingCM = "app-config-" + utils.RandName("cm") nonMatchingCM = "other-" + utils.RandName("cm") matchingSecret = "app-secret-" + utils.RandName("secret") + adapter = utils.NewDeploymentAdapter(kubeClient) }) AfterEach(func() { @@ -48,7 +50,7 @@ var _ = Describe("Regex Pattern Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the matching ConfigMap") @@ -56,7 +58,7 @@ var _ = Describe("Regex Pattern Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should be reloaded when matching ConfigMap changes") @@ -82,7 +84,7 @@ var _ = Describe("Regex Pattern Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the non-matching ConfigMap") @@ -91,7 +93,7 @@ var _ = Describe("Regex Pattern Tests", func() { By("Verifying Deployment was NOT reloaded (pattern mismatch)") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "Deployment should NOT reload when non-matching ConfigMap changes") @@ -115,7 +117,7 @@ var _ = Describe("Regex Pattern Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the matching Secret") @@ -123,7 +125,7 @@ var _ = Describe("Regex Pattern Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should be reloaded when matching Secret changes") diff --git a/test/e2e/annotations/auto_reload_test.go b/test/e2e/annotations/auto_reload_test.go index f8499b2..e0465cd 100644 --- a/test/e2e/annotations/auto_reload_test.go +++ b/test/e2e/annotations/auto_reload_test.go @@ -17,6 +17,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { secretName string spcName string vaultSecretPath string + adapter *utils.DeploymentAdapter ) BeforeEach(func() { @@ -25,6 +26,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { secretName = utils.RandName("secret") spcName = utils.RandName("spc") vaultSecretPath = fmt.Sprintf("secret/%s", utils.RandName("test")) + adapter = utils.NewDeploymentAdapter(kubeClient) }) AfterEach(func() { @@ -52,7 +54,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap data") @@ -60,7 +62,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment with auto=true should have been reloaded") @@ -80,7 +82,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the Secret data") @@ -88,7 +90,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment with auto=true should have been reloaded for Secret change") @@ -113,7 +115,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap") @@ -121,7 +123,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment with auto=true should have been reloaded for ConfigMap change") @@ -143,7 +145,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap data") @@ -152,7 +154,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { By("Verifying Deployment is NOT reloaded (negative test)") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "Deployment with auto=false should NOT have been reloaded") @@ -179,7 +181,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap") @@ -187,7 +189,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should have been reloaded for ConfigMap change") @@ -214,7 +216,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the Secret") @@ -222,7 +224,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should have been reloaded for Secret change") @@ -257,7 +259,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Finding the SPCPS created by CSI driver") @@ -280,7 +282,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { GinkgoWriter.Println("CSI driver synced new secret version") By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should have been reloaded for Vault secret change") @@ -310,7 +312,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Finding the SPCPS created by CSI driver") @@ -323,7 +325,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { By("Verifying Deployment was NOT reloaded for ConfigMap change") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "Deployment with SPC auto only should NOT have been reloaded for ConfigMap change") @@ -341,7 +343,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded for SPC change") - reloaded, err = utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err = adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should have been reloaded for Vault secret change") @@ -365,7 +367,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Finding the SPCPS created by CSI driver") @@ -385,7 +387,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment with auto=true should have been reloaded for Vault secret change") @@ -418,7 +420,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the second ConfigMap (auto-detected)") @@ -426,7 +428,7 @@ var _ = Describe("Auto Reload Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should have been reloaded for auto-detected ConfigMap change") diff --git a/test/e2e/annotations/combination_test.go b/test/e2e/annotations/combination_test.go index 51a093e..4517a79 100644 --- a/test/e2e/annotations/combination_test.go +++ b/test/e2e/annotations/combination_test.go @@ -16,6 +16,7 @@ var _ = Describe("Combination Annotation Tests", func() { configMapName2 string secretName string secretName2 string + adapter *utils.DeploymentAdapter ) BeforeEach(func() { @@ -24,6 +25,7 @@ var _ = Describe("Combination Annotation Tests", func() { configMapName2 = utils.RandName("cm2") secretName = utils.RandName("secret") secretName2 = utils.RandName("secret2") + adapter = utils.NewDeploymentAdapter(kubeClient) }) AfterEach(func() { @@ -55,7 +57,7 @@ var _ = Describe("Combination Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the auto-detected ConfigMap") @@ -63,7 +65,7 @@ var _ = Describe("Combination Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should reload when auto-detected ConfigMap changes") @@ -89,7 +91,7 @@ var _ = Describe("Combination Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the explicitly listed ConfigMap (not mounted)") @@ -97,7 +99,7 @@ var _ = Describe("Combination Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should reload when explicitly listed ConfigMap changes") @@ -123,7 +125,7 @@ var _ = Describe("Combination Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the explicitly listed Secret") @@ -131,7 +133,7 @@ var _ = Describe("Combination Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should reload when explicitly listed Secret changes") @@ -160,7 +162,7 @@ var _ = Describe("Combination Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the excluded ConfigMap") @@ -169,7 +171,7 @@ var _ = Describe("Combination Annotation Tests", func() { By("Verifying Deployment was NOT reloaded (negative test)") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "Deployment should NOT reload when excluded ConfigMap changes") @@ -196,7 +198,7 @@ var _ = Describe("Combination Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the non-excluded ConfigMap") @@ -204,7 +206,7 @@ var _ = Describe("Combination Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should reload when non-excluded ConfigMap changes") @@ -231,7 +233,7 @@ var _ = Describe("Combination Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the excluded Secret") @@ -240,7 +242,7 @@ var _ = Describe("Combination Annotation Tests", func() { By("Verifying Deployment was NOT reloaded (negative test)") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "Deployment should NOT reload when excluded Secret changes") @@ -264,7 +266,7 @@ var _ = Describe("Combination Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the second ConfigMap") @@ -272,7 +274,7 @@ var _ = Describe("Combination Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should reload when any of the listed ConfigMaps changes") @@ -294,7 +296,7 @@ var _ = Describe("Combination Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the first Secret") @@ -302,7 +304,7 @@ var _ = Describe("Combination Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should reload when any of the listed Secrets changes") @@ -327,7 +329,7 @@ var _ = Describe("Combination Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the Secret") @@ -335,7 +337,7 @@ var _ = Describe("Combination Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should reload when Secret changes with both annotations present") diff --git a/test/e2e/annotations/exclude_test.go b/test/e2e/annotations/exclude_test.go index 2313a87..3b0f1e5 100644 --- a/test/e2e/annotations/exclude_test.go +++ b/test/e2e/annotations/exclude_test.go @@ -18,6 +18,7 @@ var _ = Describe("Exclude Annotation Tests", func() { secretName string secretName2 string workloadName string + adapter *utils.DeploymentAdapter ) BeforeEach(func() { @@ -27,6 +28,7 @@ var _ = Describe("Exclude Annotation Tests", func() { secretName = utils.RandName("secret") secretName2 = utils.RandName("secret2") workloadName = utils.RandName("workload") + adapter = utils.NewDeploymentAdapter(kubeClient) }) AfterEach(func() { @@ -60,7 +62,7 @@ var _ = Describe("Exclude Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the excluded ConfigMap") @@ -69,7 +71,7 @@ var _ = Describe("Exclude Annotation Tests", func() { By("Verifying Deployment was NOT reloaded (excluded ConfigMap)") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "Deployment should NOT reload when excluded ConfigMap changes") @@ -97,7 +99,7 @@ var _ = Describe("Exclude Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the non-excluded ConfigMap") @@ -105,7 +107,7 @@ var _ = Describe("Exclude Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should reload when non-excluded ConfigMap changes") @@ -135,7 +137,7 @@ var _ = Describe("Exclude Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the excluded Secret") @@ -144,7 +146,7 @@ var _ = Describe("Exclude Annotation Tests", func() { By("Verifying Deployment was NOT reloaded (excluded Secret)") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "Deployment should NOT reload when excluded Secret changes") @@ -172,7 +174,7 @@ var _ = Describe("Exclude Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the non-excluded Secret") @@ -180,7 +182,7 @@ var _ = Describe("Exclude Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should reload when non-excluded Secret changes") @@ -290,7 +292,7 @@ var _ = Describe("Exclude Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Finding the SPCPS created by CSI driver") @@ -313,7 +315,7 @@ var _ = Describe("Exclude Annotation Tests", func() { By("Verifying Deployment was NOT reloaded (excluded SPC)") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "Deployment should NOT reload when excluded SecretProviderClassPodStatus changes") @@ -350,7 +352,7 @@ var _ = Describe("Exclude Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Finding the SPCPS for non-excluded SPC") @@ -373,7 +375,7 @@ var _ = Describe("Exclude Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should reload when non-excluded SecretProviderClassPodStatus changes") diff --git a/test/e2e/annotations/pause_period_test.go b/test/e2e/annotations/pause_period_test.go index 74bc170..f1aa17b 100644 --- a/test/e2e/annotations/pause_period_test.go +++ b/test/e2e/annotations/pause_period_test.go @@ -13,11 +13,13 @@ var _ = Describe("Pause Period Tests", func() { var ( deploymentName string configMapName string + adapter *utils.DeploymentAdapter ) BeforeEach(func() { deploymentName = utils.RandName("deploy") configMapName = utils.RandName("cm") + adapter = utils.NewDeploymentAdapter(kubeClient) }) AfterEach(func() { @@ -43,7 +45,7 @@ var _ = Describe("Pause Period Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap data") @@ -51,13 +53,13 @@ var _ = Describe("Pause Period Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should have been reloaded") By("Verifying Deployment has paused-at annotation") - paused, err := utils.WaitForDeploymentPaused(ctx, kubeClient, testNamespace, deploymentName, + paused, err := adapter.WaitPaused(ctx, testNamespace, deploymentName, utils.AnnotationDeploymentPausedAt, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(paused).To(BeTrue(), "Deployment should have paused-at annotation after reload") @@ -77,7 +79,7 @@ var _ = Describe("Pause Period Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap data") @@ -85,14 +87,14 @@ var _ = Describe("Pause Period Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should have been reloaded") By("Verifying Deployment does NOT have paused-at annotation") time.Sleep(utils.NegativeTestWait) - paused, err := utils.WaitForDeploymentPaused(ctx, kubeClient, testNamespace, deploymentName, + paused, err := adapter.WaitPaused(ctx, testNamespace, deploymentName, utils.AnnotationDeploymentPausedAt, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(paused).To(BeFalse(), "Deployment should NOT have paused-at annotation without pause-period") @@ -117,7 +119,7 @@ var _ = Describe("Pause Period Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap data") @@ -125,13 +127,13 @@ var _ = Describe("Pause Period Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should have been reloaded") By("Verifying Deployment has paused-at annotation") - paused, err := utils.WaitForDeploymentPaused(ctx, kubeClient, testNamespace, deploymentName, + paused, err := adapter.WaitPaused(ctx, testNamespace, deploymentName, utils.AnnotationDeploymentPausedAt, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(paused).To(BeTrue(), "Deployment should have paused-at annotation with pause-period on pod template") diff --git a/test/e2e/annotations/resource_ignore_test.go b/test/e2e/annotations/resource_ignore_test.go index 0a8845d..8a9c163 100644 --- a/test/e2e/annotations/resource_ignore_test.go +++ b/test/e2e/annotations/resource_ignore_test.go @@ -14,12 +14,14 @@ var _ = Describe("Resource Ignore Annotation Tests", func() { deploymentName string configMapName string secretName string + adapter *utils.DeploymentAdapter ) BeforeEach(func() { deploymentName = utils.RandName("deploy") configMapName = utils.RandName("cm") secretName = utils.RandName("secret") + adapter = utils.NewDeploymentAdapter(kubeClient) }) AfterEach(func() { @@ -44,7 +46,7 @@ var _ = Describe("Resource Ignore Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap data") @@ -53,7 +55,7 @@ var _ = Describe("Resource Ignore Annotation Tests", func() { By("Verifying Deployment was NOT reloaded (negative test)") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "Deployment should NOT reload when ConfigMap has ignore=true") @@ -74,7 +76,7 @@ var _ = Describe("Resource Ignore Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the Secret data") @@ -83,7 +85,7 @@ var _ = Describe("Resource Ignore Annotation Tests", func() { By("Verifying Deployment was NOT reloaded (negative test)") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "Deployment should NOT reload when Secret has ignore=true") diff --git a/test/e2e/annotations/search_match_test.go b/test/e2e/annotations/search_match_test.go index 95bb457..a96f6c3 100644 --- a/test/e2e/annotations/search_match_test.go +++ b/test/e2e/annotations/search_match_test.go @@ -15,12 +15,14 @@ var _ = Describe("Search and Match Annotation Tests", func() { deploymentName string configMapName string workloadName string + adapter *utils.DeploymentAdapter ) BeforeEach(func() { deploymentName = utils.RandName("deploy") configMapName = utils.RandName("cm") workloadName = utils.RandName("workload") + adapter = utils.NewDeploymentAdapter(kubeClient) }) AfterEach(func() { @@ -44,7 +46,7 @@ var _ = Describe("Search and Match Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap data") @@ -52,7 +54,7 @@ var _ = Describe("Search and Match Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment with search annotation should reload when ConfigMap has match annotation") @@ -72,7 +74,7 @@ var _ = Describe("Search and Match Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap data") @@ -81,7 +83,7 @@ var _ = Describe("Search and Match Annotation Tests", func() { By("Verifying Deployment was NOT reloaded (negative test)") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "Deployment should NOT reload when ConfigMap lacks match annotation") @@ -102,7 +104,7 @@ var _ = Describe("Search and Match Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap data") @@ -111,7 +113,7 @@ var _ = Describe("Search and Match Annotation Tests", func() { By("Verifying Deployment was NOT reloaded (negative test)") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "Deployment without search annotation should NOT reload even when ConfigMap has match") @@ -144,9 +146,9 @@ var _ = Describe("Search and Match Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for both Deployments to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName2, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName2, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap data") @@ -154,13 +156,13 @@ var _ = Describe("Search and Match Annotation Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for first Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment with search annotation should reload") By("Verifying second Deployment was NOT reloaded") - reloaded2, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName2, + reloaded2, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName2, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded2).To(BeFalse(), "Deployment without search annotation should NOT reload") diff --git a/test/e2e/argo/rollout_test.go b/test/e2e/argo/rollout_test.go index eddd073..65e0801 100644 --- a/test/e2e/argo/rollout_test.go +++ b/test/e2e/argo/rollout_test.go @@ -15,11 +15,13 @@ var _ = Describe("Argo Rollout Strategy Tests", func() { var ( rolloutName string configMapName string + adapter *utils.ArgoRolloutAdapter ) BeforeEach(func() { rolloutName = utils.RandName("rollout") configMapName = utils.RandName("cm") + adapter = utils.NewArgoRolloutAdapter(rolloutsClient) }) AfterEach(func() { @@ -44,7 +46,7 @@ var _ = Describe("Argo Rollout Strategy Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Rollout to be ready") - err = utils.WaitForRolloutReady(ctx, rolloutsClient, testNamespace, rolloutName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, rolloutName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap") @@ -52,7 +54,7 @@ var _ = Describe("Argo Rollout Strategy Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Rollout to be reloaded with annotation") - reloaded, err := utils.WaitForRolloutReloaded(ctx, rolloutsClient, testNamespace, rolloutName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, rolloutName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Argo Rollout should be reloaded with default rollout strategy") @@ -74,7 +76,7 @@ var _ = Describe("Argo Rollout Strategy Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Rollout to be ready") - err = utils.WaitForRolloutReady(ctx, rolloutsClient, testNamespace, rolloutName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, rolloutName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap") @@ -82,7 +84,7 @@ var _ = Describe("Argo Rollout Strategy Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Rollout to have restartAt field set") - restarted, err := utils.WaitForRolloutRestartAt(ctx, rolloutsClient, testNamespace, rolloutName, utils.ReloadTimeout) + restarted, err := adapter.WaitRestartAt(ctx, testNamespace, rolloutName, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(restarted).To(BeTrue(), "Argo Rollout should have restartAt field set with restart strategy") }) diff --git a/test/e2e/core/workloads_test.go b/test/e2e/core/workloads_test.go index 2f07a6b..39dd2c7 100644 --- a/test/e2e/core/workloads_test.go +++ b/test/e2e/core/workloads_test.go @@ -1654,8 +1654,10 @@ var _ = Describe("Workload Reload Tests", func() { Expect(err).NotTo(HaveOccurred()) DeferCleanup(func() { _ = utils.DeleteDeployment(ctx, kubeClient, testNamespace, workloadName) }) + adapter := utils.NewDeploymentAdapter(kubeClient) + By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, workloadName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, workloadName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Finding the SPCPS created by CSI driver") @@ -1677,7 +1679,7 @@ var _ = Describe("Workload Reload Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to have STAKATER_ env var") - found, err := utils.WaitForDeploymentEnvVar(ctx, kubeClient, testNamespace, workloadName, + found, err := adapter.WaitEnvVar(ctx, testNamespace, workloadName, utils.StakaterEnvVarPrefix, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(found).To(BeTrue(), "Deployment with init container CSI should have STAKATER_ env var") diff --git a/test/e2e/csi/csi_test.go b/test/e2e/csi/csi_test.go index fad2baf..192a6e5 100644 --- a/test/e2e/csi/csi_test.go +++ b/test/e2e/csi/csi_test.go @@ -10,12 +10,13 @@ import ( "github.com/stakater/Reloader/test/e2e/utils" ) -var _ = Describe("CSI SecretProviderClass Tests", func() { +var _ = Describe("CSI SecretProviderClass Tests", Label("csi"), func() { var ( deploymentName string configMapName string spcName string vaultSecretPath string + adapter *utils.DeploymentAdapter ) BeforeEach(func() { @@ -24,6 +25,7 @@ var _ = Describe("CSI SecretProviderClass Tests", func() { spcName = utils.RandName("spc") // Each test gets its own Vault secret path to avoid conflicts vaultSecretPath = fmt.Sprintf("secret/%s", utils.RandName("test")) + adapter = utils.NewDeploymentAdapter(kubeClient) }) AfterEach(func() { @@ -57,7 +59,7 @@ var _ = Describe("CSI SecretProviderClass Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Finding the SPCPS created by CSI driver") @@ -84,8 +86,8 @@ var _ = Describe("CSI SecretProviderClass Tests", func() { GinkgoWriter.Println("CSI driver synced new secret version") By("Waiting for Deployment to be reloaded by Reloader") - reloaded, err := utils.WaitForDeploymentReloaded( - ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded( + ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout, ) Expect(err).NotTo(HaveOccurred()) @@ -114,7 +116,7 @@ var _ = Describe("CSI SecretProviderClass Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Finding the SPCPS") @@ -134,8 +136,8 @@ var _ = Describe("CSI SecretProviderClass Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for first reload") - reloaded, err := utils.WaitForDeploymentReloaded( - ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded( + ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout, ) Expect(err).NotTo(HaveOccurred()) @@ -148,7 +150,7 @@ var _ = Describe("CSI SecretProviderClass Tests", func() { Expect(firstReloadValue).NotTo(BeEmpty()) By("Waiting for Deployment to stabilize") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Finding the NEW SPCPS after first reload (new pod = new SPCPS)") @@ -205,7 +207,7 @@ var _ = Describe("CSI SecretProviderClass Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap (should NOT trigger reload)") @@ -215,8 +217,8 @@ var _ = Describe("CSI SecretProviderClass Tests", func() { By("Verifying Deployment was NOT reloaded for ConfigMap change") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded( - ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded( + ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout, ) Expect(err).NotTo(HaveOccurred()) @@ -241,8 +243,8 @@ var _ = Describe("CSI SecretProviderClass Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Verifying Deployment WAS reloaded for Vault secret change") - reloaded, err = utils.WaitForDeploymentReloaded( - ctx, kubeClient, testNamespace, deploymentName, + reloaded, err = adapter.WaitReloaded( + ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout, ) Expect(err).NotTo(HaveOccurred()) @@ -279,7 +281,7 @@ var _ = Describe("CSI SecretProviderClass Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap (should trigger reload with auto=true)") @@ -288,15 +290,15 @@ var _ = Describe("CSI SecretProviderClass Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Verifying Deployment WAS reloaded for ConfigMap change") - reloaded, err := utils.WaitForDeploymentReloaded( - ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded( + ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout, ) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Combined auto=true should trigger reload for ConfigMap changes") By("Waiting for Deployment to stabilize") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Getting current annotation value") diff --git a/test/e2e/flags/auto_reload_all_test.go b/test/e2e/flags/auto_reload_all_test.go index c0c8625..3f94166 100644 --- a/test/e2e/flags/auto_reload_all_test.go +++ b/test/e2e/flags/auto_reload_all_test.go @@ -14,12 +14,14 @@ var _ = Describe("Auto Reload All Flag Tests", func() { deploymentName string configMapName string autoNamespace string + adapter *utils.DeploymentAdapter ) BeforeEach(func() { deploymentName = utils.RandName("deploy") configMapName = utils.RandName("cm") autoNamespace = "auto-" + utils.RandName("ns") + adapter = utils.NewDeploymentAdapter(kubeClient) }) AfterEach(func() { @@ -59,7 +61,7 @@ var _ = Describe("Auto Reload All Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, autoNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, autoNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap") @@ -67,7 +69,7 @@ var _ = Describe("Auto Reload All Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded (autoReloadAll=true)") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, autoNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, autoNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment without annotations should reload when autoReloadAll=true") @@ -87,7 +89,7 @@ var _ = Describe("Auto Reload All Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, autoNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, autoNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap") @@ -96,7 +98,7 @@ var _ = Describe("Auto Reload All Flag Tests", func() { By("Verifying Deployment was NOT reloaded (auto=false overrides autoReloadAll)") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, autoNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, autoNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "Deployment with auto=false should NOT reload even with autoReloadAll=true") diff --git a/test/e2e/flags/ignore_resources_test.go b/test/e2e/flags/ignore_resources_test.go index 6a79e0e..330804c 100644 --- a/test/e2e/flags/ignore_resources_test.go +++ b/test/e2e/flags/ignore_resources_test.go @@ -15,6 +15,7 @@ var _ = Describe("Ignore Resources Flag Tests", func() { configMapName string secretName string ignoreNS string + adapter *utils.DeploymentAdapter ) BeforeEach(func() { @@ -22,6 +23,7 @@ var _ = Describe("Ignore Resources Flag Tests", func() { configMapName = utils.RandName("cm") secretName = utils.RandName("secret") ignoreNS = "ignore-" + utils.RandName("ns") + adapter = utils.NewDeploymentAdapter(kubeClient) }) AfterEach(func() { @@ -65,7 +67,7 @@ var _ = Describe("Ignore Resources Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, ignoreNS, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, ignoreNS, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the Secret") @@ -74,7 +76,7 @@ var _ = Describe("Ignore Resources Flag Tests", func() { By("Verifying Deployment was NOT reloaded (ignoreSecrets=true)") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, ignoreNS, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, ignoreNS, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "Deployment should NOT reload when ignoreSecrets=true") @@ -94,7 +96,7 @@ var _ = Describe("Ignore Resources Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, ignoreNS, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, ignoreNS, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap") @@ -102,7 +104,7 @@ var _ = Describe("Ignore Resources Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded (ConfigMap should still work)") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, ignoreNS, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, ignoreNS, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "ConfigMap changes should still trigger reload with ignoreSecrets=true") @@ -144,7 +146,7 @@ var _ = Describe("Ignore Resources Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, ignoreNS, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, ignoreNS, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap") @@ -153,7 +155,7 @@ var _ = Describe("Ignore Resources Flag Tests", func() { By("Verifying Deployment was NOT reloaded (ignoreConfigMaps=true)") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, ignoreNS, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, ignoreNS, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "Deployment should NOT reload when ignoreConfigMaps=true") @@ -173,7 +175,7 @@ var _ = Describe("Ignore Resources Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, ignoreNS, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, ignoreNS, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the Secret") @@ -181,7 +183,7 @@ var _ = Describe("Ignore Resources Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded (Secret should still work)") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, ignoreNS, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, ignoreNS, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Secret changes should still trigger reload with ignoreConfigMaps=true") diff --git a/test/e2e/flags/ignored_workloads_test.go b/test/e2e/flags/ignored_workloads_test.go index e52d329..f704897 100644 --- a/test/e2e/flags/ignored_workloads_test.go +++ b/test/e2e/flags/ignored_workloads_test.go @@ -11,15 +11,19 @@ import ( var _ = Describe("Ignored Workloads Flag Tests", func() { var ( - cronJobName string - configMapName string - ignoreNS string + cronJobName string + configMapName string + ignoreNS string + cronJobAdapter *utils.CronJobAdapter + deploymentAdater *utils.DeploymentAdapter ) BeforeEach(func() { cronJobName = utils.RandName("cj") configMapName = utils.RandName("cm") ignoreNS = "ignore-wl-" + utils.RandName("ns") + cronJobAdapter = utils.NewCronJobAdapter(kubeClient) + deploymentAdater = utils.NewDeploymentAdapter(kubeClient) }) AfterEach(func() { @@ -67,7 +71,7 @@ var _ = Describe("Ignored Workloads Flag Tests", func() { By("Verifying CronJob was NOT reloaded (ignoreCronJobs=true)") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForCronJobReloaded(ctx, kubeClient, ignoreNS, cronJobName, + reloaded, err := cronJobAdapter.WaitReloaded(ctx, ignoreNS, cronJobName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "CronJob should NOT reload when ignoreCronJobs=true") @@ -92,7 +96,7 @@ var _ = Describe("Ignored Workloads Flag Tests", func() { }() By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, ignoreNS, deploymentName, utils.DeploymentReady) + err = deploymentAdater.WaitReady(ctx, ignoreNS, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap") @@ -100,7 +104,7 @@ var _ = Describe("Ignored Workloads Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded (Deployment should still work)") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, ignoreNS, deploymentName, + reloaded, err := deploymentAdater.WaitReloaded(ctx, ignoreNS, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should still reload with ignoreCronJobs=true") @@ -148,7 +152,7 @@ var _ = Describe("Ignored Workloads Flag Tests", func() { By("Verifying CronJob was NOT reloaded") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForCronJobReloaded(ctx, kubeClient, ignoreNS, cronJobName, + reloaded, err := cronJobAdapter.WaitReloaded(ctx, ignoreNS, cronJobName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "CronJob should NOT reload when ignoreCronJobs=true and ignoreJobs=true") diff --git a/test/e2e/flags/namespace_ignore_test.go b/test/e2e/flags/namespace_ignore_test.go index 155f05d..d653fbc 100644 --- a/test/e2e/flags/namespace_ignore_test.go +++ b/test/e2e/flags/namespace_ignore_test.go @@ -15,6 +15,7 @@ var _ = Describe("Namespace Ignore Flag Tests", func() { configMapName string ignoredNamespace string watchedNamespace string + adapter *utils.DeploymentAdapter ) BeforeEach(func() { @@ -22,6 +23,7 @@ var _ = Describe("Namespace Ignore Flag Tests", func() { configMapName = utils.RandName("cm") ignoredNamespace = "ignored-" + utils.RandName("ns") watchedNamespace = "watched-" + utils.RandName("ns") + adapter = utils.NewDeploymentAdapter(kubeClient) }) AfterEach(func() { @@ -67,7 +69,7 @@ var _ = Describe("Namespace Ignore Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, ignoredNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, ignoredNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap") @@ -76,7 +78,7 @@ var _ = Describe("Namespace Ignore Flag Tests", func() { By("Verifying Deployment was NOT reloaded (ignored namespace)") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, ignoredNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, ignoredNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "Deployment in ignored namespace should NOT be reloaded") @@ -96,7 +98,7 @@ var _ = Describe("Namespace Ignore Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, watchedNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, watchedNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap") @@ -104,7 +106,7 @@ var _ = Describe("Namespace Ignore Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, watchedNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, watchedNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment in non-ignored namespace should be reloaded") diff --git a/test/e2e/flags/namespace_selector_test.go b/test/e2e/flags/namespace_selector_test.go index fdcb382..c4acdff 100644 --- a/test/e2e/flags/namespace_selector_test.go +++ b/test/e2e/flags/namespace_selector_test.go @@ -15,6 +15,7 @@ var _ = Describe("Namespace Selector Flag Tests", func() { configMapName string matchingNS string nonMatchingNS string + adapter *utils.DeploymentAdapter ) BeforeEach(func() { @@ -22,6 +23,7 @@ var _ = Describe("Namespace Selector Flag Tests", func() { configMapName = utils.RandName("cm") matchingNS = "match-" + utils.RandName("ns") nonMatchingNS = "nomatch-" + utils.RandName("ns") + adapter = utils.NewDeploymentAdapter(kubeClient) }) AfterEach(func() { @@ -68,7 +70,7 @@ var _ = Describe("Namespace Selector Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, matchingNS, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, matchingNS, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap") @@ -76,7 +78,7 @@ var _ = Describe("Namespace Selector Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, matchingNS, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, matchingNS, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment in matching namespace should be reloaded") @@ -96,7 +98,7 @@ var _ = Describe("Namespace Selector Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, nonMatchingNS, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, nonMatchingNS, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap") @@ -105,7 +107,7 @@ var _ = Describe("Namespace Selector Flag Tests", func() { By("Verifying Deployment was NOT reloaded (non-matching namespace)") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, nonMatchingNS, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, nonMatchingNS, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "Deployment in non-matching namespace should NOT be reloaded") diff --git a/test/e2e/flags/reload_on_create_test.go b/test/e2e/flags/reload_on_create_test.go index 74f2151..bfdadb9 100644 --- a/test/e2e/flags/reload_on_create_test.go +++ b/test/e2e/flags/reload_on_create_test.go @@ -14,12 +14,14 @@ var _ = Describe("Reload On Create Flag Tests", func() { deploymentName string configMapName string createNamespace string + adapter *utils.DeploymentAdapter ) BeforeEach(func() { deploymentName = utils.RandName("deploy") configMapName = utils.RandName("cm") createNamespace = "create-" + utils.RandName("ns") + adapter = utils.NewDeploymentAdapter(kubeClient) }) AfterEach(func() { @@ -56,7 +58,7 @@ var _ = Describe("Reload On Create Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, createNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, createNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Creating the ConfigMap that the Deployment references") @@ -65,7 +67,7 @@ var _ = Describe("Reload On Create Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded (reloadOnCreate=true)") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, createNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, createNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should reload when referenced ConfigMap is created") @@ -82,7 +84,7 @@ var _ = Describe("Reload On Create Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, createNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, createNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Creating the Secret that the Deployment references") @@ -91,7 +93,7 @@ var _ = Describe("Reload On Create Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded (reloadOnCreate=true)") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, createNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, createNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should reload when referenced Secret is created") @@ -125,7 +127,7 @@ var _ = Describe("Reload On Create Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, createNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, createNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Creating the ConfigMap that the Deployment references") @@ -135,7 +137,7 @@ var _ = Describe("Reload On Create Flag Tests", func() { By("Verifying Deployment was NOT reloaded (reloadOnCreate=false)") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, createNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, createNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "Deployment should NOT reload on create when reloadOnCreate=false") diff --git a/test/e2e/flags/reload_on_delete_test.go b/test/e2e/flags/reload_on_delete_test.go index 2ddce7d..12c86d3 100644 --- a/test/e2e/flags/reload_on_delete_test.go +++ b/test/e2e/flags/reload_on_delete_test.go @@ -14,12 +14,14 @@ var _ = Describe("Reload On Delete Flag Tests", func() { deploymentName string configMapName string deleteNamespace string + adapter *utils.DeploymentAdapter ) BeforeEach(func() { deploymentName = utils.RandName("deploy") configMapName = utils.RandName("cm") deleteNamespace = "delete-" + utils.RandName("ns") + adapter = utils.NewDeploymentAdapter(kubeClient) }) AfterEach(func() { @@ -61,7 +63,7 @@ var _ = Describe("Reload On Delete Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, deleteNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, deleteNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Deleting the ConfigMap") @@ -69,7 +71,7 @@ var _ = Describe("Reload On Delete Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded (reloadOnDelete=true)") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, deleteNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, deleteNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should reload when referenced ConfigMap is deleted") @@ -90,7 +92,7 @@ var _ = Describe("Reload On Delete Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, deleteNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, deleteNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Deleting the Secret") @@ -98,7 +100,7 @@ var _ = Describe("Reload On Delete Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded (reloadOnDelete=true)") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, deleteNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, deleteNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should reload when referenced Secret is deleted") @@ -137,7 +139,7 @@ var _ = Describe("Reload On Delete Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, deleteNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, deleteNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Deleting the ConfigMap") @@ -146,7 +148,7 @@ var _ = Describe("Reload On Delete Flag Tests", func() { By("Verifying Deployment was NOT reloaded (reloadOnDelete=false)") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, deleteNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, deleteNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "Deployment should NOT reload on delete when reloadOnDelete=false") diff --git a/test/e2e/flags/resource_selector_test.go b/test/e2e/flags/resource_selector_test.go index 177b052..2bd73f3 100644 --- a/test/e2e/flags/resource_selector_test.go +++ b/test/e2e/flags/resource_selector_test.go @@ -15,6 +15,7 @@ var _ = Describe("Resource Label Selector Flag Tests", func() { matchingCM string nonMatchingCM string resourceNS string + adapter *utils.DeploymentAdapter ) BeforeEach(func() { @@ -22,6 +23,7 @@ var _ = Describe("Resource Label Selector Flag Tests", func() { matchingCM = utils.RandName("match-cm") nonMatchingCM = utils.RandName("nomatch-cm") resourceNS = "resource-" + utils.RandName("ns") + adapter = utils.NewDeploymentAdapter(kubeClient) }) AfterEach(func() { @@ -66,7 +68,7 @@ var _ = Describe("Resource Label Selector Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, resourceNS, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, resourceNS, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the labeled ConfigMap") @@ -74,7 +76,7 @@ var _ = Describe("Resource Label Selector Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, resourceNS, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, resourceNS, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment should be reloaded when labeled ConfigMap changes") @@ -94,7 +96,7 @@ var _ = Describe("Resource Label Selector Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, resourceNS, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, resourceNS, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the unlabeled ConfigMap") @@ -103,7 +105,7 @@ var _ = Describe("Resource Label Selector Flag Tests", func() { By("Verifying Deployment was NOT reloaded (unlabeled ConfigMap)") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, resourceNS, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, resourceNS, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "Deployment should NOT reload when unlabeled ConfigMap changes") diff --git a/test/e2e/flags/watch_globally_test.go b/test/e2e/flags/watch_globally_test.go index 62e3b94..e9d45fe 100644 --- a/test/e2e/flags/watch_globally_test.go +++ b/test/e2e/flags/watch_globally_test.go @@ -14,12 +14,14 @@ var _ = Describe("Watch Globally Flag Tests", func() { deploymentName string configMapName string otherNS string + adapter *utils.DeploymentAdapter ) BeforeEach(func() { deploymentName = utils.RandName("deploy") configMapName = utils.RandName("cm") otherNS = "other-" + utils.RandName("ns") + adapter = utils.NewDeploymentAdapter(kubeClient) }) AfterEach(func() { @@ -66,7 +68,7 @@ var _ = Describe("Watch Globally Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, testNamespace, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, testNamespace, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap") @@ -74,7 +76,7 @@ var _ = Describe("Watch Globally Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded (same namespace should work)") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, testNamespace, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, testNamespace, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment in Reloader's namespace should reload with watchGlobally=false") @@ -94,7 +96,7 @@ var _ = Describe("Watch Globally Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, otherNS, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, otherNS, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap in the other namespace") @@ -103,7 +105,7 @@ var _ = Describe("Watch Globally Flag Tests", func() { By("Verifying Deployment was NOT reloaded (different namespace with watchGlobally=false)") time.Sleep(utils.NegativeTestWait) - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, otherNS, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, otherNS, deploymentName, utils.AnnotationLastReloadedFrom, utils.ShortTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeFalse(), "Deployment in other namespace should NOT reload with watchGlobally=false") @@ -151,7 +153,7 @@ var _ = Describe("Watch Globally Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be ready") - err = utils.WaitForDeploymentReady(ctx, kubeClient, globalNS, deploymentName, utils.DeploymentReady) + err = adapter.WaitReady(ctx, globalNS, deploymentName, utils.DeploymentReady) Expect(err).NotTo(HaveOccurred()) By("Updating the ConfigMap") @@ -159,7 +161,7 @@ var _ = Describe("Watch Globally Flag Tests", func() { Expect(err).NotTo(HaveOccurred()) By("Waiting for Deployment to be reloaded (watchGlobally=true)") - reloaded, err := utils.WaitForDeploymentReloaded(ctx, kubeClient, globalNS, deploymentName, + reloaded, err := adapter.WaitReloaded(ctx, globalNS, deploymentName, utils.AnnotationLastReloadedFrom, utils.ReloadTimeout) Expect(err).NotTo(HaveOccurred()) Expect(reloaded).To(BeTrue(), "Deployment in any namespace should reload with watchGlobally=true") diff --git a/test/e2e/utils/accessors.go b/test/e2e/utils/accessors.go new file mode 100644 index 0000000..fe855ad --- /dev/null +++ b/test/e2e/utils/accessors.go @@ -0,0 +1,171 @@ +package utils + +import ( + "strings" + + appsv1 "k8s.io/api/apps/v1" + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + csiv1 "sigs.k8s.io/secrets-store-csi-driver/apis/v1" + + rolloutsv1alpha1 "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" + openshiftappsv1 "github.com/openshift/api/apps/v1" +) + +// Deployment accessors +var ( + DeploymentPodTemplate PodTemplateAccessor[*appsv1.Deployment] = func(d *appsv1.Deployment) *corev1.PodTemplateSpec { + return &d.Spec.Template + } + DeploymentAnnotations AnnotationAccessor[*appsv1.Deployment] = func(d *appsv1.Deployment) map[string]string { + return d.Annotations + } + DeploymentContainers ContainerAccessor[*appsv1.Deployment] = func(d *appsv1.Deployment) []corev1.Container { + return d.Spec.Template.Spec.Containers + } + DeploymentIsReady StatusAccessor[*appsv1.Deployment] = func(d *appsv1.Deployment) bool { + if d.Spec.Replicas == nil { + return false + } + return d.Status.ReadyReplicas == *d.Spec.Replicas && + d.Status.UpdatedReplicas == *d.Spec.Replicas && + d.Status.AvailableReplicas == *d.Spec.Replicas + } +) + +// DaemonSet accessors +var ( + DaemonSetPodTemplate PodTemplateAccessor[*appsv1.DaemonSet] = func(d *appsv1.DaemonSet) *corev1.PodTemplateSpec { + return &d.Spec.Template + } + DaemonSetAnnotations AnnotationAccessor[*appsv1.DaemonSet] = func(d *appsv1.DaemonSet) map[string]string { + return d.Annotations + } + DaemonSetContainers ContainerAccessor[*appsv1.DaemonSet] = func(d *appsv1.DaemonSet) []corev1.Container { + return d.Spec.Template.Spec.Containers + } + DaemonSetIsReady StatusAccessor[*appsv1.DaemonSet] = func(d *appsv1.DaemonSet) bool { + return d.Status.DesiredNumberScheduled > 0 && + d.Status.NumberReady == d.Status.DesiredNumberScheduled + } +) + +// StatefulSet accessors +var ( + StatefulSetPodTemplate PodTemplateAccessor[*appsv1.StatefulSet] = func(s *appsv1.StatefulSet) *corev1.PodTemplateSpec { + return &s.Spec.Template + } + StatefulSetAnnotations AnnotationAccessor[*appsv1.StatefulSet] = func(s *appsv1.StatefulSet) map[string]string { + return s.Annotations + } + StatefulSetContainers ContainerAccessor[*appsv1.StatefulSet] = func(s *appsv1.StatefulSet) []corev1.Container { + return s.Spec.Template.Spec.Containers + } + StatefulSetIsReady StatusAccessor[*appsv1.StatefulSet] = func(s *appsv1.StatefulSet) bool { + if s.Spec.Replicas == nil { + return false + } + return s.Status.ReadyReplicas == *s.Spec.Replicas + } +) + +// Job accessors +var ( + JobPodTemplate PodTemplateAccessor[*batchv1.Job] = func(j *batchv1.Job) *corev1.PodTemplateSpec { + return &j.Spec.Template + } + JobAnnotations AnnotationAccessor[*batchv1.Job] = func(j *batchv1.Job) map[string]string { + return j.Annotations + } + JobContainers ContainerAccessor[*batchv1.Job] = func(j *batchv1.Job) []corev1.Container { + return j.Spec.Template.Spec.Containers + } + JobIsReady StatusAccessor[*batchv1.Job] = func(j *batchv1.Job) bool { + return j.Status.Active > 0 || j.Status.Succeeded > 0 + } + JobUID UIDAccessor[*batchv1.Job] = func(j *batchv1.Job) types.UID { + return j.UID + } +) + +// CronJob accessors +var ( + CronJobPodTemplate PodTemplateAccessor[*batchv1.CronJob] = func(c *batchv1.CronJob) *corev1.PodTemplateSpec { + return &c.Spec.JobTemplate.Spec.Template + } + CronJobAnnotations AnnotationAccessor[*batchv1.CronJob] = func(c *batchv1.CronJob) map[string]string { + return c.Annotations + } + CronJobContainers ContainerAccessor[*batchv1.CronJob] = func(c *batchv1.CronJob) []corev1.Container { + return c.Spec.JobTemplate.Spec.Template.Spec.Containers + } + CronJobExists StatusAccessor[*batchv1.CronJob] = func(c *batchv1.CronJob) bool { + return true // Just existence check + } +) + +// Argo Rollout accessors +var ( + RolloutPodTemplate PodTemplateAccessor[*rolloutsv1alpha1.Rollout] = func(r *rolloutsv1alpha1.Rollout) *corev1.PodTemplateSpec { + return &r.Spec.Template + } + RolloutAnnotations AnnotationAccessor[*rolloutsv1alpha1.Rollout] = func(r *rolloutsv1alpha1.Rollout) map[string]string { + return r.Annotations + } + RolloutContainers ContainerAccessor[*rolloutsv1alpha1.Rollout] = func(r *rolloutsv1alpha1.Rollout) []corev1.Container { + return r.Spec.Template.Spec.Containers + } + RolloutIsReady StatusAccessor[*rolloutsv1alpha1.Rollout] = func(r *rolloutsv1alpha1.Rollout) bool { + if r.Spec.Replicas == nil { + return false + } + return r.Status.ReadyReplicas == *r.Spec.Replicas + } + RolloutHasRestartAt StatusAccessor[*rolloutsv1alpha1.Rollout] = func(r *rolloutsv1alpha1.Rollout) bool { + return r.Spec.RestartAt != nil + } +) + +// OpenShift DeploymentConfig accessors +var ( + DeploymentConfigPodTemplate PodTemplateAccessor[*openshiftappsv1.DeploymentConfig] = func(d *openshiftappsv1.DeploymentConfig) *corev1.PodTemplateSpec { + return d.Spec.Template + } + DeploymentConfigAnnotations AnnotationAccessor[*openshiftappsv1.DeploymentConfig] = func(d *openshiftappsv1.DeploymentConfig) map[string]string { + return d.Annotations + } + DeploymentConfigContainers ContainerAccessor[*openshiftappsv1.DeploymentConfig] = func(d *openshiftappsv1.DeploymentConfig) []corev1.Container { + if d.Spec.Template == nil { + return nil + } + return d.Spec.Template.Spec.Containers + } + DeploymentConfigIsReady StatusAccessor[*openshiftappsv1.DeploymentConfig] = func(d *openshiftappsv1.DeploymentConfig) bool { + return d.Status.ReadyReplicas == d.Spec.Replicas + } +) + +// SecretProviderClassPodStatus accessors +var ( + SPCPSIsMounted StatusAccessor[*csiv1.SecretProviderClassPodStatus] = func(s *csiv1.SecretProviderClassPodStatus) bool { + return s.Status.Mounted + } + SPCPSClassName ValueAccessor[*csiv1.SecretProviderClassPodStatus, string] = func(s *csiv1.SecretProviderClassPodStatus) string { + return s.Status.SecretProviderClassName + } + SPCPSPodName ValueAccessor[*csiv1.SecretProviderClassPodStatus, string] = func(s *csiv1.SecretProviderClassPodStatus) string { + return s.Status.PodName + } + // SPCPSVersions returns concatenated versions of all objects for change detection. + SPCPSVersions ValueAccessor[*csiv1.SecretProviderClassPodStatus, string] = func(s *csiv1.SecretProviderClassPodStatus) string { + if len(s.Status.Objects) == 0 { + return "" + } + var versions []string + for _, obj := range s.Status.Objects { + versions = append(versions, obj.Version) + } + return strings.Join(versions, ",") + } +) diff --git a/test/e2e/utils/conditions.go b/test/e2e/utils/conditions.go new file mode 100644 index 0000000..cd374ce --- /dev/null +++ b/test/e2e/utils/conditions.go @@ -0,0 +1,188 @@ +package utils + +import ( + "strings" + + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + csiv1 "sigs.k8s.io/secrets-store-csi-driver/apis/v1" +) + +// PodTemplateAccessor extracts PodTemplateSpec from a workload. +type PodTemplateAccessor[T any] func(T) *corev1.PodTemplateSpec + +// AnnotationAccessor extracts annotations from a resource. +type AnnotationAccessor[T any] func(T) map[string]string + +// ContainerAccessor extracts containers from a resource. +type ContainerAccessor[T any] func(T) []corev1.Container + +// StatusAccessor extracts ready status from a resource. +type StatusAccessor[T any] func(T) bool + +// UIDAccessor extracts UID from a resource. +type UIDAccessor[T any] func(T) types.UID + +// ValueAccessor extracts a comparable value from a resource. +type ValueAccessor[T any, V comparable] func(T) V + +// HasPodTemplateAnnotation returns a condition that checks for an annotation on the pod template. +func HasPodTemplateAnnotation[T any](accessor PodTemplateAccessor[T], key string) Condition[T] { + return func(obj T) bool { + template := accessor(obj) + if template == nil || template.Annotations == nil { + return false + } + _, ok := template.Annotations[key] + return ok + } +} + +// HasAnnotation returns a condition that checks for an annotation on the resource. +func HasAnnotation[T any](accessor AnnotationAccessor[T], key string) Condition[T] { + return func(obj T) bool { + annotations := accessor(obj) + if annotations == nil { + return false + } + _, ok := annotations[key] + return ok + } +} + +// NoAnnotation returns a condition that checks an annotation is absent. +func NoAnnotation[T any](accessor AnnotationAccessor[T], key string) Condition[T] { + return func(obj T) bool { + annotations := accessor(obj) + if annotations == nil { + return true + } + _, ok := annotations[key] + return !ok + } +} + +// HasEnvVarPrefix returns a condition that checks for an env var with the given prefix. +func HasEnvVarPrefix[T any](accessor ContainerAccessor[T], prefix string) Condition[T] { + return func(obj T) bool { + containers := accessor(obj) + for _, container := range containers { + for _, env := range container.Env { + if strings.HasPrefix(env.Name, prefix) { + return true + } + } + } + return false + } +} + +// IsReady returns a condition that checks if the resource is ready. +func IsReady[T any](accessor StatusAccessor[T]) Condition[T] { + return func(obj T) bool { + return accessor(obj) + } +} + +// HasDifferentUID returns a condition that checks if the UID differs from original. +func HasDifferentUID[T any](accessor UIDAccessor[T], originalUID types.UID) Condition[T] { + return func(obj T) bool { + return accessor(obj) != originalUID + } +} + +// HasDifferentValue returns a condition that checks if a value differs from original. +func HasDifferentValue[T any, V comparable](accessor ValueAccessor[T, V], original V) Condition[T] { + return func(obj T) bool { + return accessor(obj) != original + } +} + +// And combines multiple conditions with AND logic. +func And[T any](conditions ...Condition[T]) Condition[T] { + return func(obj T) bool { + for _, cond := range conditions { + if !cond(obj) { + return false + } + } + return true + } +} + +// Or combines multiple conditions with OR logic. +func Or[T any](conditions ...Condition[T]) Condition[T] { + return func(obj T) bool { + for _, cond := range conditions { + if cond(obj) { + return true + } + } + return false + } +} + +// Always returns a condition that always returns true (for existence checks). +func Always[T any]() Condition[T] { + return func(obj T) bool { + return true + } +} + +// IsTriggeredJobForCronJob returns a condition that checks if a Job was triggered +// by Reloader for the specified CronJob (has owner reference and instantiate annotation). +func IsTriggeredJobForCronJob(cronJobName string) Condition[*batchv1.Job] { + return func(job *batchv1.Job) bool { + for _, ownerRef := range job.OwnerReferences { + if ownerRef.Kind == "CronJob" && ownerRef.Name == cronJobName { + if job.Annotations != nil { + if _, ok := job.Annotations["cronjob.kubernetes.io/instantiate"]; ok { + return true + } + } + } + } + return false + } +} + +// SPCPSVersionChanged returns a condition that checks if the SPCPS version has changed +// from the initial version and the SPCPS is mounted. +func SPCPSVersionChanged(initialVersion string) Condition[*csiv1.SecretProviderClassPodStatus] { + return func(spcps *csiv1.SecretProviderClassPodStatus) bool { + if !spcps.Status.Mounted || len(spcps.Status.Objects) == 0 { + return false + } + for _, obj := range spcps.Status.Objects { + if obj.Version != initialVersion { + return true + } + } + return false + } +} + +// SPCPSForSPC returns a condition that checks if the SPCPS references a specific +// SecretProviderClass and is mounted. +func SPCPSForSPC(spcName string) Condition[*csiv1.SecretProviderClassPodStatus] { + return func(spcps *csiv1.SecretProviderClassPodStatus) bool { + return spcps.Status.SecretProviderClassName == spcName && spcps.Status.Mounted + } +} + +// SPCPSForPod returns a condition that checks if the SPCPS references a specific +// pod and is mounted. +func SPCPSForPod(podName string) Condition[*csiv1.SecretProviderClassPodStatus] { + return func(spcps *csiv1.SecretProviderClassPodStatus) bool { + return spcps.Status.PodName == podName && spcps.Status.Mounted + } +} + +// SPCPSForPods returns a condition that checks if the SPCPS references any of the +// specified pods and is mounted. +func SPCPSForPods(podNames map[string]bool) Condition[*csiv1.SecretProviderClassPodStatus] { + return func(spcps *csiv1.SecretProviderClassPodStatus) bool { + return podNames[spcps.Status.PodName] && spcps.Status.Mounted + } +} diff --git a/test/e2e/utils/csi.go b/test/e2e/utils/csi.go index 654e3d7..97dd940 100644 --- a/test/e2e/utils/csi.go +++ b/test/e2e/utils/csi.go @@ -3,12 +3,14 @@ package utils import ( "bytes" "context" + "errors" "fmt" "strings" "time" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" @@ -259,112 +261,72 @@ func execInVaultPod(ctx context.Context, kubeClient kubernetes.Interface, restCo return nil } -// WaitForSPCPSVersionChange waits for the SecretProviderClassPodStatus objects to change -// from the initial version. This is used after updating a Vault secret to wait for CSI -// driver to sync the new version. +// WaitForSPCPSVersionChange waits for the SecretProviderClassPodStatus version to change +// from the initial version using watches. This is used after updating a Vault secret to +// wait for CSI driver to sync the new version. func WaitForSPCPSVersionChange(ctx context.Context, client csiclient.Interface, namespace, spcpsName, initialVersion string, timeout time.Duration) error { - deadline := time.Now().Add(timeout) - for time.Now().Before(deadline) { - spcps, err := client.SecretsstoreV1().SecretProviderClassPodStatuses(namespace).Get(ctx, spcpsName, metav1.GetOptions{}) - if err == nil && spcps.Status.Mounted && len(spcps.Status.Objects) > 0 { - // Check if any object version has changed - for _, obj := range spcps.Status.Objects { - if obj.Version != initialVersion { - return nil - } - } - } - select { - case <-ctx.Done(): - return ctx.Err() - case <-time.After(1 * time.Second): - } + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return client.SecretsstoreV1().SecretProviderClassPodStatuses(namespace).Watch(ctx, opts) } - return fmt.Errorf("timeout waiting for SecretProviderClassPodStatus %s/%s version to change from %s", namespace, spcpsName, initialVersion) + + _, err := WatchUntil(ctx, watchFunc, spcpsName, SPCPSVersionChanged(initialVersion), timeout) + if errors.Is(err, ErrWatchTimeout) { + return fmt.Errorf("timeout waiting for SecretProviderClassPodStatus %s/%s version to change from %s", namespace, spcpsName, initialVersion) + } + return err } // FindSPCPSForDeployment finds the SecretProviderClassPodStatus created by CSI driver -// for pods of a given deployment. Returns the first matching SPCPS name. +// for pods of a given deployment using watches. Returns the first matching SPCPS name. func FindSPCPSForDeployment(ctx context.Context, csiClient csiclient.Interface, kubeClient kubernetes.Interface, namespace, deploymentName string, timeout time.Duration) ( string, error, ) { - deadline := time.Now().Add(timeout) - - for time.Now().Before(deadline) { - // Get pods for the deployment - pods, err := kubeClient.CoreV1().Pods(namespace).List( - ctx, metav1.ListOptions{ - LabelSelector: fmt.Sprintf("app=%s", deploymentName), - }, - ) - if err != nil { - select { - case <-ctx.Done(): - return "", ctx.Err() - case <-time.After(1 * time.Second): - continue - } - } - - // Look for SPCPS that references any of these pods - spcpsList, err := csiClient.SecretsstoreV1().SecretProviderClassPodStatuses(namespace).List(ctx, metav1.ListOptions{}) - if err != nil { - select { - case <-ctx.Done(): - return "", ctx.Err() - case <-time.After(1 * time.Second): - continue - } - } - - for _, pod := range pods.Items { - for _, spcps := range spcpsList.Items { - if spcps.Status.PodName == pod.Name && spcps.Status.Mounted { - return spcps.Name, nil - } - } - } - - select { - case <-ctx.Done(): - return "", ctx.Err() - case <-time.After(1 * time.Second): - } + // Get pods for the deployment + pods, err := kubeClient.CoreV1().Pods(namespace).List( + ctx, metav1.ListOptions{ + LabelSelector: fmt.Sprintf("app=%s", deploymentName), + }, + ) + if err != nil { + return "", fmt.Errorf("listing pods for deployment %s: %w", deploymentName, err) } - return "", fmt.Errorf("timeout finding SecretProviderClassPodStatus for deployment %s/%s", namespace, deploymentName) + podNames := make(map[string]bool) + for _, pod := range pods.Items { + podNames[pod.Name] = true + } + + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return csiClient.SecretsstoreV1().SecretProviderClassPodStatuses(namespace).Watch(ctx, opts) + } + + // Watch all SPCPS (empty name) and find one that matches any pod + spcps, err := WatchUntil(ctx, watchFunc, "", SPCPSForPods(podNames), timeout) + if errors.Is(err, ErrWatchTimeout) { + return "", fmt.Errorf("timeout finding SecretProviderClassPodStatus for deployment %s/%s", namespace, deploymentName) + } + if err != nil { + return "", err + } + return spcps.Name, nil } // FindSPCPSForSPC finds the SecretProviderClassPodStatus created by CSI driver -// that references a specific SecretProviderClass. Returns the first matching SPCPS name. +// that references a specific SecretProviderClass using watches. Returns the first matching SPCPS name. func FindSPCPSForSPC(ctx context.Context, csiClient csiclient.Interface, namespace, spcName string, timeout time.Duration) (string, error) { - deadline := time.Now().Add(timeout) - - for time.Now().Before(deadline) { - spcpsList, err := csiClient.SecretsstoreV1().SecretProviderClassPodStatuses(namespace).List(ctx, metav1.ListOptions{}) - if err != nil { - select { - case <-ctx.Done(): - return "", ctx.Err() - case <-time.After(1 * time.Second): - continue - } - } - - for _, spcps := range spcpsList.Items { - if spcps.Status.SecretProviderClassName == spcName && spcps.Status.Mounted { - return spcps.Name, nil - } - } - - select { - case <-ctx.Done(): - return "", ctx.Err() - case <-time.After(1 * time.Second): - } + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return csiClient.SecretsstoreV1().SecretProviderClassPodStatuses(namespace).Watch(ctx, opts) } - return "", fmt.Errorf("timeout finding SecretProviderClassPodStatus for SPC %s/%s", namespace, spcName) + // Watch all SPCPS (empty name) and find one that matches the SPC + spcps, err := WatchUntil(ctx, watchFunc, "", SPCPSForSPC(spcName), timeout) + if errors.Is(err, ErrWatchTimeout) { + return "", fmt.Errorf("timeout finding SecretProviderClassPodStatus for SPC %s/%s", namespace, spcName) + } + if err != nil { + return "", err + } + return spcps.Name, nil } // GetSPCPSVersion gets the current version string from a SecretProviderClassPodStatus. diff --git a/test/e2e/utils/resources.go b/test/e2e/utils/resources.go index 8543f23..a81e027 100644 --- a/test/e2e/utils/resources.go +++ b/test/e2e/utils/resources.go @@ -3,6 +3,7 @@ package utils import ( "context" "fmt" + "strings" appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" @@ -969,3 +970,38 @@ func csiVolumeName(spcName string) string { func csiMountPath(spcName string) string { return fmt.Sprintf("/mnt/secrets-store/%s", spcName) } + +// GetDeployment retrieves a deployment by name. +func GetDeployment(ctx context.Context, client kubernetes.Interface, namespace, name string) (*appsv1.Deployment, error) { + return client.AppsV1().Deployments(namespace).Get(ctx, name, metav1.GetOptions{}) +} + +// GetPodLogs retrieves logs from pods matching the given label selector. +func GetPodLogs(ctx context.Context, client kubernetes.Interface, namespace, labelSelector string) (string, error) { + pods, err := client.CoreV1().Pods(namespace).List( + ctx, metav1.ListOptions{ + LabelSelector: labelSelector, + }, + ) + if err != nil { + return "", fmt.Errorf("failed to list pods: %w", err) + } + + var allLogs strings.Builder + for _, pod := range pods.Items { + for _, container := range pod.Spec.Containers { + logs, err := client.CoreV1().Pods(namespace).GetLogs( + pod.Name, &corev1.PodLogOptions{ + Container: container.Name, + }, + ).Do(ctx).Raw() + if err != nil { + allLogs.WriteString(fmt.Sprintf("Error getting logs for %s/%s: %v\n", pod.Name, container.Name, err)) + continue + } + allLogs.WriteString(fmt.Sprintf("=== %s/%s ===\n%s\n", pod.Name, container.Name, string(logs))) + } + } + + return allLogs.String(), nil +} diff --git a/test/e2e/utils/testenv.go b/test/e2e/utils/testenv.go index 9b4e6a9..c1e28b5 100644 --- a/test/e2e/utils/testenv.go +++ b/test/e2e/utils/testenv.go @@ -158,8 +158,8 @@ func (e *TestEnvironment) DeployReloaderWithValues(values map[string]string) err // WaitForReloader waits for the Reloader deployment to be ready. func (e *TestEnvironment) WaitForReloader() error { ginkgo.GinkgoWriter.Println("Waiting for Reloader to be ready...") - return WaitForDeploymentReady(e.Ctx, e.KubeClient, e.Namespace, ReloaderDeploymentName(e.ReleaseName), - DeploymentReady) + adapter := NewDeploymentAdapter(e.KubeClient) + return adapter.WaitReady(e.Ctx, e.Namespace, ReloaderDeploymentName(e.ReleaseName), DeploymentReady) } // DeployAndWait deploys Reloader with the given values and waits for it to be ready. diff --git a/test/e2e/utils/wait.go b/test/e2e/utils/wait.go deleted file mode 100644 index 0fc70ec..0000000 --- a/test/e2e/utils/wait.go +++ /dev/null @@ -1,339 +0,0 @@ -package utils - -import ( - "context" - "errors" - "fmt" - "strings" - "time" - - appsv1 "k8s.io/api/apps/v1" - batchv1 "k8s.io/api/batch/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/kubernetes" -) - -// Timeout and interval constants for polling operations. -const ( - DefaultInterval = 1 * time.Second // Polling interval (faster feedback) - ShortTimeout = 5 * time.Second // Quick checks - NegativeTestWait = 3 * time.Second // Wait before checking negative conditions - DeploymentReady = 60 * time.Second // Workload readiness (buffer for CI) - ReloadTimeout = 15 * time.Second // Time for reload to trigger -) - -// WaitForDeploymentReady waits for a deployment to have all replicas available. -func WaitForDeploymentReady(ctx context.Context, client kubernetes.Interface, namespace, name string, timeout time.Duration) error { - return wait.PollUntilContextTimeout( - ctx, DefaultInterval, timeout, true, func(ctx context.Context) (bool, error) { - deploy, err := client.AppsV1().Deployments(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return false, nil - } - - if deploy.Status.ReadyReplicas == *deploy.Spec.Replicas && - deploy.Status.UpdatedReplicas == *deploy.Spec.Replicas && - deploy.Status.AvailableReplicas == *deploy.Spec.Replicas { - return true, nil - } - - return false, nil - }, - ) -} - -// WaitForDeploymentReloaded waits for a deployment's pod template to have the reloader annotation. -// Returns true if the annotation was found, false if timeout occurred. -func WaitForDeploymentReloaded(ctx context.Context, client kubernetes.Interface, namespace, name, annotationKey string, timeout time.Duration) (bool, error) { - return WaitForAnnotation(ctx, func(ctx context.Context) (map[string]string, error) { - deploy, err := client.AppsV1().Deployments(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return nil, err - } - return deploy.Spec.Template.Annotations, nil - }, annotationKey, timeout) -} - -// WaitForDaemonSetReloaded waits for a DaemonSet's pod template to have the reloader annotation. -func WaitForDaemonSetReloaded(ctx context.Context, client kubernetes.Interface, namespace, name, annotationKey string, timeout time.Duration) (bool, error) { - return WaitForAnnotation(ctx, func(ctx context.Context) (map[string]string, error) { - ds, err := client.AppsV1().DaemonSets(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return nil, err - } - return ds.Spec.Template.Annotations, nil - }, annotationKey, timeout) -} - -// WaitForStatefulSetReloaded waits for a StatefulSet's pod template to have the reloader annotation. -func WaitForStatefulSetReloaded(ctx context.Context, client kubernetes.Interface, namespace, name, annotationKey string, timeout time.Duration) (bool, error) { - return WaitForAnnotation(ctx, func(ctx context.Context) (map[string]string, error) { - ss, err := client.AppsV1().StatefulSets(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return nil, err - } - return ss.Spec.Template.Annotations, nil - }, annotationKey, timeout) -} - -// WaitForCronJobReloaded waits for a CronJob's pod template to have the reloader annotation. -func WaitForCronJobReloaded(ctx context.Context, client kubernetes.Interface, namespace, name, annotationKey string, timeout time.Duration) (bool, error) { - return WaitForAnnotation(ctx, func(ctx context.Context) (map[string]string, error) { - cj, err := client.BatchV1().CronJobs(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return nil, err - } - return cj.Spec.JobTemplate.Spec.Template.Annotations, nil - }, annotationKey, timeout) -} - -// WaitForCronJobTriggeredJob waits for a Job to be created by the specified CronJob. -// It checks owner references to find Jobs created by Reloader's manual trigger. -func WaitForCronJobTriggeredJob(ctx context.Context, client kubernetes.Interface, namespace, cronJobName string, timeout time.Duration) ( - bool, error, -) { - var found bool - err := wait.PollUntilContextTimeout( - ctx, DefaultInterval, timeout, true, func(ctx context.Context) (bool, error) { - jobs, err := client.BatchV1().Jobs(namespace).List(ctx, metav1.ListOptions{}) - if err != nil { - return false, nil - } - - for _, job := range jobs.Items { - for _, ownerRef := range job.OwnerReferences { - if ownerRef.Kind == "CronJob" && ownerRef.Name == cronJobName { - if job.Annotations != nil { - if _, ok := job.Annotations["cronjob.kubernetes.io/instantiate"]; ok { - found = true - return true, nil - } - } - } - } - } - - return false, nil - }, - ) - - if err != nil && !errors.Is(err, context.DeadlineExceeded) { - return false, err - } - return found, nil -} - -// WaitForDeploymentEnvVar waits for a deployment's containers to have an environment variable -// with the given prefix (e.g., "STAKATER_"). -func WaitForDeploymentEnvVar(ctx context.Context, client kubernetes.Interface, namespace, name, prefix string, timeout time.Duration) (bool, error) { - return WaitForEnvVarPrefix(ctx, func(ctx context.Context) ([]corev1.Container, error) { - deploy, err := client.AppsV1().Deployments(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return nil, err - } - return deploy.Spec.Template.Spec.Containers, nil - }, prefix, timeout) -} - -// WaitForDaemonSetEnvVar waits for a DaemonSet's containers to have an environment variable -// with the given prefix. -func WaitForDaemonSetEnvVar(ctx context.Context, client kubernetes.Interface, namespace, name, prefix string, timeout time.Duration) (bool, error) { - return WaitForEnvVarPrefix(ctx, func(ctx context.Context) ([]corev1.Container, error) { - ds, err := client.AppsV1().DaemonSets(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return nil, err - } - return ds.Spec.Template.Spec.Containers, nil - }, prefix, timeout) -} - -// WaitForStatefulSetEnvVar waits for a StatefulSet's containers to have an environment variable -// with the given prefix. -func WaitForStatefulSetEnvVar(ctx context.Context, client kubernetes.Interface, namespace, name, prefix string, timeout time.Duration) (bool, error) { - return WaitForEnvVarPrefix(ctx, func(ctx context.Context) ([]corev1.Container, error) { - ss, err := client.AppsV1().StatefulSets(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return nil, err - } - return ss.Spec.Template.Spec.Containers, nil - }, prefix, timeout) -} - -// WaitForDeploymentPaused waits for a deployment to have the paused-at annotation. -func WaitForDeploymentPaused(ctx context.Context, client kubernetes.Interface, namespace, name, pausedAtAnnotation string, timeout time.Duration) (bool, error) { - return WaitForAnnotation(ctx, func(ctx context.Context) (map[string]string, error) { - deploy, err := client.AppsV1().Deployments(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return nil, err - } - return deploy.Annotations, nil - }, pausedAtAnnotation, timeout) -} - -// WaitForDeploymentUnpaused waits for a deployment to NOT have the paused-at annotation. -func WaitForDeploymentUnpaused(ctx context.Context, client kubernetes.Interface, namespace, name, pausedAtAnnotation string, timeout time.Duration) (bool, error) { - return WaitForNoAnnotation(ctx, func(ctx context.Context) (map[string]string, error) { - deploy, err := client.AppsV1().Deployments(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return nil, err - } - return deploy.Annotations, nil - }, pausedAtAnnotation, timeout) -} - -// WaitForDaemonSetReady waits for a DaemonSet to have all pods ready. -func WaitForDaemonSetReady(ctx context.Context, client kubernetes.Interface, namespace, name string, timeout time.Duration) error { - return wait.PollUntilContextTimeout( - ctx, DefaultInterval, timeout, true, func(ctx context.Context) (bool, error) { - ds, err := client.AppsV1().DaemonSets(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return false, nil - } - - if ds.Status.DesiredNumberScheduled > 0 && - ds.Status.NumberReady == ds.Status.DesiredNumberScheduled { - return true, nil - } - - return false, nil - }, - ) -} - -// WaitForStatefulSetReady waits for a StatefulSet to have all replicas ready. -func WaitForStatefulSetReady(ctx context.Context, client kubernetes.Interface, namespace, name string, timeout time.Duration) error { - return wait.PollUntilContextTimeout( - ctx, DefaultInterval, timeout, true, func(ctx context.Context) (bool, error) { - ss, err := client.AppsV1().StatefulSets(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return false, nil - } - - if ss.Status.ReadyReplicas == *ss.Spec.Replicas { - return true, nil - } - - return false, nil - }, - ) -} - -// GetDeployment retrieves a deployment by name. -func GetDeployment(ctx context.Context, client kubernetes.Interface, namespace, name string) (*appsv1.Deployment, error) { - return client.AppsV1().Deployments(namespace).Get(ctx, name, metav1.GetOptions{}) -} - -// WaitForCronJobExists waits for a CronJob to exist in the cluster. -// This is useful for giving Reloader time to detect and index the CronJob before making changes. -func WaitForCronJobExists(ctx context.Context, client kubernetes.Interface, namespace, name string, timeout time.Duration) error { - return wait.PollUntilContextTimeout( - ctx, DefaultInterval, timeout, true, func(ctx context.Context) (bool, error) { - _, err := client.BatchV1().CronJobs(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return false, nil - } - return true, nil - }, - ) -} - -// GetJob retrieves a Job by name. -func GetJob(ctx context.Context, client kubernetes.Interface, namespace, name string) (*batchv1.Job, error) { - return client.BatchV1().Jobs(namespace).Get(ctx, name, metav1.GetOptions{}) -} - -// WaitForJobRecreated waits for a Job to be deleted and recreated with a new UID. -// Returns the new Job's UID if recreation was detected. -func WaitForJobRecreated(ctx context.Context, client kubernetes.Interface, namespace, name, originalUID string, timeout time.Duration) ( - string, bool, error, -) { - var newUID string - var recreated bool - - err := wait.PollUntilContextTimeout( - ctx, DefaultInterval, timeout, true, func(ctx context.Context) (bool, error) { - job, err := client.BatchV1().Jobs(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return false, nil - } - - if string(job.UID) != originalUID { - newUID = string(job.UID) - recreated = true - return true, nil - } - - return false, nil - }, - ) - - if err != nil && !errors.Is(err, context.DeadlineExceeded) { - return "", false, err - } - return newUID, recreated, nil -} - -// WaitForJobExists waits for a Job to exist in the cluster. -func WaitForJobExists(ctx context.Context, client kubernetes.Interface, namespace, name string, timeout time.Duration) error { - return wait.PollUntilContextTimeout( - ctx, DefaultInterval, timeout, true, func(ctx context.Context) (bool, error) { - _, err := client.BatchV1().Jobs(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return false, nil // Keep polling - } - return true, nil - }, - ) -} - -// WaitForJobReady waits for a Job to have at least one active or succeeded pod. -// This ensures the Job has actually started running before proceeding. -func WaitForJobReady(ctx context.Context, client kubernetes.Interface, namespace, name string, timeout time.Duration) error { - return wait.PollUntilContextTimeout( - ctx, DefaultInterval, timeout, true, func(ctx context.Context) (bool, error) { - job, err := client.BatchV1().Jobs(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return false, nil - } - - // Job is ready if it has at least one active or succeeded pod - if job.Status.Active > 0 || job.Status.Succeeded > 0 { - return true, nil - } - - return false, nil - }, - ) -} - -// GetPodLogs retrieves logs from pods matching the given label selector. -func GetPodLogs(ctx context.Context, client kubernetes.Interface, namespace, labelSelector string) (string, error) { - pods, err := client.CoreV1().Pods(namespace).List( - ctx, metav1.ListOptions{ - LabelSelector: labelSelector, - }, - ) - if err != nil { - return "", fmt.Errorf("failed to list pods: %w", err) - } - - var allLogs strings.Builder - for _, pod := range pods.Items { - for _, container := range pod.Spec.Containers { - logs, err := client.CoreV1().Pods(namespace).GetLogs( - pod.Name, &corev1.PodLogOptions{ - Container: container.Name, - }, - ).Do(ctx).Raw() - if err != nil { - allLogs.WriteString(fmt.Sprintf("Error getting logs for %s/%s: %v\n", pod.Name, container.Name, err)) - continue - } - allLogs.WriteString(fmt.Sprintf("=== %s/%s ===\n%s\n", pod.Name, container.Name, string(logs))) - } - } - - return allLogs.String(), nil -} diff --git a/test/e2e/utils/wait_helpers.go b/test/e2e/utils/wait_helpers.go deleted file mode 100644 index 594ae70..0000000 --- a/test/e2e/utils/wait_helpers.go +++ /dev/null @@ -1,87 +0,0 @@ -package utils - -import ( - "context" - "errors" - "strings" - "time" - - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/util/wait" -) - -// AnnotationGetter retrieves annotations from a workload's pod template. -type AnnotationGetter func(ctx context.Context) (map[string]string, error) - -// ContainerGetter retrieves containers from a workload's pod template. -type ContainerGetter func(ctx context.Context) ([]corev1.Container, error) - -// WaitForAnnotation polls until an annotation key exists. -func WaitForAnnotation(ctx context.Context, getter AnnotationGetter, key string, timeout time.Duration) (bool, error) { - var found bool - err := wait.PollUntilContextTimeout(ctx, DefaultInterval, timeout, true, func(ctx context.Context) (bool, error) { - annotations, err := getter(ctx) - if err != nil { - return false, nil // Keep polling on errors - } - if annotations != nil { - if _, ok := annotations[key]; ok { - found = true - return true, nil - } - } - return false, nil - }) - if err != nil && !errors.Is(err, context.DeadlineExceeded) { - return false, err - } - return found, nil -} - -// WaitForNoAnnotation polls until an annotation key is absent. -func WaitForNoAnnotation(ctx context.Context, getter AnnotationGetter, key string, timeout time.Duration) (bool, error) { - var absent bool - err := wait.PollUntilContextTimeout(ctx, DefaultInterval, timeout, true, func(ctx context.Context) (bool, error) { - annotations, err := getter(ctx) - if err != nil { - return false, nil - } - if annotations == nil { - absent = true - return true, nil - } - if _, ok := annotations[key]; !ok { - absent = true - return true, nil - } - return false, nil - }) - if err != nil && !errors.Is(err, context.DeadlineExceeded) { - return false, err - } - return absent, nil -} - -// WaitForEnvVarPrefix polls until a container has an env var with given prefix. -func WaitForEnvVarPrefix(ctx context.Context, getter ContainerGetter, prefix string, timeout time.Duration) (bool, error) { - var found bool - err := wait.PollUntilContextTimeout(ctx, DefaultInterval, timeout, true, func(ctx context.Context) (bool, error) { - containers, err := getter(ctx) - if err != nil { - return false, nil - } - for _, container := range containers { - for _, env := range container.Env { - if strings.HasPrefix(env.Name, prefix) { - found = true - return true, nil - } - } - } - return false, nil - }) - if err != nil && !errors.Is(err, context.DeadlineExceeded) { - return false, err - } - return found, nil -} diff --git a/test/e2e/utils/watch.go b/test/e2e/utils/watch.go new file mode 100644 index 0000000..3f9667a --- /dev/null +++ b/test/e2e/utils/watch.go @@ -0,0 +1,191 @@ +package utils + +import ( + "context" + "errors" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" +) + +// Timeout constants for watch operations. +const ( + DefaultInterval = 1 * time.Second // Polling interval (legacy, will be removed) + ShortTimeout = 5 * time.Second // Quick checks + NegativeTestWait = 3 * time.Second // Wait before checking negative conditions + DeploymentReady = 60 * time.Second // Workload readiness (buffer for CI) + ReloadTimeout = 15 * time.Second // Time for reload to trigger +) + +// ErrWatchTimeout is returned when a watch times out waiting for condition. +var ErrWatchTimeout = errors.New("watch timeout waiting for condition") + +// WatchFunc is a function that starts a watch for a specific resource. +type WatchFunc func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) + +// Condition is a function that checks if the desired state is reached. +type Condition[T any] func(T) bool + +// WatchUntil watches a resource until the condition is met or timeout occurs. +// It handles watch reconnection automatically on errors. +// If name is empty, it watches all resources and returns the first matching one. +func WatchUntil[T runtime.Object](ctx context.Context, watchFunc WatchFunc, name string, condition Condition[T], timeout time.Duration) (T, error) { + var zero T + ctx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + + opts := metav1.ListOptions{Watch: true} + if name != "" { + opts.FieldSelector = fields.OneTermEqualSelector("metadata.name", name).String() + } + + for { + select { + case <-ctx.Done(): + return zero, ErrWatchTimeout + default: + } + + result, done, err := watchOnce(ctx, watchFunc, opts, condition) + if done { + return result, err + } + // Watch disconnected, retry after brief pause + select { + case <-ctx.Done(): + return zero, ErrWatchTimeout + case <-time.After(100 * time.Millisecond): + } + } +} + +// watchOnce starts a single watch and processes events until condition met or watch ends. +func watchOnce[T runtime.Object]( + ctx context.Context, + watchFunc WatchFunc, + opts metav1.ListOptions, + condition Condition[T], +) (T, bool, error) { + var zero T + + watcher, err := watchFunc(ctx, opts) + if err != nil { + return zero, false, nil // Retry + } + defer watcher.Stop() + + for { + select { + case <-ctx.Done(): + return zero, true, ErrWatchTimeout + case event, ok := <-watcher.ResultChan(): + if !ok { + return zero, false, nil // Watch closed, retry + } + + switch event.Type { + case watch.Added, watch.Modified: + obj, ok := event.Object.(T) + if !ok { + continue + } + if condition(obj) { + return obj, true, nil + } + case watch.Deleted: + // Resource deleted, keep watching for recreation + continue + case watch.Error: + return zero, false, nil // Retry on error + } + } + } +} + +// WatchUntilDeleted watches until the resource is deleted or timeout occurs. +func WatchUntilDeleted( + ctx context.Context, + watchFunc WatchFunc, + name string, + timeout time.Duration, +) error { + ctx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + + opts := metav1.ListOptions{ + FieldSelector: fields.OneTermEqualSelector("metadata.name", name).String(), + Watch: true, + } + + for { + select { + case <-ctx.Done(): + return ErrWatchTimeout + default: + } + + deleted, err := watchDeleteOnce(ctx, watchFunc, opts) + if deleted { + return err + } + select { + case <-ctx.Done(): + return ErrWatchTimeout + case <-time.After(100 * time.Millisecond): + } + } +} + +func watchDeleteOnce( + ctx context.Context, + watchFunc WatchFunc, + opts metav1.ListOptions, +) (bool, error) { + watcher, err := watchFunc(ctx, opts) + if err != nil { + return false, nil + } + defer watcher.Stop() + + for { + select { + case <-ctx.Done(): + return true, ErrWatchTimeout + case event, ok := <-watcher.ResultChan(): + if !ok { + return false, nil + } + if event.Type == watch.Deleted { + return true, nil + } + if event.Type == watch.Error { + return false, nil + } + } + } +} + +// WatchUntilDifferentUID watches until the resource has a different UID (recreated). +func WatchUntilDifferentUID[T runtime.Object]( + ctx context.Context, + watchFunc WatchFunc, + name string, + originalUID string, + timeout time.Duration, + getUID func(T) string, +) (T, bool, error) { + var zero T + result, err := WatchUntil(ctx, watchFunc, name, func(obj T) bool { + return getUID(obj) != originalUID + }, timeout) + if errors.Is(err, ErrWatchTimeout) { + return zero, false, nil + } + if err != nil { + return zero, false, err + } + return result, true, nil +} diff --git a/test/e2e/utils/workload_adapter.go b/test/e2e/utils/workload_adapter.go index 0ac5cc5..cf5025b 100644 --- a/test/e2e/utils/workload_adapter.go +++ b/test/e2e/utils/workload_adapter.go @@ -84,6 +84,32 @@ type WorkloadAdapter interface { RequiresSpecialHandling() bool } +// Pausable is implemented by workloads that support pause/unpause. +// Currently only Deployment supports this capability. +type Pausable interface { + WaitPaused(ctx context.Context, namespace, name, annotationKey string, timeout time.Duration) (bool, error) + WaitUnpaused(ctx context.Context, namespace, name, annotationKey string, timeout time.Duration) (bool, error) +} + +// Recreatable is implemented by workloads that are recreated instead of updated. +// Currently only Job supports this capability (Jobs are immutable, so Reloader recreates them). +type Recreatable interface { + GetOriginalUID(ctx context.Context, namespace, name string) (string, error) + WaitRecreated(ctx context.Context, namespace, name, originalUID string, timeout time.Duration) (string, bool, error) +} + +// JobTriggerer is implemented by workloads that trigger jobs on reload. +// Currently only CronJob supports this capability. +type JobTriggerer interface { + WaitForTriggeredJob(ctx context.Context, namespace, name string, timeout time.Duration) (bool, error) +} + +// RestartAtSupporter is implemented by workloads that support the restartAt field. +// Currently only ArgoRollout supports this capability. +type RestartAtSupporter interface { + WaitRestartAt(ctx context.Context, namespace, name string, timeout time.Duration) (bool, error) +} + // AdapterRegistry holds adapters for all workload types. type AdapterRegistry struct { kubeClient kubernetes.Interface diff --git a/test/e2e/utils/workload_argo.go b/test/e2e/utils/workload_argo.go index 5ec6f1e..4860d41 100644 --- a/test/e2e/utils/workload_argo.go +++ b/test/e2e/utils/workload_argo.go @@ -9,7 +9,7 @@ import ( rolloutsclient "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/apimachinery/pkg/watch" "k8s.io/utils/ptr" ) @@ -46,19 +46,50 @@ func (a *ArgoRolloutAdapter) Delete(ctx context.Context, namespace, name string) return a.rolloutsClient.ArgoprojV1alpha1().Rollouts(namespace).Delete(ctx, name, metav1.DeleteOptions{}) } -// WaitReady waits for the Argo Rollout to be ready. +// WaitReady waits for the Argo Rollout to be ready using watches. func (a *ArgoRolloutAdapter) WaitReady(ctx context.Context, namespace, name string, timeout time.Duration) error { - return WaitForRolloutReady(ctx, a.rolloutsClient, namespace, name, timeout) + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.rolloutsClient.ArgoprojV1alpha1().Rollouts(namespace).Watch(ctx, opts) + } + _, err := WatchUntil(ctx, watchFunc, name, IsReady(RolloutIsReady), timeout) + return err } -// WaitReloaded waits for the Argo Rollout to have the reload annotation. +// WaitReloaded waits for the Argo Rollout to have the reload annotation using watches. func (a *ArgoRolloutAdapter) WaitReloaded(ctx context.Context, namespace, name, annotationKey string, timeout time.Duration) (bool, error) { - return WaitForRolloutReloaded(ctx, a.rolloutsClient, namespace, name, annotationKey, timeout) + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.rolloutsClient.ArgoprojV1alpha1().Rollouts(namespace).Watch(ctx, opts) + } + _, err := WatchUntil(ctx, watchFunc, name, HasPodTemplateAnnotation(RolloutPodTemplate, annotationKey), timeout) + if errors.Is(err, ErrWatchTimeout) { + return false, nil + } + return err == nil, err } -// WaitEnvVar waits for the Argo Rollout to have a STAKATER_ env var. +// WaitEnvVar waits for the Argo Rollout to have a STAKATER_ env var using watches. func (a *ArgoRolloutAdapter) WaitEnvVar(ctx context.Context, namespace, name, prefix string, timeout time.Duration) (bool, error) { - return WaitForRolloutEnvVar(ctx, a.rolloutsClient, namespace, name, prefix, timeout) + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.rolloutsClient.ArgoprojV1alpha1().Rollouts(namespace).Watch(ctx, opts) + } + _, err := WatchUntil(ctx, watchFunc, name, HasEnvVarPrefix(RolloutContainers, prefix), timeout) + if errors.Is(err, ErrWatchTimeout) { + return false, nil + } + return err == nil, err +} + +// WaitRestartAt waits for the Argo Rollout to have the restartAt field set using watches. +// This is used when Reloader is configured with rollout strategy=restart. +func (a *ArgoRolloutAdapter) WaitRestartAt(ctx context.Context, namespace, name string, timeout time.Duration) (bool, error) { + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.rolloutsClient.ArgoprojV1alpha1().Rollouts(namespace).Watch(ctx, opts) + } + _, err := WatchUntil(ctx, watchFunc, name, IsReady(RolloutHasRestartAt), timeout) + if errors.Is(err, ErrWatchTimeout) { + return false, nil + } + return err == nil, err } // SupportsEnvVarStrategy returns true as Argo Rollouts support env var reload strategy. @@ -120,70 +151,3 @@ func buildRolloutOptions(cfg WorkloadConfig) []RolloutOption { }, } } - -// WaitForRolloutReady waits for an Argo Rollout to be ready using typed client. -func WaitForRolloutReady(ctx context.Context, client rolloutsclient.Interface, namespace, name string, timeout time.Duration) error { - return wait.PollUntilContextTimeout(ctx, DefaultInterval, timeout, true, func(ctx context.Context) (bool, error) { - rollout, err := client.ArgoprojV1alpha1().Rollouts(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return false, nil - } - - // Check status.phase == "Healthy" or replicas == availableReplicas - if rollout.Status.Phase == rolloutv1alpha1.RolloutPhaseHealthy { - return true, nil - } - - if rollout.Spec.Replicas != nil && *rollout.Spec.Replicas > 0 && - rollout.Status.AvailableReplicas == *rollout.Spec.Replicas { - return true, nil - } - - return false, nil - }) -} - -// WaitForRolloutReloaded waits for an Argo Rollout's pod template to have the reloader annotation. -func WaitForRolloutReloaded(ctx context.Context, client rolloutsclient.Interface, namespace, name, annotationKey string, timeout time.Duration) (bool, error) { - return WaitForAnnotation(ctx, func(ctx context.Context) (map[string]string, error) { - rollout, err := client.ArgoprojV1alpha1().Rollouts(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return nil, err - } - return rollout.Spec.Template.Annotations, nil - }, annotationKey, timeout) -} - -// WaitForRolloutEnvVar waits for an Argo Rollout's container to have an env var with the given prefix. -func WaitForRolloutEnvVar(ctx context.Context, client rolloutsclient.Interface, namespace, name, prefix string, timeout time.Duration) (bool, error) { - return WaitForEnvVarPrefix(ctx, func(ctx context.Context) ([]corev1.Container, error) { - rollout, err := client.ArgoprojV1alpha1().Rollouts(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return nil, err - } - return rollout.Spec.Template.Spec.Containers, nil - }, prefix, timeout) -} - -// WaitForRolloutRestartAt waits for an Argo Rollout's spec.restartAt field to be set. -func WaitForRolloutRestartAt(ctx context.Context, client rolloutsclient.Interface, namespace, name string, timeout time.Duration) (bool, error) { - var found bool - err := wait.PollUntilContextTimeout(ctx, DefaultInterval, timeout, true, func(ctx context.Context) (bool, error) { - rollout, err := client.ArgoprojV1alpha1().Rollouts(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return false, nil - } - - if rollout.Spec.RestartAt != nil && !rollout.Spec.RestartAt.IsZero() { - found = true - return true, nil - } - - return false, nil - }) - - if err != nil && !errors.Is(err, context.DeadlineExceeded) { - return false, err - } - return found, nil -} diff --git a/test/e2e/utils/workload_cronjob.go b/test/e2e/utils/workload_cronjob.go index 0f52d7c..41fef04 100644 --- a/test/e2e/utils/workload_cronjob.go +++ b/test/e2e/utils/workload_cronjob.go @@ -2,9 +2,12 @@ package utils import ( "context" + "errors" "time" batchv1 "k8s.io/api/batch/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes" ) @@ -35,19 +38,29 @@ func (a *CronJobAdapter) Delete(ctx context.Context, namespace, name string) err return DeleteCronJob(ctx, a.client, namespace, name) } -// WaitReady waits for the CronJob to exist (CronJobs are "ready" immediately after creation). +// WaitReady waits for the CronJob to exist using watches. func (a *CronJobAdapter) WaitReady(ctx context.Context, namespace, name string, timeout time.Duration) error { - return WaitForCronJobExists(ctx, a.client, namespace, name, timeout) + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.client.BatchV1().CronJobs(namespace).Watch(ctx, opts) + } + _, err := WatchUntil(ctx, watchFunc, name, Always[*batchv1.CronJob](), timeout) + return err } -// WaitReloaded waits for the CronJob to have the reload annotation OR for a triggered Job. +// WaitReloaded waits for the CronJob pod template to have the reload annotation using watches. func (a *CronJobAdapter) WaitReloaded(ctx context.Context, namespace, name, annotationKey string, timeout time.Duration) (bool, error) { - return WaitForCronJobReloaded(ctx, a.client, namespace, name, annotationKey, timeout) + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.client.BatchV1().CronJobs(namespace).Watch(ctx, opts) + } + _, err := WatchUntil(ctx, watchFunc, name, HasPodTemplateAnnotation(CronJobPodTemplate, annotationKey), timeout) + if errors.Is(err, ErrWatchTimeout) { + return false, nil + } + return err == nil, err } // WaitEnvVar is not supported for CronJobs as they don't use env var reload strategy. func (a *CronJobAdapter) WaitEnvVar(ctx context.Context, namespace, name, prefix string, timeout time.Duration) (bool, error) { - // CronJobs don't support env var strategy return false, nil } @@ -61,9 +74,16 @@ func (a *CronJobAdapter) RequiresSpecialHandling() bool { return true } -// WaitForTriggeredJob waits for Reloader to trigger a new Job from this CronJob. +// WaitForTriggeredJob waits for Reloader to trigger a new Job from this CronJob using watches. func (a *CronJobAdapter) WaitForTriggeredJob(ctx context.Context, namespace, cronJobName string, timeout time.Duration) (bool, error) { - return WaitForCronJobTriggeredJob(ctx, a.client, namespace, cronJobName, timeout) + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.client.BatchV1().Jobs(namespace).Watch(ctx, opts) + } + _, err := WatchUntil(ctx, watchFunc, "", IsTriggeredJobForCronJob(cronJobName), timeout) + if errors.Is(err, ErrWatchTimeout) { + return false, nil + } + return err == nil, err } // buildCronJobOptions converts WorkloadConfig to CronJobOption slice. diff --git a/test/e2e/utils/workload_daemonset.go b/test/e2e/utils/workload_daemonset.go index 93c6e64..492f7b5 100644 --- a/test/e2e/utils/workload_daemonset.go +++ b/test/e2e/utils/workload_daemonset.go @@ -2,9 +2,12 @@ package utils import ( "context" + "errors" "time" appsv1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes" ) @@ -35,19 +38,37 @@ func (a *DaemonSetAdapter) Delete(ctx context.Context, namespace, name string) e return DeleteDaemonSet(ctx, a.client, namespace, name) } -// WaitReady waits for the DaemonSet to be ready. +// WaitReady waits for the DaemonSet to be ready using watches. func (a *DaemonSetAdapter) WaitReady(ctx context.Context, namespace, name string, timeout time.Duration) error { - return WaitForDaemonSetReady(ctx, a.client, namespace, name, timeout) + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.client.AppsV1().DaemonSets(namespace).Watch(ctx, opts) + } + _, err := WatchUntil(ctx, watchFunc, name, IsReady(DaemonSetIsReady), timeout) + return err } -// WaitReloaded waits for the DaemonSet to have the reload annotation. +// WaitReloaded waits for the DaemonSet to have the reload annotation using watches. func (a *DaemonSetAdapter) WaitReloaded(ctx context.Context, namespace, name, annotationKey string, timeout time.Duration) (bool, error) { - return WaitForDaemonSetReloaded(ctx, a.client, namespace, name, annotationKey, timeout) + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.client.AppsV1().DaemonSets(namespace).Watch(ctx, opts) + } + _, err := WatchUntil(ctx, watchFunc, name, HasPodTemplateAnnotation(DaemonSetPodTemplate, annotationKey), timeout) + if errors.Is(err, ErrWatchTimeout) { + return false, nil + } + return err == nil, err } -// WaitEnvVar waits for the DaemonSet to have a STAKATER_ env var. +// WaitEnvVar waits for the DaemonSet to have a STAKATER_ env var using watches. func (a *DaemonSetAdapter) WaitEnvVar(ctx context.Context, namespace, name, prefix string, timeout time.Duration) (bool, error) { - return WaitForDaemonSetEnvVar(ctx, a.client, namespace, name, prefix, timeout) + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.client.AppsV1().DaemonSets(namespace).Watch(ctx, opts) + } + _, err := WatchUntil(ctx, watchFunc, name, HasEnvVarPrefix(DaemonSetContainers, prefix), timeout) + if errors.Is(err, ErrWatchTimeout) { + return false, nil + } + return err == nil, err } // SupportsEnvVarStrategy returns true as DaemonSets support env var reload strategy. diff --git a/test/e2e/utils/workload_deployment.go b/test/e2e/utils/workload_deployment.go index b0cbfb1..28f7f55 100644 --- a/test/e2e/utils/workload_deployment.go +++ b/test/e2e/utils/workload_deployment.go @@ -2,9 +2,12 @@ package utils import ( "context" + "errors" "time" appsv1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes" ) @@ -35,19 +38,61 @@ func (a *DeploymentAdapter) Delete(ctx context.Context, namespace, name string) return DeleteDeployment(ctx, a.client, namespace, name) } -// WaitReady waits for the Deployment to be ready. +// WaitReady waits for the Deployment to be ready using watches. func (a *DeploymentAdapter) WaitReady(ctx context.Context, namespace, name string, timeout time.Duration) error { - return WaitForDeploymentReady(ctx, a.client, namespace, name, timeout) + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.client.AppsV1().Deployments(namespace).Watch(ctx, opts) + } + _, err := WatchUntil(ctx, watchFunc, name, IsReady(DeploymentIsReady), timeout) + return err } -// WaitReloaded waits for the Deployment to have the reload annotation. +// WaitReloaded waits for the Deployment to have the reload annotation using watches. func (a *DeploymentAdapter) WaitReloaded(ctx context.Context, namespace, name, annotationKey string, timeout time.Duration) (bool, error) { - return WaitForDeploymentReloaded(ctx, a.client, namespace, name, annotationKey, timeout) + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.client.AppsV1().Deployments(namespace).Watch(ctx, opts) + } + _, err := WatchUntil(ctx, watchFunc, name, HasPodTemplateAnnotation(DeploymentPodTemplate, annotationKey), timeout) + if errors.Is(err, ErrWatchTimeout) { + return false, nil + } + return err == nil, err } -// WaitEnvVar waits for the Deployment to have a STAKATER_ env var. +// WaitEnvVar waits for the Deployment to have a STAKATER_ env var using watches. func (a *DeploymentAdapter) WaitEnvVar(ctx context.Context, namespace, name, prefix string, timeout time.Duration) (bool, error) { - return WaitForDeploymentEnvVar(ctx, a.client, namespace, name, prefix, timeout) + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.client.AppsV1().Deployments(namespace).Watch(ctx, opts) + } + _, err := WatchUntil(ctx, watchFunc, name, HasEnvVarPrefix(DeploymentContainers, prefix), timeout) + if errors.Is(err, ErrWatchTimeout) { + return false, nil + } + return err == nil, err +} + +// WaitPaused waits for the Deployment to have the paused annotation using watches. +func (a *DeploymentAdapter) WaitPaused(ctx context.Context, namespace, name, annotationKey string, timeout time.Duration) (bool, error) { + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.client.AppsV1().Deployments(namespace).Watch(ctx, opts) + } + _, err := WatchUntil(ctx, watchFunc, name, HasAnnotation(DeploymentAnnotations, annotationKey), timeout) + if errors.Is(err, ErrWatchTimeout) { + return false, nil + } + return err == nil, err +} + +// WaitUnpaused waits for the Deployment to NOT have the paused annotation using watches. +func (a *DeploymentAdapter) WaitUnpaused(ctx context.Context, namespace, name, annotationKey string, timeout time.Duration) (bool, error) { + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.client.AppsV1().Deployments(namespace).Watch(ctx, opts) + } + _, err := WatchUntil(ctx, watchFunc, name, NoAnnotation(DeploymentAnnotations, annotationKey), timeout) + if errors.Is(err, ErrWatchTimeout) { + return false, nil + } + return err == nil, err } // SupportsEnvVarStrategy returns true as Deployments support env var reload strategy. diff --git a/test/e2e/utils/workload_job.go b/test/e2e/utils/workload_job.go index c83d24f..4daa781 100644 --- a/test/e2e/utils/workload_job.go +++ b/test/e2e/utils/workload_job.go @@ -2,9 +2,13 @@ package utils import ( "context" + "errors" "time" batchv1 "k8s.io/api/batch/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes" ) @@ -36,18 +40,22 @@ func (a *JobAdapter) Delete(ctx context.Context, namespace, name string) error { return DeleteJob(ctx, a.client, namespace, name) } -// WaitReady waits for the Job to exist. +// WaitReady waits for the Job to be ready (has active or succeeded pods) using watches. func (a *JobAdapter) WaitReady(ctx context.Context, namespace, name string, timeout time.Duration) error { - return WaitForJobExists(ctx, a.client, namespace, name, timeout) + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.client.BatchV1().Jobs(namespace).Watch(ctx, opts) + } + _, err := WatchUntil(ctx, watchFunc, name, IsReady(JobIsReady), timeout) + return err } -// WaitReloaded waits for the Job to be recreated (new UID). +// WaitReloaded waits for the Job to be recreated (new UID) using watches. // For Jobs, Reloader recreates the Job rather than updating annotations. func (a *JobAdapter) WaitReloaded(ctx context.Context, namespace, name, annotationKey string, timeout time.Duration) (bool, error) { // For Jobs, we check if it was recreated by looking for a new UID // This requires storing the original UID before the test // For simplicity, we use the same pattern as other workloads - // The test should verify recreation using WaitForJobRecreated instead + // The test should verify recreation using WaitForRecreation instead return false, nil } @@ -56,6 +64,21 @@ func (a *JobAdapter) WaitEnvVar(ctx context.Context, namespace, name, prefix str return false, nil } +// WaitRecreated waits for the Job to be recreated with a different UID using watches. +func (a *JobAdapter) WaitRecreated(ctx context.Context, namespace, name, originalUID string, timeout time.Duration) (string, bool, error) { + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.client.BatchV1().Jobs(namespace).Watch(ctx, opts) + } + job, err := WatchUntil(ctx, watchFunc, name, HasDifferentUID(JobUID, types.UID(originalUID)), timeout) + if errors.Is(err, ErrWatchTimeout) { + return "", false, nil + } + if err != nil { + return "", false, err + } + return string(job.UID), true, nil +} + // SupportsEnvVarStrategy returns false as Jobs don't support env var reload strategy. func (a *JobAdapter) SupportsEnvVarStrategy() bool { return false @@ -68,18 +91,13 @@ func (a *JobAdapter) RequiresSpecialHandling() bool { // GetOriginalUID retrieves the current UID of the Job for recreation verification. func (a *JobAdapter) GetOriginalUID(ctx context.Context, namespace, name string) (string, error) { - job, err := GetJob(ctx, a.client, namespace, name) + job, err := a.client.BatchV1().Jobs(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { return "", err } return string(job.UID), nil } -// WaitForRecreation waits for the Job to be recreated with a new UID. -func (a *JobAdapter) WaitForRecreation(ctx context.Context, namespace, name, originalUID string, timeout time.Duration) (string, bool, error) { - return WaitForJobRecreated(ctx, a.client, namespace, name, originalUID, timeout) -} - // buildJobOptions converts WorkloadConfig to JobOption slice. func buildJobOptions(cfg WorkloadConfig) []JobOption { return []JobOption{ diff --git a/test/e2e/utils/workload_openshift.go b/test/e2e/utils/workload_openshift.go index 3e89a40..7bf774a 100644 --- a/test/e2e/utils/workload_openshift.go +++ b/test/e2e/utils/workload_openshift.go @@ -2,13 +2,14 @@ package utils import ( "context" + "errors" "time" openshiftappsv1 "github.com/openshift/api/apps/v1" openshiftclient "github.com/openshift/client-go/apps/clientset/versioned" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/apimachinery/pkg/watch" ) // DCOption is a function that modifies a DeploymentConfig. @@ -47,19 +48,37 @@ func (a *DeploymentConfigAdapter) Delete(ctx context.Context, namespace, name st return a.openshiftClient.AppsV1().DeploymentConfigs(namespace).Delete(ctx, name, metav1.DeleteOptions{}) } -// WaitReady waits for the DeploymentConfig to be ready. +// WaitReady waits for the DeploymentConfig to be ready using watches. func (a *DeploymentConfigAdapter) WaitReady(ctx context.Context, namespace, name string, timeout time.Duration) error { - return WaitForDeploymentConfigReady(ctx, a.openshiftClient, namespace, name, timeout) + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.openshiftClient.AppsV1().DeploymentConfigs(namespace).Watch(ctx, opts) + } + _, err := WatchUntil(ctx, watchFunc, name, IsReady(DeploymentConfigIsReady), timeout) + return err } -// WaitReloaded waits for the DeploymentConfig to have the reload annotation. +// WaitReloaded waits for the DeploymentConfig to have the reload annotation using watches. func (a *DeploymentConfigAdapter) WaitReloaded(ctx context.Context, namespace, name, annotationKey string, timeout time.Duration) (bool, error) { - return WaitForDeploymentConfigReloaded(ctx, a.openshiftClient, namespace, name, annotationKey, timeout) + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.openshiftClient.AppsV1().DeploymentConfigs(namespace).Watch(ctx, opts) + } + _, err := WatchUntil(ctx, watchFunc, name, HasPodTemplateAnnotation(DeploymentConfigPodTemplate, annotationKey), timeout) + if errors.Is(err, ErrWatchTimeout) { + return false, nil + } + return err == nil, err } -// WaitEnvVar waits for the DeploymentConfig to have a STAKATER_ env var. +// WaitEnvVar waits for the DeploymentConfig to have a STAKATER_ env var using watches. func (a *DeploymentConfigAdapter) WaitEnvVar(ctx context.Context, namespace, name, prefix string, timeout time.Duration) (bool, error) { - return WaitForDeploymentConfigEnvVar(ctx, a.openshiftClient, namespace, name, prefix, timeout) + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.openshiftClient.AppsV1().DeploymentConfigs(namespace).Watch(ctx, opts) + } + _, err := WatchUntil(ctx, watchFunc, name, HasEnvVarPrefix(DeploymentConfigContainers, prefix), timeout) + if errors.Is(err, ErrWatchTimeout) { + return false, nil + } + return err == nil, err } // SupportsEnvVarStrategy returns true as DeploymentConfigs support env var reload strategy. @@ -117,47 +136,3 @@ func buildDeploymentConfigOptions(cfg WorkloadConfig) []DCOption { }, } } - -// WaitForDeploymentConfigReady waits for a DeploymentConfig to be ready using typed client. -func WaitForDeploymentConfigReady(ctx context.Context, client openshiftclient.Interface, namespace, name string, timeout time.Duration) error { - return wait.PollUntilContextTimeout(ctx, DefaultInterval, timeout, true, func(ctx context.Context) (bool, error) { - dc, err := client.AppsV1().DeploymentConfigs(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return false, nil - } - - if dc.Spec.Replicas > 0 && dc.Status.ReadyReplicas == dc.Spec.Replicas { - return true, nil - } - - return false, nil - }) -} - -// WaitForDeploymentConfigReloaded waits for a DeploymentConfig's pod template to have the reloader annotation. -func WaitForDeploymentConfigReloaded(ctx context.Context, client openshiftclient.Interface, namespace, name, annotationKey string, timeout time.Duration) (bool, error) { - return WaitForAnnotation(ctx, func(ctx context.Context) (map[string]string, error) { - dc, err := client.AppsV1().DeploymentConfigs(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return nil, err - } - if dc.Spec.Template != nil { - return dc.Spec.Template.Annotations, nil - } - return nil, nil - }, annotationKey, timeout) -} - -// WaitForDeploymentConfigEnvVar waits for a DeploymentConfig's container to have an env var with the given prefix. -func WaitForDeploymentConfigEnvVar(ctx context.Context, client openshiftclient.Interface, namespace, name, prefix string, timeout time.Duration) (bool, error) { - return WaitForEnvVarPrefix(ctx, func(ctx context.Context) ([]corev1.Container, error) { - dc, err := client.AppsV1().DeploymentConfigs(namespace).Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return nil, err - } - if dc.Spec.Template != nil { - return dc.Spec.Template.Spec.Containers, nil - } - return nil, nil - }, prefix, timeout) -} diff --git a/test/e2e/utils/workload_statefulset.go b/test/e2e/utils/workload_statefulset.go index c8dadbe..feb7e06 100644 --- a/test/e2e/utils/workload_statefulset.go +++ b/test/e2e/utils/workload_statefulset.go @@ -2,9 +2,12 @@ package utils import ( "context" + "errors" "time" appsv1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes" ) @@ -35,19 +38,37 @@ func (a *StatefulSetAdapter) Delete(ctx context.Context, namespace, name string) return DeleteStatefulSet(ctx, a.client, namespace, name) } -// WaitReady waits for the StatefulSet to be ready. +// WaitReady waits for the StatefulSet to be ready using watches. func (a *StatefulSetAdapter) WaitReady(ctx context.Context, namespace, name string, timeout time.Duration) error { - return WaitForStatefulSetReady(ctx, a.client, namespace, name, timeout) + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.client.AppsV1().StatefulSets(namespace).Watch(ctx, opts) + } + _, err := WatchUntil(ctx, watchFunc, name, IsReady(StatefulSetIsReady), timeout) + return err } -// WaitReloaded waits for the StatefulSet to have the reload annotation. +// WaitReloaded waits for the StatefulSet to have the reload annotation using watches. func (a *StatefulSetAdapter) WaitReloaded(ctx context.Context, namespace, name, annotationKey string, timeout time.Duration) (bool, error) { - return WaitForStatefulSetReloaded(ctx, a.client, namespace, name, annotationKey, timeout) + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.client.AppsV1().StatefulSets(namespace).Watch(ctx, opts) + } + _, err := WatchUntil(ctx, watchFunc, name, HasPodTemplateAnnotation(StatefulSetPodTemplate, annotationKey), timeout) + if errors.Is(err, ErrWatchTimeout) { + return false, nil + } + return err == nil, err } -// WaitEnvVar waits for the StatefulSet to have a STAKATER_ env var. +// WaitEnvVar waits for the StatefulSet to have a STAKATER_ env var using watches. func (a *StatefulSetAdapter) WaitEnvVar(ctx context.Context, namespace, name, prefix string, timeout time.Duration) (bool, error) { - return WaitForStatefulSetEnvVar(ctx, a.client, namespace, name, prefix, timeout) + watchFunc := func(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return a.client.AppsV1().StatefulSets(namespace).Watch(ctx, opts) + } + _, err := WatchUntil(ctx, watchFunc, name, HasEnvVarPrefix(StatefulSetContainers, prefix), timeout) + if errors.Is(err, ErrWatchTimeout) { + return false, nil + } + return err == nil, err } // SupportsEnvVarStrategy returns true as StatefulSets support env var reload strategy.