@@ -556,6 +556,128 @@ func TestRegistration_Apex_UsesRDAPNameservers(t *testing.T) {
556556 assert .True (t , res .RequeueAfter > 0 )
557557}
558558
559+ func TestVerification_RequeueImmediate_WhenWakeDueOrPast (t * testing.T ) {
560+ s := runtime .NewScheme ()
561+ _ = scheme .AddToScheme (s )
562+ _ = networkingv1alpha .AddToScheme (s )
563+
564+ // Fixed reference time
565+ now := time .Date (2025 , 10 , 22 , 15 , 40 , 14 , 0 , time .UTC )
566+
567+ // Domain has existing verification scaffold and next attempt is due NOW
568+ dom := newDomain ("default" , "due-now" , func (d * networkingv1alpha.Domain ) {
569+ d .Status .Verification = & networkingv1alpha.DomainVerificationStatus {
570+ DNSRecord : networkingv1alpha.DNSVerificationRecord {
571+ Name : "_dnsverify.example.com" ,
572+ Type : "TXT" ,
573+ Content : "token" ,
574+ },
575+ NextVerificationAttempt : metav1.Time {Time : now },
576+ }
577+ })
578+
579+ cl := fake .NewClientBuilder ().WithScheme (s ).WithObjects (dom ).WithStatusSubresource (dom ).Build ()
580+ mgr := & fakeMockManager {cl : cl }
581+
582+ // Configure zero retry interval and zero jitter to force nextAttempt == now
583+ operatorConfig := config.NetworkServicesOperator {
584+ DomainVerification : config.DomainVerificationConfig {
585+ RetryIntervals : []config.RetryInterval {{Interval : metav1.Duration {Duration : 0 }}},
586+ RetryJitterMaxFactor : 0 ,
587+ },
588+ DomainRegistration : config.DomainRegistrationConfig { // prevent nil panics in registration
589+ LookupTimeout : & metav1.Duration {Duration : 3 * time .Second },
590+ RefreshInterval : & metav1.Duration {Duration : time .Hour },
591+ JitterMaxFactor : 0.1 ,
592+ RetryBackoff : & metav1.Duration {Duration : time .Minute },
593+ },
594+ }
595+
596+ r := & DomainReconciler {
597+ mgr : mgr ,
598+ Config : operatorConfig ,
599+ timeNow : func () time.Time { return now },
600+ // Stubs to avoid real I/O
601+ httpGet : func (ctx context.Context , url string ) ([]byte , * http.Response , error ) {
602+ return nil , nil , fmt .Errorf ("not implemented" )
603+ },
604+ lookupTXT : func (ctx context.Context , name string ) ([]string , error ) { return nil , & net.DNSError {IsNotFound : true } },
605+ rdapDo : func (ctx context.Context , req * rdap.Request ) (* rdap.Response , error ) {
606+ return & rdap.Response {Object : & rdap.Domain {LDHName : "example.com" }}, nil
607+ },
608+ lookupNS : func (ctx context.Context , name string ) ([]* net.NS , error ) { return nil , & net.DNSError {IsNotFound : true } },
609+ lookupIP : func (ctx context.Context , name string ) ([]net.IPAddr , error ) { return nil , nil },
610+ rdapQueryIP : func (ctx context.Context , ip string ) (* rdap.IPNetwork , error ) { return nil , nil },
611+ }
612+
613+ res , err := r .Reconcile (context .Background (), mcreconcile.Request {ClusterName : "test" , Request : reconcile.Request {NamespacedName : client .ObjectKeyFromObject (dom )}})
614+ assert .NoError (t , err )
615+
616+ // With the fix, we should requeue immediately when wake time is now/past
617+ assert .Equal (t , time .Duration (1 * time .Second ), res .RequeueAfter )
618+ }
619+
620+ func TestVerification_RequeueImmediate_WhenWakeInPast (t * testing.T ) {
621+ s := runtime .NewScheme ()
622+ _ = scheme .AddToScheme (s )
623+ _ = networkingv1alpha .AddToScheme (s )
624+
625+ // Fixed reference time
626+ now := time .Date (2025 , 10 , 22 , 15 , 40 , 14 , 0 , time .UTC )
627+
628+ // Domain has existing verification scaffold and next attempt was due 1s ago
629+ dom := newDomain ("default" , "due-past" , func (d * networkingv1alpha.Domain ) {
630+ d .Status .Verification = & networkingv1alpha.DomainVerificationStatus {
631+ DNSRecord : networkingv1alpha.DNSVerificationRecord {
632+ Name : "_dnsverify.example.com" ,
633+ Type : "TXT" ,
634+ Content : "token" ,
635+ },
636+ NextVerificationAttempt : metav1.Time {Time : now .Add (- 1 * time .Second )},
637+ }
638+ })
639+
640+ cl := fake .NewClientBuilder ().WithScheme (s ).WithObjects (dom ).WithStatusSubresource (dom ).Build ()
641+ mgr := & fakeMockManager {cl : cl }
642+
643+ operatorConfig := config.NetworkServicesOperator {
644+ DomainVerification : config.DomainVerificationConfig {
645+ RetryIntervals : []config.RetryInterval {{Interval : metav1.Duration {Duration : 0 }}},
646+ RetryJitterMaxFactor : 0 ,
647+ },
648+ DomainRegistration : config.DomainRegistrationConfig {
649+ LookupTimeout : & metav1.Duration {Duration : 3 * time .Second },
650+ RefreshInterval : & metav1.Duration {Duration : time .Hour },
651+ JitterMaxFactor : 0.1 ,
652+ RetryBackoff : & metav1.Duration {Duration : time .Minute },
653+ },
654+ }
655+
656+ r := & DomainReconciler {
657+ mgr : mgr ,
658+ Config : operatorConfig ,
659+ timeNow : func () time.Time { return now },
660+ // Stubs to avoid real I/O
661+ httpGet : func (ctx context.Context , url string ) ([]byte , * http.Response , error ) {
662+ return nil , nil , fmt .Errorf ("not implemented" )
663+ },
664+ lookupTXT : func (ctx context.Context , name string ) ([]string , error ) { return nil , & net.DNSError {IsNotFound : true } },
665+ rdapDo : func (ctx context.Context , req * rdap.Request ) (* rdap.Response , error ) {
666+ return & rdap.Response {Object : & rdap.Domain {LDHName : "example.com" }}, nil
667+ },
668+ lookupNS : func (ctx context.Context , name string ) ([]* net.NS , error ) { return nil , & net.DNSError {IsNotFound : true } },
669+ lookupIP : func (ctx context.Context , name string ) ([]net.IPAddr , error ) { return nil , nil },
670+ rdapQueryIP : func (ctx context.Context , ip string ) (* rdap.IPNetwork , error ) { return nil , nil },
671+ }
672+
673+ res , err := r .Reconcile (context .Background (), mcreconcile.Request {ClusterName : "test" , Request : reconcile.Request {NamespacedName : client .ObjectKeyFromObject (dom )}})
674+ assert .NoError (t , err )
675+
676+ // With the fix, we should requeue immediately when wake time is past
677+ assert .True (t , res .Requeue )
678+ assert .Equal (t , time .Duration (0 ), res .RequeueAfter )
679+ }
680+
559681func TestRegistration_Subdomain_DelegationOverridesApexNS (t * testing.T ) {
560682 s := runtime .NewScheme ()
561683 _ = scheme .AddToScheme (s )
0 commit comments