diff --git a/app/src/main/java/org/mozilla/fenix/settings/logins/controller/SavedLoginsStorageController.kt b/app/src/main/java/org/mozilla/fenix/settings/logins/controller/SavedLoginsStorageController.kt index e04e1418a..754ddb688 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/logins/controller/SavedLoginsStorageController.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/logins/controller/SavedLoginsStorageController.kt @@ -7,6 +7,7 @@ package org.mozilla.fenix.settings.logins.controller import android.util.Log import androidx.navigation.NavController import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Deferred import kotlinx.coroutines.Dispatchers @@ -31,14 +32,15 @@ open class SavedLoginsStorageController( private val passwordsStorage: SyncableLoginsStorage, private val viewLifecycleScope: CoroutineScope, private val navController: NavController, - private val loginsFragmentStore: LoginsFragmentStore + private val loginsFragmentStore: LoginsFragmentStore, + private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO ) { private suspend fun getLogin(loginId: String): Login? = passwordsStorage.get(loginId) fun delete(loginId: String) { var deleteLoginJob: Deferred? = null - val deleteJob = viewLifecycleScope.launch(Dispatchers.IO) { + val deleteJob = viewLifecycleScope.launch(ioDispatcher) { deleteLoginJob = async { passwordsStorage.delete(loginId) } @@ -56,7 +58,7 @@ open class SavedLoginsStorageController( fun save(loginId: String, usernameText: String, passwordText: String) { var saveLoginJob: Deferred? = null - viewLifecycleScope.launch(Dispatchers.IO) { + viewLifecycleScope.launch(ioDispatcher) { saveLoginJob = async { // must retrieve from storage to get the httpsRealm and formActionOrigin val oldLogin = passwordsStorage.get(loginId) @@ -123,7 +125,7 @@ open class SavedLoginsStorageController( fun findPotentialDuplicates(loginId: String) { var deferredLogin: Deferred>? = null // What scope should be used here? - val fetchLoginJob = viewLifecycleScope.launch(Dispatchers.IO) { + val fetchLoginJob = viewLifecycleScope.launch(ioDispatcher) { deferredLogin = async { val login = getLogin(loginId) passwordsStorage.getPotentialDupesIgnoringUsername(login!!) @@ -149,7 +151,7 @@ open class SavedLoginsStorageController( fun fetchLoginDetails(loginId: String) { var deferredLogin: Deferred>? = null - val fetchLoginJob = viewLifecycleScope.launch(Dispatchers.IO) { + val fetchLoginJob = viewLifecycleScope.launch(ioDispatcher) { deferredLogin = async { passwordsStorage.list() } @@ -177,7 +179,7 @@ open class SavedLoginsStorageController( fun handleLoadAndMapLogins() { var deferredLogins: Deferred>? = null - val fetchLoginsJob = viewLifecycleScope.launch(Dispatchers.IO) { + val fetchLoginsJob = viewLifecycleScope.launch(ioDispatcher) { deferredLogins = async { passwordsStorage.list() } diff --git a/app/src/test/java/org/mozilla/fenix/settings/logins/SavedLoginsStorageControllerTest.kt b/app/src/test/java/org/mozilla/fenix/settings/logins/SavedLoginsStorageControllerTest.kt index f9cb599dc..d29acb3ed 100644 --- a/app/src/test/java/org/mozilla/fenix/settings/logins/SavedLoginsStorageControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/settings/logins/SavedLoginsStorageControllerTest.kt @@ -13,9 +13,9 @@ import io.mockk.every import io.mockk.just import io.mockk.mockk import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.TestCoroutineDispatcher import kotlinx.coroutines.test.TestCoroutineScope +import kotlinx.coroutines.test.runBlockingTest import mozilla.components.concept.storage.Login import mozilla.components.service.sync.logins.SyncableLoginsStorage import mozilla.components.support.test.rule.MainCoroutineRule @@ -41,6 +41,7 @@ class SavedLoginsStorageControllerTest { private val navController: NavController = mockk(relaxed = true) private val loginsFragmentStore: LoginsFragmentStore = mockk(relaxed = true) private val scope = TestCoroutineScope() + private val ioDispatcher = TestCoroutineDispatcher() private val loginMock: Login = mockk(relaxed = true) @Before @@ -55,17 +56,19 @@ class SavedLoginsStorageControllerTest { passwordsStorage = passwordsStorage, viewLifecycleScope = scope, navController = navController, - loginsFragmentStore = loginsFragmentStore + loginsFragmentStore = loginsFragmentStore, + ioDispatcher = ioDispatcher ) } @After fun cleanUp() { scope.cleanupTestCoroutines() + ioDispatcher.cleanupTestCoroutines() } @Test - fun `WHEN a login is deleted, THEN navigate back to the previous page`() = runBlocking { + fun `WHEN a login is deleted, THEN navigate back to the previous page`() = scope.runBlockingTest { val loginId = "id" coEvery { passwordsStorage.delete(any()) } returns true controller.delete(loginId) @@ -77,7 +80,7 @@ class SavedLoginsStorageControllerTest { } @Test - fun `WHEN fetching the login list, THEN update the state in the store`() { + fun `WHEN fetching the login list, THEN update the state in the store`() = scope.runBlockingTest { val login = Login( guid = "id", origin = "https://www.test.co.gov.org", @@ -103,7 +106,7 @@ class SavedLoginsStorageControllerTest { } @Test - fun `WHEN saving an update to an item, THEN navigate to login detail view`() { + fun `WHEN saving an update to an item, THEN navigate to login detail view`() = scope.runBlockingTest { val oldLogin = Login( guid = "id", origin = "https://www.test.co.gov.org", @@ -147,7 +150,7 @@ class SavedLoginsStorageControllerTest { } @Test - fun `WHEN finding login dupes, THEN update duplicates in the store`() { + fun `WHEN finding login dupes, THEN update duplicates in the store`() = scope.runBlockingTest { val login = Login( guid = "id", origin = "https://www.test.co.gov.org",