From f9c80156a560930a070410bcbc0888bc06b779b9 Mon Sep 17 00:00:00 2001 From: "Ankit Kr. Chowdhury" Date: Thu, 6 Aug 2026 08:55:22 +0000 Subject: [PATCH] fix: retry image-update writes in Eventually to handle 409 Conflict in CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The reconciler can modify the AgentDeployment (finalizer add, status write) between the test's Get and Update, bumping the resourceVersion. The resulting 409 Conflict was flaking the 'does not advance StableVersion during a partial rollout' test (and would also flake 'updates the child Deployment image'). Fix: wrap the Get+Update block in Eventually so the test transparently retries on conflict — the standard controller-runtime envtest idiom for this pattern. --- .../agentdeployment_controller_test.go | 40 ++++++++++++++----- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/internal/controller/agentdeployment_controller_test.go b/internal/controller/agentdeployment_controller_test.go index 4160556..6f65ae5 100644 --- a/internal/controller/agentdeployment_controller_test.go +++ b/internal/controller/agentdeployment_controller_test.go @@ -363,11 +363,17 @@ var _ = Describe("AgentDeployment Controller", func() { }) It("updates the child Deployment image when spec.image changes", func() { - // Update the image field. - ad := &agentraxv1alpha1.AgentDeployment{} - Expect(k8sClient.Get(ctx, key, ad)).To(Succeed()) - ad.Spec.Image = "nginx:1.25" - Expect(k8sClient.Update(ctx, ad)).To(Succeed()) + // Wrap Get+Update in Eventually to handle 409 Conflict: the reconciler + // may bump the resourceVersion (finalizer add, status write) between + // the test's Get and Update, causing a stale-object conflict. + Eventually(func() error { + ad := &agentraxv1alpha1.AgentDeployment{} + if err := k8sClient.Get(ctx, key, ad); err != nil { + return err + } + ad.Spec.Image = "nginx:1.25" + return k8sClient.Update(ctx, ad) + }, testTimeout, testInterval).Should(Succeed(), "spec.image update should be accepted without conflict") // Verify the child Deployment picks up the new image. Eventually(func() string { @@ -388,12 +394,26 @@ var _ = Describe("AgentDeployment Controller", func() { // After updating the image the Deployment generation advances but // ObservedGeneration / UpdatedReplicas / AvailableReplicas never satisfy // the rollout-complete gate — so StableVersion must stay empty. - ad := &agentraxv1alpha1.AgentDeployment{} - Expect(k8sClient.Get(ctx, key, ad)).To(Succeed()) - stableVersionBefore := ad.Status.StableVersion + var stableVersionBefore string + // Wrap Get in Eventually to read a fully-settled object before capturing the baseline. + Eventually(func() error { + ad := &agentraxv1alpha1.AgentDeployment{} + if err := k8sClient.Get(ctx, key, ad); err != nil { + return err + } + stableVersionBefore = ad.Status.StableVersion + return nil + }, testTimeout, testInterval).Should(Succeed()) - ad.Spec.Image = "nginx:1.25" - Expect(k8sClient.Update(ctx, ad)).To(Succeed()) + // Wrap Get+Update in Eventually to handle 409 Conflict (same as above). + Eventually(func() error { + ad := &agentraxv1alpha1.AgentDeployment{} + if err := k8sClient.Get(ctx, key, ad); err != nil { + return err + } + ad.Spec.Image = "nginx:1.25" + return k8sClient.Update(ctx, ad) + }, testTimeout, testInterval).Should(Succeed(), "spec.image update should be accepted without conflict") // Wait for the Deployment spec to reflect the new image so we know the // reconciler has processed the update.