commit bdf182dee332208b509bb7c9115cc4ff811333ec parent b3b5d4ab09d0073a31fc517d599141f9b5776a89 Author: mcarare <48995920+mcarare@users.noreply.github.com> Date: Fri, 12 Dec 2025 13:01:14 +0000 Bug 2002504 - Refactor GeckoCreditCardsAddressesStorageDelegate to use CoroutineDispatcher. r=android-reviewers,giorga This patch modifies `GeckoCreditCardsAddressesStorageDelegate` to accept a `CoroutineDispatcher` instead of a `CoroutineScope`. It updates the implementation to use `withContext` with the provided dispatcher. Additionally, it refactors `GeckoCreditCardsAddressesStorageDelegateTest` to utilize `StandardTestDispatcher` and `runTest`, removing the usage of `MainCoroutineRule`. Differential Revision: https://phabricator.services.mozilla.com/D274273 Diffstat:
2 files changed, 21 insertions(+), 26 deletions(-)
diff --git a/mobile/android/android-components/components/service/sync-autofill/src/main/java/mozilla/components/service/sync/autofill/GeckoCreditCardsAddressesStorageDelegate.kt b/mobile/android/android-components/components/service/sync-autofill/src/main/java/mozilla/components/service/sync/autofill/GeckoCreditCardsAddressesStorageDelegate.kt @@ -4,9 +4,8 @@ package mozilla.components.service.sync.autofill -import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import mozilla.components.concept.storage.Address import mozilla.components.concept.storage.CreditCard @@ -24,14 +23,14 @@ import mozilla.components.support.ktx.kotlin.last4Digits * [CreditCardsAddressesStorageDelegate] implementation. * * @param storage The [CreditCardsAddressesStorage] used for looking up addresses and credit cards to autofill. - * @param scope [CoroutineScope] for long running operations. Defaults to using the [Dispatchers.IO]. + * @param dispatcher [CoroutineDispatcher] for long running operations. Defaults to using the [Dispatchers.IO]. * @param isCreditCardAutofillEnabled callback allowing to limit [storage] operations if autofill is disabled. * @param validationDelegate The [DefaultCreditCardValidationDelegate] used to check if a credit card * can be saved in [storage] and returns information about why it can or cannot */ class GeckoCreditCardsAddressesStorageDelegate( private val storage: Lazy<CreditCardsAddressesStorage>, - private val scope: CoroutineScope = CoroutineScope(Dispatchers.IO), + private val dispatcher: CoroutineDispatcher = Dispatchers.IO, private val validationDelegate: DefaultCreditCardValidationDelegate = DefaultCreditCardValidationDelegate(storage), private val isCreditCardAutofillEnabled: () -> Boolean = { false }, private val isAddressAutofillEnabled: () -> Boolean = { false }, @@ -50,7 +49,7 @@ class GeckoCreditCardsAddressesStorageDelegate( return crypto.decrypt(key, encryptedCardNumber) } - override suspend fun onAddressesFetch(): List<Address> = withContext(scope.coroutineContext) { + override suspend fun onAddressesFetch(): List<Address> = withContext(dispatcher) { if (!isAddressAutofillEnabled()) { emptyList() } else { @@ -63,7 +62,7 @@ class GeckoCreditCardsAddressesStorageDelegate( } override suspend fun onCreditCardsFetch(): List<CreditCard> = - withContext(scope.coroutineContext) { + withContext(dispatcher) { if (!isCreditCardAutofillEnabled()) { emptyList() } else { @@ -74,7 +73,7 @@ class GeckoCreditCardsAddressesStorageDelegate( override suspend fun onCreditCardSave(creditCard: CreditCardEntry) { if (!creditCard.isValid) return - scope.launch { + withContext(dispatcher) { when (val result = validationDelegate.shouldCreateOrUpdate(creditCard)) { is CreditCardValidationDelegate.Result.CanBeCreated -> { storage.value.addCreditCard( diff --git a/mobile/android/android-components/components/service/sync-autofill/src/test/java/mozilla/components/service/sync/autofill/GeckoCreditCardsAddressesStorageDelegateTest.kt b/mobile/android/android-components/components/service/sync-autofill/src/test/java/mozilla/components/service/sync/autofill/GeckoCreditCardsAddressesStorageDelegateTest.kt @@ -5,6 +5,7 @@ package mozilla.components.service.sync.autofill import androidx.test.ext.junit.runners.AndroidJUnit4 +import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.runTest import mozilla.appservices.RustComponentsInitializer import mozilla.components.concept.storage.Address @@ -19,11 +20,8 @@ import mozilla.components.support.ktx.kotlin.last4Digits import mozilla.components.support.test.any import mozilla.components.support.test.mock import mozilla.components.support.test.robolectric.testContext -import mozilla.components.support.test.rule.MainCoroutineRule -import mozilla.components.support.test.rule.runTestOnMain import org.junit.Assert.assertEquals import org.junit.Before -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.doReturn @@ -35,9 +33,7 @@ import org.mockito.Mockito.verify @RunWith(AndroidJUnit4::class) class GeckoCreditCardsAddressesStorageDelegateTest { - @get:Rule - val coroutinesTestRule = MainCoroutineRule() - private val scope = coroutinesTestRule.scope + private val testDispatcher = StandardTestDispatcher() private lateinit var storage: AutofillCreditCardsAddressesStorage private lateinit var securePrefs: SecureAbove22Preferences @@ -54,12 +50,12 @@ class GeckoCreditCardsAddressesStorageDelegateTest { // forceInsecure is set in the tests because a keystore wouldn't be configured in the test environment. securePrefs = SecureAbove22Preferences(testContext, "autofill", forceInsecure = true) storage = spy(AutofillCreditCardsAddressesStorage(testContext, lazy { securePrefs })) - delegate = GeckoCreditCardsAddressesStorageDelegate(lazy { storage }, scope, validationDelegate) + delegate = GeckoCreditCardsAddressesStorageDelegate(lazy { storage }, testDispatcher, validationDelegate) } @Test fun `GIVEN a newly added credit card WHEN decrypt is called THEN it returns the plain credit card number`() = - runTestOnMain { + runTest(testDispatcher) { val plaintextNumber = CreditCardNumber.Plaintext("4111111111111111") val creditCardFields = NewCreditCardFields( billingName = "Jon Doe", @@ -80,11 +76,11 @@ class GeckoCreditCardsAddressesStorageDelegateTest { @Test fun `GIVEN autofill enabled WHEN onCreditCardsFetch is called THEN it returns all stored cards`() = - runTest { + runTest(testDispatcher) { val storage: AutofillCreditCardsAddressesStorage = mock() val storedCards = listOf<CreditCard>(mock()) doReturn(storedCards).`when`(storage).getAllCreditCards() - delegate = GeckoCreditCardsAddressesStorageDelegate(lazy { storage }, scope, isCreditCardAutofillEnabled = { true }) + delegate = GeckoCreditCardsAddressesStorageDelegate(lazy { storage }, testDispatcher, isCreditCardAutofillEnabled = { true }) val result = delegate.onCreditCardsFetch() @@ -94,11 +90,11 @@ class GeckoCreditCardsAddressesStorageDelegateTest { @Test fun `GIVEN autofill disabled WHEN onCreditCardsFetch is called THEN it returns an empty list of cards`() = - runTest { + runTest(testDispatcher) { val storage: AutofillCreditCardsAddressesStorage = mock() val storedCards = listOf<CreditCard>(mock()) doReturn(storedCards).`when`(storage).getAllCreditCards() - delegate = GeckoCreditCardsAddressesStorageDelegate(lazy { storage }, scope, isCreditCardAutofillEnabled = { false }) + delegate = GeckoCreditCardsAddressesStorageDelegate(lazy { storage }, testDispatcher, isCreditCardAutofillEnabled = { false }) val result = delegate.onCreditCardsFetch() @@ -108,7 +104,7 @@ class GeckoCreditCardsAddressesStorageDelegateTest { @Test fun `GIVEN a new credit card WHEN onCreditCardSave is called THEN it adds a new credit card in storage`() { - runTest { + runTest(testDispatcher) { val billingName = "Jon Doe" val cardNumber = "4111111111111111" val expiryMonth = 12L @@ -142,7 +138,7 @@ class GeckoCreditCardsAddressesStorageDelegateTest { @Test fun `GIVEN an existing credit card WHEN onCreditCardSave is called THEN it updates the existing credit card in storage`() { - runTest { + runTest(testDispatcher) { val billingName = "Jon Doe" val cardNumber = "4111111111111111" val expiryMonth = 12L @@ -189,7 +185,7 @@ class GeckoCreditCardsAddressesStorageDelegateTest { @Test fun `GIVEN an invalid credit card entry WHEN onCreditCardSave is called THEN the request is ignored`() { - runTest { + runTest(testDispatcher) { val billingName = "Jon Doe" val cardNumber = "" val expiryMonth = "" @@ -215,11 +211,11 @@ class GeckoCreditCardsAddressesStorageDelegateTest { @Test fun `GIVEN address autofill is enabled WHEN onAddressesFetch is called THEN it returns all stored addresses`() = - runTest { + runTest(testDispatcher) { val storage: AutofillCreditCardsAddressesStorage = mock() val storedAddresses = listOf<Address>(mock(), mock()) doReturn(storedAddresses).`when`(storage).getAllAddresses() - delegate = GeckoCreditCardsAddressesStorageDelegate(lazy { storage }, scope, isAddressAutofillEnabled = { true }) + delegate = GeckoCreditCardsAddressesStorageDelegate(lazy { storage }, testDispatcher, isAddressAutofillEnabled = { true }) val result = delegate.onAddressesFetch() @@ -229,11 +225,11 @@ class GeckoCreditCardsAddressesStorageDelegateTest { @Test fun `GIVEN address autofill is disabled WHEN onAddressesFetch is called THEN it returns an empty list of addresses`() = - runTest { + runTest(testDispatcher) { val storage: AutofillCreditCardsAddressesStorage = mock() val storedCards = listOf<CreditCard>(mock()) doReturn(storedCards).`when`(storage).getAllCreditCards() - delegate = GeckoCreditCardsAddressesStorageDelegate(lazy { storage }, scope, isAddressAutofillEnabled = { false }) + delegate = GeckoCreditCardsAddressesStorageDelegate(lazy { storage }, testDispatcher, isAddressAutofillEnabled = { false }) val result = delegate.onAddressesFetch()