diff --git a/libraries/session-storage/impl/build.gradle.kts b/libraries/session-storage/impl/build.gradle.kts index cfbfa4c57d..a083d56480 100644 --- a/libraries/session-storage/impl/build.gradle.kts +++ b/libraries/session-storage/impl/build.gradle.kts @@ -45,6 +45,7 @@ dependencies { testImplementation(libs.test.turbine) testImplementation(libs.coroutines.test) testImplementation(libs.sqldelight.driver.jvm) + testImplementation(projects.tests.testutils) } sqldelight { diff --git a/libraries/session-storage/impl/src/test/kotlin/io/element/android/libraries/sessionstorage/impl/DatabaseSessionStoreTests.kt b/libraries/session-storage/impl/src/test/kotlin/io/element/android/libraries/sessionstorage/impl/DatabaseSessionStoreTests.kt index 760eefd20c..09d0ef867b 100644 --- a/libraries/session-storage/impl/src/test/kotlin/io/element/android/libraries/sessionstorage/impl/DatabaseSessionStoreTests.kt +++ b/libraries/session-storage/impl/src/test/kotlin/io/element/android/libraries/sessionstorage/impl/DatabaseSessionStoreTests.kt @@ -22,7 +22,6 @@ import com.google.common.truth.Truth.assertThat import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.matrix.session.SessionData import io.element.android.libraries.sessionstorage.api.LoggedInState -import io.element.android.libraries.sessionstorage.api.LoginType import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest @@ -33,19 +32,7 @@ class DatabaseSessionStoreTests { private lateinit var database: SessionDatabase private lateinit var databaseSessionStore: DatabaseSessionStore - private val aSessionData = SessionData( - userId = "userId", - deviceId = "deviceId", - accessToken = "accessToken", - refreshToken = "refreshToken", - homeserverUrl = "homeserverUrl", - slidingSyncProxy = null, - loginTimestamp = null, - oidcData = "aOidcData", - isTokenValid = 1, - loginType = LoginType.UNKNOWN.name, - passphrase = null, - ) + private val aSessionData = aSessionData() @OptIn(ExperimentalCoroutinesApi::class) @Before diff --git a/libraries/session-storage/impl/src/test/kotlin/io/element/android/libraries/sessionstorage/impl/Fixtures.kt b/libraries/session-storage/impl/src/test/kotlin/io/element/android/libraries/sessionstorage/impl/Fixtures.kt new file mode 100644 index 0000000000..341e5e0e92 --- /dev/null +++ b/libraries/session-storage/impl/src/test/kotlin/io/element/android/libraries/sessionstorage/impl/Fixtures.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.sessionstorage.impl + +import io.element.android.libraries.matrix.session.SessionData +import io.element.android.libraries.sessionstorage.api.LoginType + +internal fun aSessionData() = SessionData( + userId = "userId", + deviceId = "deviceId", + accessToken = "accessToken", + refreshToken = "refreshToken", + homeserverUrl = "homeserverUrl", + slidingSyncProxy = null, + loginTimestamp = null, + oidcData = "aOidcData", + isTokenValid = 1, + loginType = LoginType.UNKNOWN.name, + passphrase = null, +) diff --git a/libraries/session-storage/impl/src/test/kotlin/io/element/android/libraries/sessionstorage/impl/observer/DefaultSessionObserverTest.kt b/libraries/session-storage/impl/src/test/kotlin/io/element/android/libraries/sessionstorage/impl/observer/DefaultSessionObserverTest.kt new file mode 100644 index 0000000000..c0fc805fc6 --- /dev/null +++ b/libraries/session-storage/impl/src/test/kotlin/io/element/android/libraries/sessionstorage/impl/observer/DefaultSessionObserverTest.kt @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.sessionstorage.impl.observer + +import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver +import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.sessionstorage.impl.DatabaseSessionStore +import io.element.android.libraries.sessionstorage.impl.SessionDatabase +import io.element.android.libraries.sessionstorage.impl.aSessionData +import io.element.android.libraries.sessionstorage.impl.toApiModel +import io.element.android.tests.testutils.testCoroutineDispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.cancelChildren +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test + +@OptIn(ExperimentalCoroutinesApi::class) class DefaultSessionObserverTest { + private lateinit var database: SessionDatabase + private lateinit var databaseSessionStore: DatabaseSessionStore + + @OptIn(ExperimentalCoroutinesApi::class) + @Before + fun setup() { + // Initialise in memory SQLite driver + val driver = JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY) + SessionDatabase.Schema.create(driver) + database = SessionDatabase(driver) + databaseSessionStore = DatabaseSessionStore( + database = database, + dispatchers = CoroutineDispatchers( + io = UnconfinedTestDispatcher(), + computation = UnconfinedTestDispatcher(), + main = UnconfinedTestDispatcher(), + ) + ) + } + + @Test + fun `adding data invokes onSessionCreated`() = runTest { + val sessionData = aSessionData() + val sut = createDefaultSessionObserver() + runCurrent() + val listener = TestSessionListener() + sut.addListener(listener) + databaseSessionStore.storeData(sessionData.toApiModel()) + listener.assertEvents(TestSessionListener.Event.Created(sessionData.userId)) + sut.removeListener(listener) + coroutineContext.cancelChildren() + } + + @Test + fun `adding and deleting data invokes onSessionCreated and onSessionDeleted`() = runTest { + val sessionData = aSessionData() + val sut = createDefaultSessionObserver() + runCurrent() + val listener = TestSessionListener() + sut.addListener(listener) + databaseSessionStore.storeData(sessionData.toApiModel()) + listener.assertEvents(TestSessionListener.Event.Created(sessionData.userId)) + databaseSessionStore.removeSession(sessionData.userId) + listener.assertEvents( + TestSessionListener.Event.Created(sessionData.userId), + TestSessionListener.Event.Deleted(sessionData.userId), + ) + coroutineContext.cancelChildren() + } + + private fun TestScope.createDefaultSessionObserver(): DefaultSessionObserver { + return DefaultSessionObserver( + sessionStore = databaseSessionStore, + coroutineScope = this, + dispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true), + ) + } +} diff --git a/libraries/session-storage/impl/src/test/kotlin/io/element/android/libraries/sessionstorage/impl/observer/TestSessionListener.kt b/libraries/session-storage/impl/src/test/kotlin/io/element/android/libraries/sessionstorage/impl/observer/TestSessionListener.kt new file mode 100644 index 0000000000..2ec826ec4a --- /dev/null +++ b/libraries/session-storage/impl/src/test/kotlin/io/element/android/libraries/sessionstorage/impl/observer/TestSessionListener.kt @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.sessionstorage.impl.observer + +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.sessionstorage.api.observer.SessionListener + +class TestSessionListener : SessionListener { + sealed class Event { + data class Created(val userId: String) : Event() + data class Deleted(val userId: String) : Event() + } + + private val trackRecord: MutableList = mutableListOf() + + override suspend fun onSessionCreated(userId: String) { + trackRecord.add(Event.Created(userId)) + } + + override suspend fun onSessionDeleted(userId: String) { + trackRecord.add(Event.Deleted(userId)) + } + + fun assertEvents(vararg events: Event) { + assertThat(trackRecord).containsExactly(*events) + } +}