Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
ziglee opened this issue Dec 30, 2021 · 7 comments
Open

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

ziglee opened this issue Dec 30, 2021 · 7 comments

Comments

@ziglee
Copy link

ziglee commented Dec 30, 2021

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
Copy link
Author

ziglee commented Dec 30, 2021

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

@Nailik
Copy link

Nailik commented Apr 13, 2022

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

@Nailik
Copy link

Nailik commented May 13, 2022

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
Copy link
Author

ziglee commented Jan 12, 2023

An issue was created on roboelectric repository:
robolectric/robolectric#7919

@dstarchevskyy
Copy link

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

@SimonMarquis
Copy link

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

@parlet
Copy link

parlet commented Feb 23, 2024

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 ^^^^^^^^^^^^^^^^^
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants