@@ -567,4 +567,98 @@ public void testTokenRefreshDoesNotTriggerPushRegistration() throws Exception {
567567 }
568568 }
569569
570+ @ Test
571+ public void testAuthTokenRecoveryFrom401TriggersPushAndMessageSync () throws Exception {
572+ IterablePushRegistration .IterablePushRegistrationImpl originalPushImpl = IterablePushRegistration .instance ;
573+ IterablePushRegistration .instance = mock (IterablePushRegistration .IterablePushRegistrationImpl .class );
574+
575+ try {
576+ // Initialize with auth and auto push registration enabled
577+ getContext ().getSharedPreferences (IterableConstants .SHARED_PREFS_FILE , Context .MODE_PRIVATE ).edit ().clear ().apply ();
578+ IterableApi .sharedInstance = new IterableApi ();
579+ authHandler = mock (IterableAuthHandler .class );
580+ IterableApi .initialize (getContext (), "apiKey" ,
581+ new IterableConfig .Builder ()
582+ .setAuthHandler (authHandler )
583+ .setAutoPushRegistration (true )
584+ .setPushIntegrationName ("pushIntegration" )
585+ .build ());
586+
587+ // Initial login
588+ doReturn (validJWT ).when (authHandler ).onAuthTokenRequested ();
589+ IterableApi .getInstance ().setEmail ("test@example.com" );
590+ Thread .sleep (500 );
591+ shadowOf (getMainLooper ()).idle ();
592+ shadowOf (getMainLooper ()).runToEndOfTasks ();
593+
594+ // Verify initial push registration happened
595+ verify (IterablePushRegistration .instance ).executePushRegistrationTask (any (IterablePushRegistrationData .class ));
596+
597+ // Reset mock to clear invocation history
598+ Mockito .reset (IterablePushRegistration .instance );
599+
600+ // Simulate 401 rejection: mark auth token as INVALID
601+ IterableApi .getInstance ().getAuthManager ().setAuthTokenInvalid ();
602+
603+ // Simulate token recovery: transition from INVALID -> VALID
604+ // This should trigger AuthTokenReadyListeners (including IterableApi)
605+ IterableApi .getInstance ().getAuthManager ().setIsLastAuthTokenValid (true );
606+
607+ // Allow main looper to process any posted callbacks
608+ shadowOf (getMainLooper ()).idle ();
609+ shadowOf (getMainLooper ()).runToEndOfTasks ();
610+
611+ // After 401 recovery, push registration SHOULD be triggered
612+ verify (IterablePushRegistration .instance ).executePushRegistrationTask (any (IterablePushRegistrationData .class ));
613+ } finally {
614+ IterablePushRegistration .instance = originalPushImpl ;
615+ }
616+ }
617+
618+ @ Test
619+ public void testRoutineTokenRefreshDoesNotTriggerResync () throws Exception {
620+ IterablePushRegistration .IterablePushRegistrationImpl originalPushImpl = IterablePushRegistration .instance ;
621+ IterablePushRegistration .instance = mock (IterablePushRegistration .IterablePushRegistrationImpl .class );
622+
623+ try {
624+ // Initialize with auth and auto push registration enabled
625+ getContext ().getSharedPreferences (IterableConstants .SHARED_PREFS_FILE , Context .MODE_PRIVATE ).edit ().clear ().apply ();
626+ IterableApi .sharedInstance = new IterableApi ();
627+ authHandler = mock (IterableAuthHandler .class );
628+ IterableApi .initialize (getContext (), "apiKey" ,
629+ new IterableConfig .Builder ()
630+ .setAuthHandler (authHandler )
631+ .setAutoPushRegistration (true )
632+ .setPushIntegrationName ("pushIntegration" )
633+ .build ());
634+
635+ // Initial login
636+ doReturn (validJWT ).when (authHandler ).onAuthTokenRequested ();
637+ IterableApi .getInstance ().setEmail ("test@example.com" );
638+ Thread .sleep (500 );
639+ shadowOf (getMainLooper ()).idle ();
640+ shadowOf (getMainLooper ()).runToEndOfTasks ();
641+
642+ // Verify initial push registration happened
643+ verify (IterablePushRegistration .instance ).executePushRegistrationTask (any (IterablePushRegistrationData .class ));
644+ Mockito .reset (IterablePushRegistration .instance );
645+
646+ // Simulate routine token refresh (no INVALID state involved)
647+ // Auth state stays UNKNOWN -> UNKNOWN, so listener should NOT fire
648+ doReturn (newJWT ).when (authHandler ).onAuthTokenRequested ();
649+ IterableApi .getInstance ().getAuthManager ().requestNewAuthToken (false , null );
650+ Thread .sleep (500 );
651+ shadowOf (getMainLooper ()).idle ();
652+ shadowOf (getMainLooper ()).runToEndOfTasks ();
653+
654+ // Verify token was actually refreshed
655+ assertEquals (newJWT , IterableApi .getInstance ().getAuthToken ());
656+
657+ // Assert that push registration was NOT called on routine refresh
658+ verify (IterablePushRegistration .instance , never ()).executePushRegistrationTask (any (IterablePushRegistrationData .class ));
659+ } finally {
660+ IterablePushRegistration .instance = originalPushImpl ;
661+ }
662+ }
663+
570664}
0 commit comments