android / codelab-android-datastore

Apache License 2.0
227 stars 105 forks source link

"multiple instances" error when removing value during unit testing #48

Open ziglee opened 2 years ago

ziglee commented 2 years ago

When trying to remove some key from datastore-preferences during unittest I'm getting an error about "multiple instances" of the datastore. The following code reproduces the problem:

` import android.content.Context import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.PreferenceDataStoreFactory import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.preferencesDataStoreFile import androidx.test.core.app.ApplicationProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.SupervisorJob import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner

@ExperimentalCoroutinesApi @RunWith(RobolectricTestRunner::class) class TestDataStore {

companion object {
    private val DATASTORE_KEY = stringPreferencesKey("DATASTORE_KEY")
}

@get:Rule
val testCoroutineRule = TestCoroutineRule()

private lateinit var dataStore: DataStore<Preferences>

@Before
fun setup() {
    val context = ApplicationProvider.getApplicationContext<Context>()
    dataStore =
        PreferenceDataStoreFactory.create(
            scope = CoroutineScope(testCoroutineRule.testCoroutineDispatcher + SupervisorJob())
        ) {
            context.preferencesDataStoreFile("preferences")
        }
}

@Test
fun test() {
    testCoroutineRule.runBlockingTest {
        dataStore.edit { it[DATASTORE_KEY] = "team" }

        dataStore.edit { it.remove(DATASTORE_KEY) }
    }
}

} `

The stacktrace:

Unable to rename C:\Users\Cassio\AppData\Local\Temp\robolectric-Method_test8095984772844777287\com.nautiluslog.data.test-dataDir\files\datastore\preferences.preferences_pb.tmp.This likely means that there are multiple instances of DataStore for this file. Ensure that you are only creating a single instance of datastore for this file. java.io.IOException: Unable to rename C:\Users\Cassio\AppData\Local\Temp\robolectric-Method_test8095984772844777287\com.nautiluslog.data.test-dataDir\files\datastore\preferences.preferences_pb.tmp.This likely means that there are multiple instances of DataStore for this file. Ensure that you are only creating a single instance of datastore for this file. at androidx.datastore.core.SingleProcessDataStore.writeData$datastore_core(SingleProcessDataStore.kt:433) at androidx.datastore.core.SingleProcessDataStore.transformAndWrite(SingleProcessDataStore.kt:410) at androidx.datastore.core.SingleProcessDataStore.handleUpdate(SingleProcessDataStore.kt:276) at androidx.datastore.core.SingleProcessDataStore.access$handleUpdate(SingleProcessDataStore.kt:76) at androidx.datastore.core.SingleProcessDataStore$actor$3.invokeSuspend(SingleProcessDataStore.kt:242) at androidx.datastore.core.SingleProcessDataStore$actor$3.invoke(SingleProcessDataStore.kt) at androidx.datastore.core.SingleProcessDataStore$actor$3.invoke(SingleProcessDataStore.kt) at androidx.datastore.core.SimpleActor$offer$2.invokeSuspend(SimpleActor.kt:122) (Coroutine boundary) at com.nautiluslog.data.repository.TestDataStore$test$1.invokeSuspend(TestDataStore.kt:54) at com.nautiluslog.testutils.TestCoroutineRule$runBlockingTest$1.invokeSuspend(TestCoroutineRule.kt:30) at kotlinx.coroutines.test.TestBuildersKt$runBlockingTest$deferred$1.invokeSuspend(TestBuilders.kt:50)

ziglee commented 2 years ago

The problem happens inside SingleProcessDataStore.writeData function during scratchFile.renameTo(file). The file cannot be renamed because it already exist the destination name.

Nailik commented 2 years ago

Yes this happens when running unit tests on WIndows, any updates on this?

Nailik commented 2 years ago

Any updates on this? still happens and there is no workaround to test ProtoDataStore on Windows. This issue is also present multiple times in the issuetracker https://issuetracker.google.com/issues/194301881 https://issuetracker.google.com/issues/194208090 https://issuetracker.google.com/issues/203087070

ziglee commented 1 year ago

An issue was created on roboelectric repository: https://github.com/robolectric/robolectric/issues/7919

dstarchevskyy commented 1 year ago

I also faced this issue when call preferences.clear() in my test

SimonMarquis commented 1 year ago

Can we keep either this issue or #98? They are duplicates.

parlet commented 8 months ago

The years change, the issues don't, so here's a "temporary" (*winks*) solution for everyone set aback by this problem during their testing:

@Override
@Before
public void setUp() throws Exception {
    super.setUp();
    final File dataStoreFile = new File(mockContext.getFilesDir(), "datastore/yourDataStoreName.preferences_pb");
    dataStoreFile.delete();                                        // edit me ^^^^^^^^^^^^^^^^^
}