From 9df1f318103ba87d2c735124862781d4debec21f Mon Sep 17 00:00:00 2001 From: Jonathan Klee Date: Wed, 1 Apr 2026 14:27:38 +0200 Subject: [PATCH 1/3] refactor: remove useless InvalidAuthEvent Reauth is done on-demand at the low-level app details implementation --- .../foundation/e/apps/data/event/AppEvent.kt | 1 - .../data/playstore/utils/GPlayHttpClient.kt | 7 ------ .../foundation/e/apps/ui/LoginViewModel.kt | 25 ------------------- .../java/foundation/e/apps/ui/MainActivity.kt | 25 ------------------- .../ui/application/ApplicationViewModel.kt | 6 ----- .../e/apps/gplay/GPlayHttpClientTest.kt | 13 +++------- .../e/apps/login/LoginViewModelTest.kt | 24 ------------------ 7 files changed, 4 insertions(+), 97 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/data/event/AppEvent.kt b/app/src/main/java/foundation/e/apps/data/event/AppEvent.kt index b12a12ea8..0bc916073 100644 --- a/app/src/main/java/foundation/e/apps/data/event/AppEvent.kt +++ b/app/src/main/java/foundation/e/apps/data/event/AppEvent.kt @@ -30,7 +30,6 @@ sealed class AppEvent(val data: Any) { class SignatureMissMatchError(packageName: String) : AppEvent(packageName) class UpdateEvent(result: ResultSupreme.WorkError) : AppEvent(result) - class InvalidAuthEvent(authName: String) : AppEvent(authName) class ErrorMessageEvent(stringResourceId: Int) : AppEvent(stringResourceId) class ErrorMessageDialogEvent(stringResourceId: Int) : AppEvent(stringResourceId) class AppPurchaseEvent(appInstall: AppInstall) : AppEvent(appInstall) diff --git a/app/src/main/java/foundation/e/apps/data/playstore/utils/GPlayHttpClient.kt b/app/src/main/java/foundation/e/apps/data/playstore/utils/GPlayHttpClient.kt index caad7213f..bf54b65f7 100644 --- a/app/src/main/java/foundation/e/apps/data/playstore/utils/GPlayHttpClient.kt +++ b/app/src/main/java/foundation/e/apps/data/playstore/utils/GPlayHttpClient.kt @@ -23,7 +23,6 @@ import com.aurora.gplayapi.data.models.PlayResponse import com.aurora.gplayapi.network.IHttpClient import foundation.e.apps.data.event.AppEvent import foundation.e.apps.data.event.EventBus -import foundation.e.apps.data.login.core.AuthObject import foundation.e.apps.data.system.SystemInfoProvider import kotlinx.coroutines.MainScope import kotlinx.coroutines.asContextElement @@ -219,12 +218,6 @@ class GPlayHttpClient @Inject constructor( val responseBytes = response.body?.bytes() ?: byteArrayOf() when (code) { - STATUS_CODE_UNAUTHORIZED -> MainScope().launch { - EventBus.invokeEvent( - AppEvent.InvalidAuthEvent(AuthObject.GPlayAuth::class.java.simpleName) - ) - } - STATUS_CODE_TOO_MANY_REQUESTS -> MainScope().launch { if (url.toString().contains(SEARCH_SUGGEST)) { return@launch diff --git a/app/src/main/java/foundation/e/apps/ui/LoginViewModel.kt b/app/src/main/java/foundation/e/apps/ui/LoginViewModel.kt index 3d44f6cdc..add8a202a 100644 --- a/app/src/main/java/foundation/e/apps/ui/LoginViewModel.kt +++ b/app/src/main/java/foundation/e/apps/ui/LoginViewModel.kt @@ -36,7 +36,6 @@ import foundation.e.apps.login.MicrogAccountFetchResult import foundation.e.apps.login.MicrogAccountFetcher import foundation.e.apps.login.StoreAuthCoordinator import kotlinx.coroutines.launch -import okhttp3.Cache import javax.inject.Inject /** @@ -53,7 +52,6 @@ class LoginViewModel @Inject constructor( private val googleLoginUseCase: GoogleLoginUseCase, private val noGoogleLoginUseCase: NoGoogleLoginUseCase, private val logoutUseCase: LogoutUseCase, - private val cache: Cache, @ApplicationContext private val context: Context ) : ViewModel() { @@ -163,29 +161,6 @@ class LoginViewModel @Inject constructor( } } - /** - * Once an AuthObject is marked as invalid, it will be refreshed - * automatically by LoadingViewModel. - * If GPlay auth is invalid, LoadingViewModel.onLoadData has a retry block, - * this block will clear existing GPlay AuthData and freshly start the login flow. - */ - fun markInvalidAuthObject(authObjectName: String) { - val authObjectsLocal = authObjects.value?.toMutableList() - val invalidObject = authObjectsLocal?.find { it::class.java.simpleName == authObjectName } - - val replacedObject = invalidObject?.createInvalidAuthObject() - - authObjectsLocal?.apply { - if (invalidObject != null && replacedObject != null) { - remove(invalidObject) - add(replacedObject) - } - } - - authObjects.postValue(authObjectsLocal) - cache.evictAll() - } - /** * Clears all saved data and logs out the user to the sign in screen. */ diff --git a/app/src/main/java/foundation/e/apps/ui/MainActivity.kt b/app/src/main/java/foundation/e/apps/ui/MainActivity.kt index e972acd6d..f6e6472a3 100644 --- a/app/src/main/java/foundation/e/apps/ui/MainActivity.kt +++ b/app/src/main/java/foundation/e/apps/ui/MainActivity.kt @@ -23,7 +23,6 @@ import android.os.Build.VERSION import android.os.Build.VERSION_CODES import android.os.Bundle import android.view.View -import android.widget.Toast import android.window.OnBackInvokedDispatcher.PRIORITY_DEFAULT import androidx.activity.OnBackPressedCallback import androidx.activity.result.contract.ActivityResultContracts @@ -261,10 +260,6 @@ class MainActivity : AppCompatActivity() { private fun observeEvents() { lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { - launch { - observeInvalidAuth() - } - launch { observeAppUnavailable() } @@ -520,19 +515,6 @@ class MainActivity : AppCompatActivity() { } } - private suspend fun observeInvalidAuth() { - EventBus.events.filter { appEvent -> - appEvent is AppEvent.InvalidAuthEvent - }.distinctUntilChanged { old, new -> - ((old.data is String) && (new.data is String) && old.data == new.data) - }.collectLatest { - if (BuildConfig.DEBUG) { - Toast.makeText(this, "Refreshing token...", Toast.LENGTH_SHORT).show() - } - validatedAuthObject(it) - } - } - private suspend fun observeAppUnavailable() { EventBus.events.filterIsInstance() .collectLatest { event -> @@ -542,13 +524,6 @@ class MainActivity : AppCompatActivity() { } } - private fun validatedAuthObject(appEvent: AppEvent) { - val data = appEvent.data as String - if (data.isNotBlank()) { - loginViewModel.markInvalidAuthObject(data) - } - } - private suspend fun observeTooManyRequests() { EventBus.events.filter { appEvent -> appEvent is AppEvent.TooManyRequests diff --git a/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt b/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt index de36a579a..090e24edc 100644 --- a/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt +++ b/app/src/main/java/foundation/e/apps/ui/application/ApplicationViewModel.kt @@ -148,12 +148,6 @@ class ApplicationViewModel @Inject constructor( updateShareVisibilityState(app.shareUri.toString()) updateAppContentRatingState(packageName, app.contentRating) - - if (status != ResultStatus.OK) { - EventBus.invokeEvent( - AppEvent.InvalidAuthEvent(AuthObject.GPlayAuth::class.java.simpleName) - ) - } } catch (e: InternalException.AppNotFound) { _errorMessageLiveData.postValue(R.string.app_not_found) scheduleAutoRedirect() diff --git a/app/src/test/java/foundation/e/apps/gplay/GPlayHttpClientTest.kt b/app/src/test/java/foundation/e/apps/gplay/GPlayHttpClientTest.kt index a846fe545..93b866211 100644 --- a/app/src/test/java/foundation/e/apps/gplay/GPlayHttpClientTest.kt +++ b/app/src/test/java/foundation/e/apps/gplay/GPlayHttpClientTest.kt @@ -19,14 +19,13 @@ package foundation.e.apps.gplay import com.aurora.gplayapi.data.models.PlayResponse -import foundation.e.apps.data.login.core.AuthObject +import foundation.e.apps.data.event.AppEvent +import foundation.e.apps.data.event.EventBus import foundation.e.apps.data.playstore.utils.GPlayHttpClient import foundation.e.apps.data.playstore.utils.GplayHttpRequestException +import foundation.e.apps.data.system.SystemInfoProvider import foundation.e.apps.util.FakeCall import foundation.e.apps.util.MainCoroutineRule -import foundation.e.apps.data.system.SystemInfoProvider -import foundation.e.apps.data.event.AppEvent -import foundation.e.apps.data.event.EventBus import io.mockk.every import io.mockk.mockkObject import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -167,12 +166,8 @@ class GPlayHttpClientTest { Mockito.`when`(okHttpClient.newCall(any())).thenReturn(call) } - private suspend fun assertResponse(response: PlayResponse, statusValue: Int = 401) { + private fun assertResponse(response: PlayResponse, statusValue: Int = 401) { assertFalse(response.isSuccessful) assertTrue(response.code == statusValue) - val event = EventBus.events.first() - assertTrue(event is AppEvent.InvalidAuthEvent) - assertTrue(event.data is String) - assertTrue(event.data == AuthObject.GPlayAuth::class.java.simpleName) } } diff --git a/app/src/test/java/foundation/e/apps/login/LoginViewModelTest.kt b/app/src/test/java/foundation/e/apps/login/LoginViewModelTest.kt index 0761fd5d9..33dc2dcf7 100644 --- a/app/src/test/java/foundation/e/apps/login/LoginViewModelTest.kt +++ b/app/src/test/java/foundation/e/apps/login/LoginViewModelTest.kt @@ -21,10 +21,7 @@ package foundation.e.apps.login import android.content.Context import android.content.Intent import androidx.arch.core.executor.testing.InstantTaskExecutorRule -import com.aurora.gplayapi.data.models.AuthData import foundation.e.apps.R -import foundation.e.apps.data.ResultSupreme -import foundation.e.apps.data.login.core.AuthObject import foundation.e.apps.domain.login.AnonymousLoginUseCase import foundation.e.apps.domain.login.GoogleLoginUseCase import foundation.e.apps.domain.login.MicrogLoginUseCase @@ -38,7 +35,6 @@ import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.setMain -import okhttp3.Cache import org.junit.After import org.junit.Before import org.junit.Rule @@ -68,8 +64,6 @@ class LoginViewModelTest { @Mock private lateinit var logoutUseCase: LogoutUseCase @Mock - private lateinit var cache: Cache - @Mock private lateinit var context: Context private lateinit var loginViewModel: LoginViewModel @@ -90,7 +84,6 @@ class LoginViewModelTest { googleLoginUseCase, noGoogleLoginUseCase, logoutUseCase, - cache, context ) whenever(context.getString(R.string.sign_in_microg_login_failed)).thenReturn("fallback") @@ -101,23 +94,6 @@ class LoginViewModelTest { Dispatchers.resetMain() } - @Test - fun testMarkInvalidAuthObject() { - val authObjectList = mutableListOf( - AuthObject.GPlayAuth( - ResultSupreme.Success(AuthData("aa@aa.com", "feri4234")), User.GOOGLE - ) - ) - loginViewModel.authObjects.value = authObjectList - - loginViewModel.markInvalidAuthObject(AuthObject.GPlayAuth::class.java.simpleName) - val currentAuthObjectList = loginViewModel.authObjects.value as List - val invalidGplayAuth = currentAuthObjectList.find { it is AuthObject.GPlayAuth } - - assert(invalidGplayAuth != null) - assert((invalidGplayAuth as AuthObject.GPlayAuth).result.isUnknownError()) - } - @Test fun `initialMicrogLogin saves user and starts flow on success`() = runTest { val result = MicrogAccountFetchResult.Success("user@gmail.com", "token") -- GitLab From d0d1e519fecec798b60202055b6e631e4bfce6ea Mon Sep 17 00:00:00 2001 From: Jonathan Klee Date: Wed, 1 Apr 2026 15:52:31 +0200 Subject: [PATCH 2/3] tests: add new unit tests for token refresh --- .../data/playstore/PlayStoreRepositoryTest.kt | 215 ++++++++++++++++++ 1 file changed, 215 insertions(+) diff --git a/app/src/test/java/foundation/e/apps/data/playstore/PlayStoreRepositoryTest.kt b/app/src/test/java/foundation/e/apps/data/playstore/PlayStoreRepositoryTest.kt index 84d0b5ec8..eacea937c 100644 --- a/app/src/test/java/foundation/e/apps/data/playstore/PlayStoreRepositoryTest.kt +++ b/app/src/test/java/foundation/e/apps/data/playstore/PlayStoreRepositoryTest.kt @@ -304,6 +304,221 @@ class PlayStoreRepositoryTest { } } + @Test + fun `getAppDetails does not retry when token refresh fails`() = runTest { + val authData = AuthData(email = "user@gmail.com") + val playStoreAuthManager = mock() + + repository = createRepository(playStoreAuthManager) + + whenever(playStoreAuthManager.getGPlayAuthOrThrow()).thenReturn(authData) + whenever(playStoreAuthManager.getValidatedAuthData()) + .thenReturn(ResultSupreme.Error("auth refresh failed")) + every { + anyConstructed().getAppByPackageName("pkg.test") + } throws GplayHttpRequestException(401, "unauthorized") + + kotlin.test.assertFailsWith { + repository.getAppDetails("pkg.test") + } + + mockitoVerify(playStoreAuthManager).getValidatedAuthData() + verify(exactly = 1) { anyConstructed().getAppByPackageName("pkg.test") } + } + + @Test + fun `getAppDetails does not retry when token refresh returns null auth data`() = runTest { + val authData = AuthData(email = "user@gmail.com") + val playStoreAuthManager = mock() + + repository = createRepository(playStoreAuthManager) + + whenever(playStoreAuthManager.getGPlayAuthOrThrow()).thenReturn(authData) + whenever(playStoreAuthManager.getValidatedAuthData()) + .thenReturn(ResultSupreme.Success(null)) + every { + anyConstructed().getAppByPackageName("pkg.test") + } throws GplayHttpRequestException(401, "unauthorized") + + kotlin.test.assertFailsWith { + repository.getAppDetails("pkg.test") + } + + mockitoVerify(playStoreAuthManager).getValidatedAuthData() + verify(exactly = 1) { anyConstructed().getAppByPackageName("pkg.test") } + } + + @Test + fun `getAppDetails does not retry on non-auth errors`() = runTest { + val authData = AuthData(email = "user@gmail.com") + val playStoreAuthManager = mock() + + repository = createRepository(playStoreAuthManager) + + whenever(playStoreAuthManager.getGPlayAuthOrThrow()).thenReturn(authData) + every { + anyConstructed().getAppByPackageName("pkg.test") + } throws GplayHttpRequestException(500, "server error") + + kotlin.test.assertFailsWith { + repository.getAppDetails("pkg.test") + } + + mockitoVerify(playStoreAuthManager, org.mockito.kotlin.never()).getValidatedAuthData() + verify(exactly = 1) { anyConstructed().getAppByPackageName("pkg.test") } + } + + @Test + fun `getAppDetails throws when version code is still zero after token refresh`() = runTest { + val authData = AuthData(email = "user@gmail.com") + val staleApp = App(packageName = "pkg.test", versionCode = 0) + val playStoreAuthManager = mock() + val storeAuthCoordinator = mock() + val playStoreAuthStore = createPlayStoreAuthStore(authData) + + repository = createRepository(playStoreAuthManager, playStoreAuthStore, storeAuthCoordinator) + + whenever(playStoreAuthManager.getGPlayAuthOrThrow()).thenReturn(authData) + whenever(storeAuthCoordinator.fetchAuthObjects(listOf(StoreType.PLAY_STORE))) + .thenReturn(emptyList()) + every { + anyConstructed().getAppByPackageName("pkg.test") + } returns staleApp + + kotlin.test.assertFailsWith { + repository.getAppDetails("pkg.test") + } + + mockitoVerify(storeAuthCoordinator).fetchAuthObjects(listOf(StoreType.PLAY_STORE)) + } + + @Test + fun `getAppsDetails retries after 401`() = runTest { + val authData = AuthData(email = "user@gmail.com") + val apps = listOf(App(packageName = "pkg.test", versionCode = 2)) + val playStoreAuthManager = mock() + + repository = createRepository(playStoreAuthManager) + + whenever(playStoreAuthManager.getGPlayAuthOrThrow()).thenReturn(authData) + whenever(playStoreAuthManager.getValidatedAuthData()).thenReturn(ResultSupreme.Success(authData)) + every { + anyConstructed().getAppByPackageName(listOf("pkg.test")) + } throws GplayHttpRequestException(401, "unauthorized") andThen apps + + val result = repository.getAppsDetails(listOf("pkg.test")) + + assertThat(result).hasSize(1) + mockitoVerify(playStoreAuthManager).getValidatedAuthData() + verify(exactly = 2) { + anyConstructed().getAppByPackageName(listOf("pkg.test")) + } + } + + @Test + fun `getAppsDetails does not retry when token refresh fails`() = runTest { + val authData = AuthData(email = "user@gmail.com") + val playStoreAuthManager = mock() + + repository = createRepository(playStoreAuthManager) + + whenever(playStoreAuthManager.getGPlayAuthOrThrow()).thenReturn(authData) + whenever(playStoreAuthManager.getValidatedAuthData()) + .thenReturn(ResultSupreme.Error("auth refresh failed")) + every { + anyConstructed().getAppByPackageName(listOf("pkg.test")) + } throws GplayHttpRequestException(401, "unauthorized") + + kotlin.test.assertFailsWith { + repository.getAppsDetails(listOf("pkg.test")) + } + + mockitoVerify(playStoreAuthManager).getValidatedAuthData() + verify(exactly = 1) { + anyConstructed().getAppByPackageName(listOf("pkg.test")) + } + } + + @Test + fun `getAppsDetails does not refresh auth for non-anonymous user when all version codes are zero`() = runTest { + val authData = AuthData(email = "user@gmail.com", isAnonymous = false) + val staleApps = listOf(App(packageName = "pkg.test", versionCode = 0)) + val playStoreAuthManager = mock() + val storeAuthCoordinator = mock() + val playStoreAuthStore = createPlayStoreAuthStore(authData) + + repository = createRepository(playStoreAuthManager, playStoreAuthStore, storeAuthCoordinator) + + whenever(playStoreAuthManager.getGPlayAuthOrThrow()).thenReturn(authData) + every { + anyConstructed().getAppByPackageName(listOf("pkg.test")) + } returns staleApps + + val result = repository.getAppsDetails(listOf("pkg.test")) + + assertThat(result).isEmpty() + mockitoVerify(storeAuthCoordinator, org.mockito.kotlin.never()) + .fetchAuthObjects(org.mockito.kotlin.any()) + verify(exactly = 1) { + anyConstructed().getAppByPackageName(listOf("pkg.test")) + } + } + + @Test + fun `getAppsDetails does not refresh auth when not all version codes are zero`() = runTest { + val authData = AuthData(email = "anon@example.com", isAnonymous = true) + val apps = listOf( + App(packageName = "pkg.a", versionCode = 0), + App(packageName = "pkg.b", versionCode = 5) + ) + val playStoreAuthManager = mock() + val storeAuthCoordinator = mock() + val playStoreAuthStore = createPlayStoreAuthStore(authData) + + repository = createRepository(playStoreAuthManager, playStoreAuthStore, storeAuthCoordinator) + + whenever(playStoreAuthManager.getGPlayAuthOrThrow()).thenReturn(authData) + every { + anyConstructed().getAppByPackageName(listOf("pkg.a", "pkg.b")) + } returns apps + + val result = repository.getAppsDetails(listOf("pkg.a", "pkg.b")) + + assertThat(result).hasSize(1) + assertThat(result.first().package_name).isEqualTo("pkg.b") + mockitoVerify(storeAuthCoordinator, org.mockito.kotlin.never()) + .fetchAuthObjects(org.mockito.kotlin.any()) + verify(exactly = 1) { + anyConstructed().getAppByPackageName(listOf("pkg.a", "pkg.b")) + } + } + + @Test + fun `getAppsDetails returns empty result when version codes still zero after token refresh`() = runTest { + val authData = AuthData(email = "anon@example.com", isAnonymous = true) + val staleApps = listOf(App(packageName = "pkg.test", versionCode = 0)) + val playStoreAuthManager = mock() + val storeAuthCoordinator = mock() + val playStoreAuthStore = createPlayStoreAuthStore(authData) + + repository = createRepository(playStoreAuthManager, playStoreAuthStore, storeAuthCoordinator) + + whenever(playStoreAuthManager.getGPlayAuthOrThrow()).thenReturn(authData) + whenever(storeAuthCoordinator.fetchAuthObjects(listOf(StoreType.PLAY_STORE))) + .thenReturn(emptyList()) + every { + anyConstructed().getAppByPackageName(listOf("pkg.test")) + } returns staleApps + + val result = repository.getAppsDetails(listOf("pkg.test")) + + assertThat(result).isEmpty() + mockitoVerify(storeAuthCoordinator).fetchAuthObjects(listOf(StoreType.PLAY_STORE)) + verify(exactly = 2) { + anyConstructed().getAppByPackageName(listOf("pkg.test")) + } + } + @Test fun `getAppsDetails filters invalid apps`() = runTest { val authData = AuthData(email = "user@gmail.com") -- GitLab From 2ef7e1d3bf44397e4d0093eff9dadd2f9185b3ee Mon Sep 17 00:00:00 2001 From: Jonathan Klee Date: Wed, 1 Apr 2026 17:57:18 +0200 Subject: [PATCH 3/3] refactor: remove useless isAnonymousUser() call --- .../data/playstore/PlayStoreRepository.kt | 2 +- .../data/playstore/PlayStoreRepositoryTest.kt | 33 ++++++++++++++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/data/playstore/PlayStoreRepository.kt b/app/src/main/java/foundation/e/apps/data/playstore/PlayStoreRepository.kt index 1c4e777d8..c262c2cd8 100644 --- a/app/src/main/java/foundation/e/apps/data/playstore/PlayStoreRepository.kt +++ b/app/src/main/java/foundation/e/apps/data/playstore/PlayStoreRepository.kt @@ -176,7 +176,7 @@ class PlayStoreRepository @Inject constructor( getAppDetailsHelper().getAppByPackageName(packageNames) } - if (!isEmulator() && appDetails.all { it.versionCode == 0L } && isAnonymousUser()) { + if (!isEmulator() && appDetails.all { it.versionCode == 0L }) { // Google Play returns limited result ( i.e. version code being 0) with a stale token, // so we need to refresh authentication to get a new token. Timber.i("Version code is 0.") diff --git a/app/src/test/java/foundation/e/apps/data/playstore/PlayStoreRepositoryTest.kt b/app/src/test/java/foundation/e/apps/data/playstore/PlayStoreRepositoryTest.kt index eacea937c..44e9f2610 100644 --- a/app/src/test/java/foundation/e/apps/data/playstore/PlayStoreRepositoryTest.kt +++ b/app/src/test/java/foundation/e/apps/data/playstore/PlayStoreRepositoryTest.kt @@ -440,15 +440,46 @@ class PlayStoreRepositoryTest { } @Test - fun `getAppsDetails does not refresh auth for non-anonymous user when all version codes are zero`() = runTest { + fun `getAppsDetails refreshes auth for non-anonymous user when all version codes are zero`() = runTest { val authData = AuthData(email = "user@gmail.com", isAnonymous = false) val staleApps = listOf(App(packageName = "pkg.test", versionCode = 0)) + val refreshedApps = listOf(App(packageName = "pkg.test", versionCode = 5)) val playStoreAuthManager = mock() val storeAuthCoordinator = mock() val playStoreAuthStore = createPlayStoreAuthStore(authData) repository = createRepository(playStoreAuthManager, playStoreAuthStore, storeAuthCoordinator) + whenever(playStoreAuthManager.getGPlayAuthOrThrow()).thenReturn(authData) + whenever(storeAuthCoordinator.fetchAuthObjects(listOf(StoreType.PLAY_STORE))) + .thenReturn(emptyList()) + every { + anyConstructed().getAppByPackageName(listOf("pkg.test")) + } returns staleApps andThen refreshedApps + + val result = repository.getAppsDetails(listOf("pkg.test")) + + assertThat(result).hasSize(1) + assertThat(result.first().package_name).isEqualTo("pkg.test") + mockitoVerify(storeAuthCoordinator).fetchAuthObjects(listOf(StoreType.PLAY_STORE)) + verify(exactly = 2) { + anyConstructed().getAppByPackageName(listOf("pkg.test")) + } + } + + @Test + fun `getAppsDetails does not refresh auth on emulator when all version codes are zero`() = runTest { + val authData = AuthData(email = "user@gmail.com", isAnonymous = false) + val staleApps = listOf(App(packageName = "pkg.test", versionCode = 0)) + val playStoreAuthManager = mock() + val storeAuthCoordinator = mock() + + every { SystemInfoProvider.getSystemProperty("ro.boot.qemu") } returns "1" + repository = createRepository( + playStoreAuthManager = playStoreAuthManager, + storeAuthCoordinator = storeAuthCoordinator + ) + whenever(playStoreAuthManager.getGPlayAuthOrThrow()).thenReturn(authData) every { anyConstructed().getAppByPackageName(listOf("pkg.test")) -- GitLab