Loading app/src/main/java/foundation/e/apps/data/login/playstore/PlayStoreAuthenticator.kt +3 −7 Original line number Diff line number Diff line Loading @@ -136,15 +136,11 @@ class PlayStoreAuthenticator @Inject constructor( } private suspend fun loginWithGoogleBackend(): ResultSupreme<AuthData?> { val aasToken = playStoreAuthStore.awaitAasToken() return if (aasToken.isNotBlank()) { loginWithAasToken() } else { loginWithAasTokenConversion() } val storedAasToken = playStoreAuthStore.awaitAasToken() if (storedAasToken.isNotBlank()) { return loginWithAasToken() } private suspend fun loginWithAasTokenConversion(): ResultSupreme<AuthData?> { val email = playStoreAuthStore.awaitEmail() val oauthToken = playStoreAuthStore.awaitOauthToken() val aasTokenResponse = aasTokenConverter.convert(email, oauthToken) Loading app/src/test/java/foundation/e/apps/data/login/playstore/PlayStoreAuthenticatorTest.kt +129 −2 Original line number Diff line number Diff line Loading @@ -25,6 +25,10 @@ import kotlinx.serialization.json.Json import org.junit.After import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any import org.mockito.kotlin.mock import org.mockito.kotlin.whenever import org.mockito.kotlin.verify as mockitoVerify import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config Loading Loading @@ -144,16 +148,18 @@ class PlayStoreAuthenticatorTest { val sessionRepository = FakeSessionRepository( initialUser = User.GOOGLE, playStoreAuthSource = PlayStoreAuthSource.GOOGLE, aasToken = "aas-token" aasToken = "", oauthToken = "oauth-token", ) val googleLoginManager = mockk<GoogleLoginManager>() val microgLoginManager = mockk<MicrogLoginManager>() val anonymousLoginManager = mockk<AnonymousLoginManager>() val aasTokenConverter = mockk<OauthToAasTokenConverter>() val aasTokenConverter = mock<OauthToAasTokenConverter>() val userProfileFetcher = mockk<UserProfileFetcher>() val authData = AuthData(email = "user@gmail.com") val profile = UserProfile(name = "Test User", email = authData.email) whenever(aasTokenConverter.convert(any(), any())).thenReturn(ResultSupreme.Success("fresh-aas-token")) coEvery { googleLoginManager.login() } returns authData coEvery { userProfileFetcher.fetch(authData) } returns profile Loading @@ -176,10 +182,131 @@ class PlayStoreAuthenticatorTest { assertThat(authObject.result.data?.email).isEqualTo(authData.email) assertThat(authObject.result.data?.userProfile).isEqualTo(profile) assertThat(authObject.result.data?.locale).isEqualTo(context.resources.configuration.locales[0]) mockitoVerify(aasTokenConverter).convert(any(), any()) coVerify(exactly = 1) { googleLoginManager.login() } coVerify(exactly = 1) { userProfileFetcher.fetch(authData) } } @Test fun login_refreshesAasTokenViaConversionOnGoogleLogin() = runTest { val context = applicationContext() val sessionRepository = FakeSessionRepository( initialUser = User.GOOGLE, playStoreAuthSource = PlayStoreAuthSource.GOOGLE, aasToken = "", oauthToken = "oauth-token", ) val googleLoginManager = mockk<GoogleLoginManager>() val aasTokenConverter = mock<OauthToAasTokenConverter>() val userProfileFetcher = mockk<UserProfileFetcher>() val authData = AuthData(email = "user@gmail.com") whenever(aasTokenConverter.convert(any(), any())).thenReturn(ResultSupreme.Success("fresh-aas-token")) coEvery { googleLoginManager.login() } returns authData coEvery { userProfileFetcher.fetch(any()) } returns null val authenticator = PlayStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, appPreferencesRepository = FakeAppPreferencesRepository(), authDataCache = AuthDataCache(sessionRepository, json), googleLoginManager = googleLoginManager, microgLoginManager = mockk(), anonymousLoginManager = mockk(), aasTokenConverter = aasTokenConverter, userProfileFetcher = userProfileFetcher ) authenticator.login() mockitoVerify(aasTokenConverter).convert(any(), any()) coVerify(exactly = 1) { googleLoginManager.login() } assertThat(sessionRepository.awaitAasToken()).isEqualTo("fresh-aas-token") } @Test fun login_usesStoredAasTokenWithoutConversionWhenAvailable() = runTest { val context = applicationContext() val sessionRepository = FakeSessionRepository( initialUser = User.GOOGLE, playStoreAuthSource = PlayStoreAuthSource.GOOGLE, aasToken = "stored-aas-token", oauthToken = "expired-oauth-token", ) val googleLoginManager = mockk<GoogleLoginManager>() val aasTokenConverter = mock<OauthToAasTokenConverter>() val userProfileFetcher = mockk<UserProfileFetcher>() val authData = AuthData(email = "user@gmail.com") whenever(aasTokenConverter.convert(any(), any())).thenReturn(ResultSupreme.Error("conversion failed")) coEvery { googleLoginManager.login() } returns authData coEvery { userProfileFetcher.fetch(any()) } returns null val authenticator = PlayStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, appPreferencesRepository = FakeAppPreferencesRepository(), authDataCache = AuthDataCache(sessionRepository, json), googleLoginManager = googleLoginManager, microgLoginManager = mockk(), anonymousLoginManager = mockk(), aasTokenConverter = aasTokenConverter, userProfileFetcher = userProfileFetcher ) val result = authenticator.login() val authObject = result.authObject as AuthObject.GPlayAuth assertThat(authObject.result.data?.email).isEqualTo(authData.email) mockitoVerify(aasTokenConverter, org.mockito.kotlin.never()).convert(any(), any()) coVerify(exactly = 1) { googleLoginManager.login() } // AAS token in storage must not be overwritten when conversion failed assertThat(sessionRepository.awaitAasToken()).isEqualTo("stored-aas-token") } @Test fun login_fallsBackToOauthTokenWhenConversionFailsAndNoStoredAasToken() = runTest { val context = applicationContext() val sessionRepository = FakeSessionRepository( initialUser = User.GOOGLE, playStoreAuthSource = PlayStoreAuthSource.GOOGLE, aasToken = "", oauthToken = "oauth-token", ) val googleLoginManager = mockk<GoogleLoginManager>() val aasTokenConverter = mock<OauthToAasTokenConverter>() val userProfileFetcher = mockk<UserProfileFetcher>() val authData = AuthData(email = "user@gmail.com") whenever(aasTokenConverter.convert(any(), any())).thenReturn(ResultSupreme.Error("conversion failed")) coEvery { googleLoginManager.loginWithOauthToken("oauth-token") } returns authData coEvery { userProfileFetcher.fetch(any()) } returns null val authenticator = PlayStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, appPreferencesRepository = FakeAppPreferencesRepository(), authDataCache = AuthDataCache(sessionRepository, json), googleLoginManager = googleLoginManager, microgLoginManager = mockk(), anonymousLoginManager = mockk(), aasTokenConverter = aasTokenConverter, userProfileFetcher = userProfileFetcher ) val result = authenticator.login() val authObject = result.authObject as AuthObject.GPlayAuth assertThat(authObject.result.data?.email).isEqualTo(authData.email) mockitoVerify(aasTokenConverter).convert(any(), any()) coVerify(exactly = 1) { googleLoginManager.loginWithOauthToken("oauth-token") } coVerify(exactly = 0) { googleLoginManager.login() } assertThat(sessionRepository.awaitAasToken()).isEmpty() } private class FakeSessionRepository( initialUser: User, currentAuthData: AuthData? = null, Loading Loading
app/src/main/java/foundation/e/apps/data/login/playstore/PlayStoreAuthenticator.kt +3 −7 Original line number Diff line number Diff line Loading @@ -136,15 +136,11 @@ class PlayStoreAuthenticator @Inject constructor( } private suspend fun loginWithGoogleBackend(): ResultSupreme<AuthData?> { val aasToken = playStoreAuthStore.awaitAasToken() return if (aasToken.isNotBlank()) { loginWithAasToken() } else { loginWithAasTokenConversion() } val storedAasToken = playStoreAuthStore.awaitAasToken() if (storedAasToken.isNotBlank()) { return loginWithAasToken() } private suspend fun loginWithAasTokenConversion(): ResultSupreme<AuthData?> { val email = playStoreAuthStore.awaitEmail() val oauthToken = playStoreAuthStore.awaitOauthToken() val aasTokenResponse = aasTokenConverter.convert(email, oauthToken) Loading
app/src/test/java/foundation/e/apps/data/login/playstore/PlayStoreAuthenticatorTest.kt +129 −2 Original line number Diff line number Diff line Loading @@ -25,6 +25,10 @@ import kotlinx.serialization.json.Json import org.junit.After import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any import org.mockito.kotlin.mock import org.mockito.kotlin.whenever import org.mockito.kotlin.verify as mockitoVerify import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config Loading Loading @@ -144,16 +148,18 @@ class PlayStoreAuthenticatorTest { val sessionRepository = FakeSessionRepository( initialUser = User.GOOGLE, playStoreAuthSource = PlayStoreAuthSource.GOOGLE, aasToken = "aas-token" aasToken = "", oauthToken = "oauth-token", ) val googleLoginManager = mockk<GoogleLoginManager>() val microgLoginManager = mockk<MicrogLoginManager>() val anonymousLoginManager = mockk<AnonymousLoginManager>() val aasTokenConverter = mockk<OauthToAasTokenConverter>() val aasTokenConverter = mock<OauthToAasTokenConverter>() val userProfileFetcher = mockk<UserProfileFetcher>() val authData = AuthData(email = "user@gmail.com") val profile = UserProfile(name = "Test User", email = authData.email) whenever(aasTokenConverter.convert(any(), any())).thenReturn(ResultSupreme.Success("fresh-aas-token")) coEvery { googleLoginManager.login() } returns authData coEvery { userProfileFetcher.fetch(authData) } returns profile Loading @@ -176,10 +182,131 @@ class PlayStoreAuthenticatorTest { assertThat(authObject.result.data?.email).isEqualTo(authData.email) assertThat(authObject.result.data?.userProfile).isEqualTo(profile) assertThat(authObject.result.data?.locale).isEqualTo(context.resources.configuration.locales[0]) mockitoVerify(aasTokenConverter).convert(any(), any()) coVerify(exactly = 1) { googleLoginManager.login() } coVerify(exactly = 1) { userProfileFetcher.fetch(authData) } } @Test fun login_refreshesAasTokenViaConversionOnGoogleLogin() = runTest { val context = applicationContext() val sessionRepository = FakeSessionRepository( initialUser = User.GOOGLE, playStoreAuthSource = PlayStoreAuthSource.GOOGLE, aasToken = "", oauthToken = "oauth-token", ) val googleLoginManager = mockk<GoogleLoginManager>() val aasTokenConverter = mock<OauthToAasTokenConverter>() val userProfileFetcher = mockk<UserProfileFetcher>() val authData = AuthData(email = "user@gmail.com") whenever(aasTokenConverter.convert(any(), any())).thenReturn(ResultSupreme.Success("fresh-aas-token")) coEvery { googleLoginManager.login() } returns authData coEvery { userProfileFetcher.fetch(any()) } returns null val authenticator = PlayStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, appPreferencesRepository = FakeAppPreferencesRepository(), authDataCache = AuthDataCache(sessionRepository, json), googleLoginManager = googleLoginManager, microgLoginManager = mockk(), anonymousLoginManager = mockk(), aasTokenConverter = aasTokenConverter, userProfileFetcher = userProfileFetcher ) authenticator.login() mockitoVerify(aasTokenConverter).convert(any(), any()) coVerify(exactly = 1) { googleLoginManager.login() } assertThat(sessionRepository.awaitAasToken()).isEqualTo("fresh-aas-token") } @Test fun login_usesStoredAasTokenWithoutConversionWhenAvailable() = runTest { val context = applicationContext() val sessionRepository = FakeSessionRepository( initialUser = User.GOOGLE, playStoreAuthSource = PlayStoreAuthSource.GOOGLE, aasToken = "stored-aas-token", oauthToken = "expired-oauth-token", ) val googleLoginManager = mockk<GoogleLoginManager>() val aasTokenConverter = mock<OauthToAasTokenConverter>() val userProfileFetcher = mockk<UserProfileFetcher>() val authData = AuthData(email = "user@gmail.com") whenever(aasTokenConverter.convert(any(), any())).thenReturn(ResultSupreme.Error("conversion failed")) coEvery { googleLoginManager.login() } returns authData coEvery { userProfileFetcher.fetch(any()) } returns null val authenticator = PlayStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, appPreferencesRepository = FakeAppPreferencesRepository(), authDataCache = AuthDataCache(sessionRepository, json), googleLoginManager = googleLoginManager, microgLoginManager = mockk(), anonymousLoginManager = mockk(), aasTokenConverter = aasTokenConverter, userProfileFetcher = userProfileFetcher ) val result = authenticator.login() val authObject = result.authObject as AuthObject.GPlayAuth assertThat(authObject.result.data?.email).isEqualTo(authData.email) mockitoVerify(aasTokenConverter, org.mockito.kotlin.never()).convert(any(), any()) coVerify(exactly = 1) { googleLoginManager.login() } // AAS token in storage must not be overwritten when conversion failed assertThat(sessionRepository.awaitAasToken()).isEqualTo("stored-aas-token") } @Test fun login_fallsBackToOauthTokenWhenConversionFailsAndNoStoredAasToken() = runTest { val context = applicationContext() val sessionRepository = FakeSessionRepository( initialUser = User.GOOGLE, playStoreAuthSource = PlayStoreAuthSource.GOOGLE, aasToken = "", oauthToken = "oauth-token", ) val googleLoginManager = mockk<GoogleLoginManager>() val aasTokenConverter = mock<OauthToAasTokenConverter>() val userProfileFetcher = mockk<UserProfileFetcher>() val authData = AuthData(email = "user@gmail.com") whenever(aasTokenConverter.convert(any(), any())).thenReturn(ResultSupreme.Error("conversion failed")) coEvery { googleLoginManager.loginWithOauthToken("oauth-token") } returns authData coEvery { userProfileFetcher.fetch(any()) } returns null val authenticator = PlayStoreAuthenticator( context = context, sessionRepository = sessionRepository, playStoreAuthStore = sessionRepository, appPreferencesRepository = FakeAppPreferencesRepository(), authDataCache = AuthDataCache(sessionRepository, json), googleLoginManager = googleLoginManager, microgLoginManager = mockk(), anonymousLoginManager = mockk(), aasTokenConverter = aasTokenConverter, userProfileFetcher = userProfileFetcher ) val result = authenticator.login() val authObject = result.authObject as AuthObject.GPlayAuth assertThat(authObject.result.data?.email).isEqualTo(authData.email) mockitoVerify(aasTokenConverter).convert(any(), any()) coVerify(exactly = 1) { googleLoginManager.loginWithOauthToken("oauth-token") } coVerify(exactly = 0) { googleLoginManager.login() } assertThat(sessionRepository.awaitAasToken()).isEmpty() } private class FakeSessionRepository( initialUser: User, currentAuthData: AuthData? = null, Loading