@@ -653,6 +653,7 @@ func TestCNPGClusterFreshlyRecovered(t *testing.T) {
653653 cases := []struct {
654654 name string
655655 state recoveryClusterState
656+ appMark string
656657 startedAt * metav1.Time
657658 want bool
658659 }{
@@ -689,37 +690,56 @@ func TestCNPGClusterFreshlyRecovered(t *testing.T) {
689690 {
690691 name : "unmarked, created after start (our own re-render by an older chart): fresh" ,
691692 state : recoveryClusterState {hasRecovery : true , createdAt : & after },
693+ appMark : ours ,
692694 startedAt : & started ,
693695 want : true ,
694696 },
697+ {
698+ name : "unmarked, created after start, values not patched by this restore (manual recovery re-rendered): not fresh" ,
699+ state : recoveryClusterState {hasRecovery : true , createdAt : & after },
700+ appMark : "" ,
701+ startedAt : & started ,
702+ want : false ,
703+ },
704+ {
705+ name : "unmarked, created after start, values patched by another restore: not fresh" ,
706+ state : recoveryClusterState {hasRecovery : true , createdAt : & after },
707+ appMark : other ,
708+ startedAt : & started ,
709+ want : false ,
710+ },
695711 {
696712 name : "unmarked, created before start (leftover from previous restore): not fresh" ,
697713 state : recoveryClusterState {hasRecovery : true , createdAt : & before },
714+ appMark : ours ,
698715 startedAt : & started ,
699716 want : false ,
700717 },
701718 {
702719 name : "unmarked, created exactly at start: not fresh (conservative tie -> purge)" ,
703720 state : recoveryClusterState {hasRecovery : true , createdAt : & started },
721+ appMark : ours ,
704722 startedAt : & started ,
705723 want : false ,
706724 },
707725 {
708726 name : "unmarked, missing cluster creation timestamp: not fresh" ,
709727 state : recoveryClusterState {hasRecovery : true },
728+ appMark : ours ,
710729 startedAt : & started ,
711730 want : false ,
712731 },
713732 {
714733 name : "unmarked, missing job start timestamp: not fresh" ,
715734 state : recoveryClusterState {hasRecovery : true , createdAt : & after },
735+ appMark : ours ,
716736 startedAt : nil ,
717737 want : false ,
718738 },
719739 }
720740 for _ , tc := range cases {
721741 t .Run (tc .name , func (t * testing.T ) {
722- got := cnpgClusterFreshlyRecovered (tc .state , ours , tc .startedAt )
742+ got := cnpgClusterFreshlyRecovered (tc .state , ours , tc .appMark , tc . startedAt )
723743 if got != tc .want {
724744 t .Errorf ("got %v want %v" , got , tc .want )
725745 }
@@ -2279,12 +2299,16 @@ func TestReconcileCNPGRestore_RepeatInPlacePurgesStaleRecoveryCluster(t *testing
22792299 }
22802300 })
22812301
2282- t .Run ("freshly-recovered cluster from this restore is not re-purged" , func (t * testing.T ) {
2302+ t .Run ("unmarked cluster this restore's values rendered is not re-purged" , func (t * testing.T ) {
22832303 backup := mkBackupArtifact (t )
2284- // creationTimestamp a minute after StartedAt: this restore's own re-render.
2304+ // creationTimestamp a minute after StartedAt: this restore's own
2305+ // re-render by a chart that does not annotate the Cluster.
22852306 fresh := metav1 .NewTime (startedAt .Add (time .Minute ))
2286- c := newCNPGStrategyTestClient (t , backup , mkRestoreJob (), strategy , cnpgBackup ,
2287- newPostgresApp (appName , ns ), mkRecoveryCluster (fresh ))
2307+ rjSeed := mkRestoreJob ()
2308+ app := newPostgresApp (appName , ns )
2309+ app .Spec .Bootstrap .NewServerName = restoredServerName (clusterName , rjSeed .UID )
2310+ c := newCNPGStrategyTestClient (t , backup , rjSeed , strategy , cnpgBackup ,
2311+ app , mkRecoveryCluster (fresh ))
22882312 r := & RestoreJobReconciler {Client : c , Interface : dynamicfake .NewSimpleDynamicClient (testCNPGScheme (t )), Recorder : record .NewFakeRecorder (10 )}
22892313
22902314 rj := & backupsv1alpha1.RestoreJob {}
@@ -2307,6 +2331,33 @@ func TestReconcileCNPGRestore_RepeatInPlacePurgesStaleRecoveryCluster(t *testing
23072331 }
23082332 })
23092333
2334+ // A manually configured recovery (bootstrap.enabled without
2335+ // newServerName) renders no annotation. Re-rendered after StartedAt but
2336+ // before this restore patches the values, it holds the manual recovery
2337+ // source, not this restore's backup.
2338+ t .Run ("unmarked cluster from values this restore has not patched is purged even when created after start" , func (t * testing.T ) {
2339+ backup := mkBackupArtifact (t )
2340+ fresh := metav1 .NewTime (startedAt .Add (time .Minute ))
2341+ app := newPostgresApp (appName , ns )
2342+ app .Spec .Bootstrap .Enabled = true
2343+ app .Spec .Bootstrap .OldName = "manual-source"
2344+ c := newCNPGStrategyTestClient (t , backup , mkRestoreJob (), strategy , cnpgBackup ,
2345+ app , mkRecoveryCluster (fresh ), mkClusterPVC ())
2346+ r := & RestoreJobReconciler {Client : c , Interface : dynamicfake .NewSimpleDynamicClient (testCNPGScheme (t )), Recorder : record .NewFakeRecorder (10 )}
2347+
2348+ rj := & backupsv1alpha1.RestoreJob {}
2349+ if err := c .Get (ctx , client.ObjectKey {Namespace : ns , Name : "rj" }, rj ); err != nil {
2350+ t .Fatalf ("get seeded RestoreJob: %v" , err )
2351+ }
2352+ if _ , err := r .reconcileCNPGRestore (ctx , rj , backup ); err != nil {
2353+ t .Fatalf ("reconcileCNPGRestore: %v" , err )
2354+ }
2355+ err := c .Get (ctx , client.ObjectKey {Namespace : ns , Name : clusterName }, & cnpgtypes.Cluster {})
2356+ if ! apierrors .IsNotFound (err ) {
2357+ t .Fatalf ("expected the manual recovery Cluster to be purged (NotFound), got err=%v" , err )
2358+ }
2359+ })
2360+
23102361 t .Run ("recovery cluster marked by another restore is purged even when created after start" , func (t * testing.T ) {
23112362 backup := mkBackupArtifact (t )
23122363 fresh := metav1 .NewTime (startedAt .Add (time .Minute ))
0 commit comments