@@ -466,3 +466,165 @@ func TestKustomizationReconciler_RESTMapper(t *testing.T) {
466466 g .Expect (err ).To (HaveOccurred ())
467467 })
468468}
469+
470+ func TestKustomizationReconciler_CancelHealthCheckOnNewRevision (t * testing.T ) {
471+ g := NewWithT (t )
472+ id := "cancel-" + randStringRunes (5 )
473+ resultK := & kustomizev1.Kustomization {}
474+ timeout := 60 * time .Second
475+
476+ reconciler .CancelHealthCheckOnNewRevision = true
477+ t .Cleanup (func () { reconciler .CancelHealthCheckOnNewRevision = false })
478+
479+ err := createNamespace (id )
480+ g .Expect (err ).NotTo (HaveOccurred (), "failed to create test namespace" )
481+
482+ err = createKubeConfigSecret (id )
483+ g .Expect (err ).NotTo (HaveOccurred (), "failed to create kubeconfig secret" )
484+
485+ // Create initial successful manifests
486+ successManifests := []testserver.File {
487+ {
488+ Name : "configmap.yaml" ,
489+ Body : fmt .Sprintf (`apiVersion: v1
490+ kind: ConfigMap
491+ metadata:
492+ name: test-config
493+ namespace: %s
494+ data:
495+ foo: bar` , id ),
496+ },
497+ }
498+ artifact , err := testServer .ArtifactFromFiles (successManifests )
499+ g .Expect (err ).ToNot (HaveOccurred ())
500+
501+ repositoryName := types.NamespacedName {
502+ Name : fmt .Sprintf ("cancel-%s" , randStringRunes (5 )),
503+ Namespace : id ,
504+ }
505+
506+ err = applyGitRepository (repositoryName , artifact , "main/" + artifact )
507+ g .Expect (err ).NotTo (HaveOccurred ())
508+
509+ kustomization := & kustomizev1.Kustomization {}
510+ kustomization .Name = id
511+ kustomization .Namespace = id
512+ kustomization .Spec = kustomizev1.KustomizationSpec {
513+ Interval : metav1.Duration {Duration : 10 * time .Minute },
514+ Path : "./" ,
515+ Wait : true ,
516+ Timeout : & metav1.Duration {Duration : 5 * time .Minute },
517+ SourceRef : kustomizev1.CrossNamespaceSourceReference {
518+ Name : repositoryName .Name ,
519+ Kind : sourcev1 .GitRepositoryKind ,
520+ Namespace : id ,
521+ },
522+ KubeConfig : & meta.KubeConfigReference {
523+ SecretRef : & meta.SecretKeyReference {
524+ Name : "kubeconfig" ,
525+ },
526+ },
527+ }
528+
529+ err = k8sClient .Create (context .Background (), kustomization )
530+ g .Expect (err ).NotTo (HaveOccurred ())
531+
532+ // Wait for initial reconciliation to succeed
533+ g .Eventually (func () bool {
534+ _ = k8sClient .Get (context .Background (), client .ObjectKeyFromObject (kustomization ), resultK )
535+ return conditions .IsReady (resultK )
536+ }, timeout , time .Second ).Should (BeTrue ())
537+
538+ // Create failing manifests (deployment with bad image that will timeout)
539+ failingManifests := []testserver.File {
540+ {
541+ Name : "deployment.yaml" ,
542+ Body : fmt .Sprintf (`apiVersion: apps/v1
543+ kind: Deployment
544+ metadata:
545+ name: failing-deployment
546+ namespace: %s
547+ spec:
548+ replicas: 1
549+ selector:
550+ matchLabels:
551+ app: failing-app
552+ template:
553+ metadata:
554+ labels:
555+ app: failing-app
556+ spec:
557+ containers:
558+ - name: app
559+ image: nonexistent.registry/badimage:latest
560+ ports:
561+ - containerPort: 8080` , id ),
562+ },
563+ }
564+
565+ // Apply failing revision
566+ failingArtifact , err := testServer .ArtifactFromFiles (failingManifests )
567+ g .Expect (err ).ToNot (HaveOccurred ())
568+
569+ err = applyGitRepository (repositoryName , failingArtifact , "main/" + failingArtifact )
570+ g .Expect (err ).NotTo (HaveOccurred ())
571+
572+ // Wait for reconciliation to start on failing revision
573+ g .Eventually (func () bool {
574+ _ = k8sClient .Get (context .Background (), client .ObjectKeyFromObject (kustomization ), resultK )
575+ return resultK .Status .LastAttemptedRevision == "main/" + failingArtifact
576+ }, timeout , time .Second ).Should (BeTrue ())
577+
578+ // Now quickly apply a fixed revision while health check should be in progress
579+ fixedManifests := []testserver.File {
580+ {
581+ Name : "deployment.yaml" ,
582+ Body : fmt .Sprintf (`apiVersion: apps/v1
583+ kind: Deployment
584+ metadata:
585+ name: working-deployment
586+ namespace: %s
587+ spec:
588+ replicas: 1
589+ selector:
590+ matchLabels:
591+ app: working-app
592+ template:
593+ metadata:
594+ labels:
595+ app: working-app
596+ spec:
597+ containers:
598+ - name: app
599+ image: nginx:latest
600+ ports:
601+ - containerPort: 80` , id ),
602+ },
603+ }
604+
605+ fixedArtifact , err := testServer .ArtifactFromFiles (fixedManifests )
606+ g .Expect (err ).ToNot (HaveOccurred ())
607+
608+ // Apply the fixed revision shortly after the failing one
609+ time .Sleep (2 * time .Second ) // Give some time for health check to start
610+ err = applyGitRepository (repositoryName , fixedArtifact , "main/" + fixedArtifact )
611+ g .Expect (err ).NotTo (HaveOccurred ())
612+
613+ // The key test: verify that the fixed revision gets attempted
614+ // and that the health check cancellation worked
615+ g .Eventually (func () bool {
616+ _ = k8sClient .Get (context .Background (), client .ObjectKeyFromObject (kustomization ), resultK )
617+ return resultK .Status .LastAttemptedRevision == "main/" + fixedArtifact
618+ }, timeout , time .Second ).Should (BeTrue ())
619+
620+ // Check cancellation event was emitted
621+ events := getEvents (resultK .GetName (), nil )
622+ var found bool
623+ for _ , e := range events {
624+ if e .Message == "New revision detected during health check, cancelling" {
625+ found = true
626+ break
627+ }
628+ }
629+ g .Expect (found ).To (BeTrue (), "did not find event for health check cancellation" )
630+ }
0 commit comments