@@ -159,6 +159,43 @@ func TestMigrationReconciler_snapshotFailed_setsFailedPhase(t *testing.T) {
159159 assert .Equal (t , "Failed" , updated .Status .Phase )
160160}
161161
162+ func TestMigrationReconciler_requeueWhenSourceVMUnscheduled (t * testing.T ) {
163+ // Source VM has no NodeName yet → should requeue, not fail
164+ mig := & impv1alpha1.ImpVMMigration {}
165+ mig .Name , mig .Namespace = "mig-unsched" , "default"
166+ mig .Spec .SourceVMName = "vm-unsched"
167+ mig .Spec .SourceVMNamespace = "default"
168+ mig .Status .Phase = "Pending"
169+
170+ vm := & impv1alpha1.ImpVM {}
171+ vm .Name , vm .Namespace = "vm-unsched" , "default"
172+ // NodeName is empty — VM not yet scheduled
173+
174+ scheme := newMigrationTestScheme (t )
175+ c := fake .NewClientBuilder ().WithScheme (scheme ).WithObjects (mig , vm ).WithStatusSubresource (mig ).Build ()
176+ // Push status into the fake store.
177+ migWithStatus := mig .DeepCopy ()
178+ require .NoError (t , c .Status ().Update (context .Background (), migWithStatus ))
179+
180+ r := & ImpVMMigrationReconciler {Client : c , Scheme : scheme }
181+
182+ res , err := r .Reconcile (context .Background (), reconcile.Request {
183+ NamespacedName : types.NamespacedName {Name : "mig-unsched" , Namespace : "default" },
184+ })
185+ if err != nil {
186+ t .Fatalf ("unexpected error: %v" , err )
187+ }
188+ if res .RequeueAfter == 0 && ! res .Requeue {
189+ t .Error ("expected requeue when source VM has no NodeName" )
190+ }
191+
192+ var updated impv1alpha1.ImpVMMigration
193+ _ = c .Get (context .Background (), types.NamespacedName {Name : "mig-unsched" , Namespace : "default" }, & updated )
194+ if updated .Status .Phase == "Failed" {
195+ t .Error ("migration should not be Failed when source VM is simply unscheduled" )
196+ }
197+ }
198+
162199func newMigrationReconciler () * ImpVMMigrationReconciler {
163200 return & ImpVMMigrationReconciler {
164201 Client : k8sClient ,
0 commit comments