Updates to session restoration (#1905)
## Description This PR reworks some of the internal handling of changing users and auto sign in. 1. Most recently used server/user is migrated from `AppPreferences` to `MostRecentServerProvider` 2. Checking if a user profile is protected occurs at a lower level in `ServerRepository` so fewer services need to check for this 3. Now always defaults to the most recent server's user list in cases where the most recent user can't be switched to such as if the profile is protected, auto signin is disabled, or and error occurred The default implementation for `MostRecentServerProvider` uses Android's `SharedPreferences`. `SharedPreferences` was already was being used to track the most recent server for crash reporting (the crash reporting process cannot use the Hilt DI). This PR enhances this and adds a better API for saving/retrieving. This also removes the last bit of "user specific" data from `AppPreferences`. ### Related issues None specific, but there have been a few related to auto sign-in & intents that were recently fixed. This PR is a more detailed approach to those same problems. ### Testing Manually via the emulator. There are also unit tests for most (all?) of the different settings and state combinations. ## Screenshots N/A ## AI or LLM usage None
This commit is contained in:
parent
a11cd9fb74
commit
f01c5d367c
19 changed files with 786 additions and 493 deletions
|
|
@ -1,14 +1,12 @@
|
|||
package com.github.damontecres.wholphin.test
|
||||
package com.github.damontecres.wholphin
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.widget.Toast
|
||||
import androidx.datastore.core.DataStore
|
||||
import com.github.damontecres.wholphin.MainActivityViewModel
|
||||
import com.github.damontecres.wholphin.data.CurrentUser
|
||||
import com.github.damontecres.wholphin.data.JellyfinServerDao
|
||||
import com.github.damontecres.wholphin.data.RestoredSession
|
||||
import com.github.damontecres.wholphin.data.ServerRepository
|
||||
import com.github.damontecres.wholphin.data.model.JellyfinServerUsers
|
||||
import com.github.damontecres.wholphin.preferences.AppPreferences
|
||||
import com.github.damontecres.wholphin.preferences.update
|
||||
import com.github.damontecres.wholphin.services.AppUpgradeHandler
|
||||
|
|
@ -19,8 +17,10 @@ import com.github.damontecres.wholphin.services.IntentService
|
|||
import com.github.damontecres.wholphin.services.NavigationManager
|
||||
import com.github.damontecres.wholphin.services.SetupDestination
|
||||
import com.github.damontecres.wholphin.services.SetupNavigationManager
|
||||
import com.github.damontecres.wholphin.test.currentUser
|
||||
import com.github.damontecres.wholphin.test.server
|
||||
import com.github.damontecres.wholphin.test.user
|
||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||
import com.github.damontecres.wholphin.ui.toServerString
|
||||
import com.github.damontecres.wholphin.util.WholphinDispatchers
|
||||
import com.github.damontecres.wholphin.util.configure
|
||||
import com.github.damontecres.wholphin.util.reset
|
||||
|
|
@ -36,11 +36,11 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||
import kotlinx.coroutines.test.advanceUntilIdle
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.jellyfin.sdk.model.UUID
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
|
@ -58,7 +58,6 @@ class TestMainActivityViewModel {
|
|||
private val backdropService: BackdropService = mockk(relaxed = true)
|
||||
private val appUpgradeHandler: AppUpgradeHandler = mockk()
|
||||
private val intentService: IntentService = mockk()
|
||||
private val serverDao: JellyfinServerDao = mockk()
|
||||
|
||||
val viewModel =
|
||||
MainActivityViewModel(
|
||||
|
|
@ -74,6 +73,7 @@ class TestMainActivityViewModel {
|
|||
)
|
||||
|
||||
private val serverId = UUID.randomUUID()
|
||||
private val server = server(serverId)
|
||||
private val userId = UUID.randomUUID()
|
||||
private val currentUser = currentUser(serverId, userId)
|
||||
|
||||
|
|
@ -88,13 +88,6 @@ class TestMainActivityViewModel {
|
|||
WholphinDispatchers.configure(testDispatcher)
|
||||
every { appUpgradeHandler.needUpgrade() } returns false
|
||||
every { appUpgradeHandler.copySubfont(any()) } returns Unit
|
||||
every { serverRepository.serverDao } returns serverDao
|
||||
coEvery { serverDao.getServer(serverId) } returns
|
||||
JellyfinServerUsers(
|
||||
currentUser.server,
|
||||
// User list is unused
|
||||
emptyList(),
|
||||
)
|
||||
mockkStatic(Toast::class)
|
||||
val mockToast = mockk<Toast>()
|
||||
every { Toast.makeText(any(), any<CharSequence>(), any()) } returns mockToast
|
||||
|
|
@ -121,22 +114,26 @@ class TestMainActivityViewModel {
|
|||
runTest(testDispatcher) {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow(currentUser)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns currentUser
|
||||
// coEvery { serverRepository.tryRestoreSession(serverId, userId) } returns currentUser
|
||||
// coEvery { serverRepository.restoreLastSession() } returns
|
||||
// RestoredSession.Success(currentUser)
|
||||
|
||||
viewModel.appStart(null)
|
||||
advanceUntilIdle()
|
||||
viewModel.handleAppStart()
|
||||
|
||||
val slot = slot<SetupDestination>()
|
||||
verify { setupNavigationManager.navigateTo(capture(slot)) }
|
||||
slot.captured.let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.AppContent)
|
||||
Assert.assertTrue(
|
||||
"destination is ${destination::class}",
|
||||
destination is SetupDestination.AppContent,
|
||||
)
|
||||
destination as SetupDestination.AppContent
|
||||
assertEquals(currentUser, destination.current)
|
||||
Assert.assertEquals(currentUser, destination.current)
|
||||
}
|
||||
coVerify(exactly = 0) { serverRepository.restoreLastSession() }
|
||||
coVerify(exactly = 0) { serverRepository.getMostRecentServer() }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -144,27 +141,27 @@ class TestMainActivityViewModel {
|
|||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = false
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(currentUser)
|
||||
// coEvery { serverRepository.restoreSession(serverId, userId) } returns currentUser
|
||||
coEvery { serverRepository.getMostRecentServer() } returns
|
||||
RestoredSession.ServerOnly(server)
|
||||
|
||||
viewModel.appStart(null)
|
||||
advanceUntilIdle()
|
||||
viewModel.handleAppStart()
|
||||
|
||||
verify(exactly = 1) { serverDao.getServer(serverId) }
|
||||
coVerify(exactly = 0) { serverRepository.restoreSession(any(), any()) }
|
||||
coVerify(exactly = 0) { serverRepository.tryChangeUser(any(), any()) }
|
||||
coVerify(exactly = 0) { serverRepository.restoreLastSession() }
|
||||
coVerify(exactly = 1) { serverRepository.getMostRecentServer() }
|
||||
val args = mutableListOf<SetupDestination>()
|
||||
verify { setupNavigationManager.navigateTo(capture(args)) }
|
||||
assertEquals(2, args.size)
|
||||
Assert.assertEquals(1, args.size)
|
||||
args[0].let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.Loading)
|
||||
}
|
||||
args[1].let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.UserList)
|
||||
Assert.assertTrue(
|
||||
"destination is ${destination::class}",
|
||||
destination is SetupDestination.UserList,
|
||||
)
|
||||
destination as SetupDestination.UserList
|
||||
assertEquals(currentUser.server, destination.server)
|
||||
Assert.assertEquals(currentUser.server, destination.server)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -173,27 +170,30 @@ class TestMainActivityViewModel {
|
|||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(protectedCurrentUser)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns protectedCurrentUser
|
||||
every { serverRepository.current } returns
|
||||
MutableStateFlow<CurrentUser?>(
|
||||
protectedCurrentUser,
|
||||
)
|
||||
coEvery {
|
||||
serverRepository.tryChangeUser(serverId, userId)
|
||||
} returns null
|
||||
coEvery { serverRepository.restoreLastSession() } returns
|
||||
RestoredSession.ServerOnly(server)
|
||||
|
||||
viewModel.appStart(null)
|
||||
advanceUntilIdle()
|
||||
viewModel.handleAppStart()
|
||||
|
||||
coVerify(exactly = 0) { serverRepository.restoreSession(serverId, userId) }
|
||||
verify { serverDao.getServer(serverId) }
|
||||
coVerify(exactly = 0) { serverRepository.tryChangeUser(serverId, userId) }
|
||||
val args = mutableListOf<SetupDestination>()
|
||||
verify { setupNavigationManager.navigateTo(capture(args)) }
|
||||
assertEquals(2, args.size)
|
||||
Assert.assertEquals(1, args.size)
|
||||
args[0].let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.Loading)
|
||||
}
|
||||
args[1].let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.UserList)
|
||||
Assert.assertTrue(
|
||||
"destination is ${destination::class}",
|
||||
destination is SetupDestination.UserList,
|
||||
)
|
||||
destination as SetupDestination.UserList
|
||||
assertEquals(currentUser.server, destination.server)
|
||||
Assert.assertEquals(currentUser.server, destination.server)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -202,22 +202,26 @@ class TestMainActivityViewModel {
|
|||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(null)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns protectedCurrentUser
|
||||
coEvery { serverRepository.restoreLastSession() } returns
|
||||
RestoredSession.ServerOnly(server)
|
||||
coEvery {
|
||||
serverRepository.tryChangeUser(serverId, userId)
|
||||
} returns null
|
||||
|
||||
viewModel.appStart(null)
|
||||
advanceUntilIdle()
|
||||
viewModel.handleAppStart()
|
||||
|
||||
coVerify(exactly = 1) { serverRepository.restoreSession(serverId, userId) }
|
||||
coVerify(exactly = 1) { serverRepository.restoreLastSession() }
|
||||
val slot = slot<SetupDestination>()
|
||||
verify { setupNavigationManager.navigateTo(capture(slot)) }
|
||||
slot.captured.let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.UserList)
|
||||
Assert.assertTrue(
|
||||
"destination is ${destination::class}",
|
||||
destination is SetupDestination.UserList,
|
||||
)
|
||||
destination as SetupDestination.UserList
|
||||
assertEquals(currentUser.server, destination.server)
|
||||
Assert.assertEquals(currentUser.server, destination.server)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -226,45 +230,49 @@ class TestMainActivityViewModel {
|
|||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = ""
|
||||
currentUserId = ""
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(null)
|
||||
coEvery { serverRepository.restoreSession(null, null) } returns null
|
||||
coEvery { serverRepository.restoreLastSession() } returns RestoredSession.None
|
||||
|
||||
viewModel.appStart(null)
|
||||
advanceUntilIdle()
|
||||
viewModel.handleAppStart()
|
||||
|
||||
coVerify(exactly = 1) { serverRepository.restoreSession(null, null) }
|
||||
coVerify(exactly = 1) { serverRepository.restoreLastSession() }
|
||||
val slot = slot<SetupDestination>()
|
||||
verify { setupNavigationManager.navigateTo(capture(slot)) }
|
||||
slot.captured.let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.ServerList)
|
||||
Assert.assertTrue(
|
||||
"destination is ${destination::class}",
|
||||
destination is SetupDestination.ServerList,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test intent result is noop`() =
|
||||
fun `Test intent result is noop, hot reload`() =
|
||||
runTest(testDispatcher) {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow(currentUser)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns currentUser
|
||||
coEvery { serverRepository.restoreLastSession() } returns
|
||||
RestoredSession.Success(currentUser)
|
||||
coEvery { intentService.parseIntent(any()) } returns IntentResult.NoOp
|
||||
|
||||
viewModel.appStart(Intent())
|
||||
advanceUntilIdle()
|
||||
val result = viewModel.handleIntent(Intent())
|
||||
assertFalse(result)
|
||||
|
||||
val slot = slot<SetupDestination>()
|
||||
verify { setupNavigationManager.navigateTo(capture(slot)) }
|
||||
slot.captured.let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.AppContent)
|
||||
destination as SetupDestination.AppContent
|
||||
assertEquals(currentUser, destination.current)
|
||||
}
|
||||
// val slot = slot<SetupDestination>()
|
||||
// verify { setupNavigationManager.navigateTo(capture(slot)) }
|
||||
// slot.captured.let { destination ->
|
||||
// Assert.assertTrue(
|
||||
// "destination is ${destination::class}",
|
||||
// destination is SetupDestination.AppContent,
|
||||
// )
|
||||
// destination as SetupDestination.AppContent
|
||||
// Assert.assertEquals(currentUser, destination.current)
|
||||
// }
|
||||
coVerify(exactly = 0) { serverRepository.restoreLastSession() }
|
||||
coVerify(exactly = 0) { serverRepository.getMostRecentServer() }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -272,22 +280,22 @@ class TestMainActivityViewModel {
|
|||
runTest(testDispatcher) {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow(currentUser)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns currentUser
|
||||
coEvery { intentService.parseIntent(any()) } returns IntentResult.Error("Error")
|
||||
|
||||
viewModel.appStart(Intent())
|
||||
advanceUntilIdle()
|
||||
val result = viewModel.handleIntent(Intent())
|
||||
assertTrue(result)
|
||||
|
||||
val slot = slot<SetupDestination>()
|
||||
verify { setupNavigationManager.navigateTo(capture(slot)) }
|
||||
slot.captured.let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.UserList)
|
||||
Assert.assertTrue(
|
||||
"destination is ${destination::class}",
|
||||
destination is SetupDestination.UserList,
|
||||
)
|
||||
destination as SetupDestination.UserList
|
||||
assertEquals(currentUser.server, destination.server)
|
||||
Assert.assertEquals(currentUser.server, destination.server)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -296,20 +304,20 @@ class TestMainActivityViewModel {
|
|||
runTest(testDispatcher) {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow(null)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns currentUser
|
||||
coEvery { intentService.parseIntent(any()) } returns IntentResult.Error("Error")
|
||||
|
||||
viewModel.appStart(Intent())
|
||||
advanceUntilIdle()
|
||||
val result = viewModel.handleIntent(Intent())
|
||||
assertTrue(result)
|
||||
|
||||
val slot = slot<SetupDestination>()
|
||||
verify { setupNavigationManager.navigateTo(capture(slot)) }
|
||||
slot.captured.let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.ServerList)
|
||||
Assert.assertTrue(
|
||||
"destination is ${destination::class}",
|
||||
destination is SetupDestination.ServerList,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -318,11 +326,9 @@ class TestMainActivityViewModel {
|
|||
runTest(testDispatcher) {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow(currentUser)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns currentUser
|
||||
// coEvery { serverRepository.tryRestoreSession(serverId, userId) } returns currentUser
|
||||
coEvery { intentService.parseIntent(any()) } returns
|
||||
IntentResult.Target(
|
||||
destinations = listOf(Destination.Favorites),
|
||||
|
|
@ -331,21 +337,27 @@ class TestMainActivityViewModel {
|
|||
val backstack = mutableListOf<Destination>()
|
||||
every { navigationManager.backStack } returns backstack
|
||||
|
||||
viewModel.appStart(Intent())
|
||||
advanceUntilIdle()
|
||||
val result = viewModel.handleIntent(Intent())
|
||||
assertTrue(result)
|
||||
|
||||
val slot = slot<SetupDestination>()
|
||||
verify { setupNavigationManager.navigateTo(capture(slot)) }
|
||||
verify { navigationManager.reloadHome() }
|
||||
slot.captured.let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.AppContent)
|
||||
Assert.assertTrue(
|
||||
"destination is ${destination::class}",
|
||||
destination is SetupDestination.AppContent,
|
||||
)
|
||||
destination as SetupDestination.AppContent
|
||||
assertEquals(currentUser, destination.current)
|
||||
Assert.assertEquals(currentUser, destination.current)
|
||||
}
|
||||
// Note: navigation manager internally handles Home destination, so it won't be in this list
|
||||
assertEquals(1, backstack.size)
|
||||
Assert.assertEquals(1, backstack.size)
|
||||
backstack[0].let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is Destination.Favorites)
|
||||
Assert.assertTrue(
|
||||
"destination is ${destination::class}",
|
||||
destination is Destination.Favorites,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -354,11 +366,9 @@ class TestMainActivityViewModel {
|
|||
runTest(testDispatcher) {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow(currentUser)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns currentUser
|
||||
// coEvery { serverRepository.tryRestoreSession(serverId, userId) } returns currentUser
|
||||
coEvery { intentService.parseIntent(any()) } returns
|
||||
IntentResult.Target(
|
||||
destinations = listOf(Destination.Favorites),
|
||||
|
|
@ -367,20 +377,26 @@ class TestMainActivityViewModel {
|
|||
val backstack = mutableListOf<Destination>()
|
||||
every { navigationManager.backStack } returns backstack
|
||||
|
||||
viewModel.appStart(Intent())
|
||||
advanceUntilIdle()
|
||||
val result = viewModel.handleIntent(Intent())
|
||||
assertTrue(result)
|
||||
|
||||
val slot = slot<SetupDestination>()
|
||||
verify { setupNavigationManager.navigateTo(capture(slot)) }
|
||||
verify(exactly = 0) { navigationManager.reloadHome() }
|
||||
slot.captured.let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.AppContent)
|
||||
Assert.assertTrue(
|
||||
"destination is ${destination::class}",
|
||||
destination is SetupDestination.AppContent,
|
||||
)
|
||||
destination as SetupDestination.AppContent
|
||||
assertEquals(currentUser, destination.current)
|
||||
Assert.assertEquals(currentUser, destination.current)
|
||||
}
|
||||
assertEquals(1, backstack.size)
|
||||
Assert.assertEquals(1, backstack.size)
|
||||
backstack[0].let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is Destination.Favorites)
|
||||
Assert.assertTrue(
|
||||
"destination is ${destination::class}",
|
||||
destination is Destination.Favorites,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -389,11 +405,9 @@ class TestMainActivityViewModel {
|
|||
runTest(testDispatcher) {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow(null)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns currentUser
|
||||
// coEvery { serverRepository.tryRestoreSession(serverId, userId) } returns currentUser
|
||||
coEvery { intentService.parseIntent(any()) } returns
|
||||
IntentResult.Target(
|
||||
destinations = listOf(Destination.Favorites),
|
||||
|
|
@ -402,14 +416,17 @@ class TestMainActivityViewModel {
|
|||
val backstack = mutableListOf<Destination>()
|
||||
every { navigationManager.backStack } returns backstack
|
||||
|
||||
viewModel.appStart(Intent())
|
||||
advanceUntilIdle()
|
||||
val result = viewModel.handleIntent(Intent())
|
||||
assertTrue(result)
|
||||
|
||||
val slot = slot<SetupDestination>()
|
||||
verify { setupNavigationManager.navigateTo(capture(slot)) }
|
||||
verify(exactly = 0) { navigationManager.reloadHome() }
|
||||
slot.captured.let { destination ->
|
||||
assertTrue("destination is ${destination::class}", destination is SetupDestination.ServerList)
|
||||
Assert.assertTrue(
|
||||
"destination is ${destination::class}",
|
||||
destination is SetupDestination.ServerList,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ package com.github.damontecres.wholphin.services
|
|||
import android.app.SearchManager
|
||||
import android.content.Intent
|
||||
import com.github.damontecres.wholphin.data.CurrentUser
|
||||
import com.github.damontecres.wholphin.data.JellyfinServerDao
|
||||
import com.github.damontecres.wholphin.data.RestoredSession
|
||||
import com.github.damontecres.wholphin.data.ServerRepository
|
||||
import com.github.damontecres.wholphin.preferences.AppPreferences
|
||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||
|
|
@ -20,7 +20,6 @@ import io.mockk.coEvery
|
|||
import io.mockk.coVerify
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.test.runTest
|
||||
|
|
@ -42,7 +41,6 @@ import org.robolectric.annotation.Config
|
|||
class IntentServiceTest {
|
||||
private val api: ApiClient = mockk()
|
||||
private val serverRepository: ServerRepository = mockk()
|
||||
private val serverDao: JellyfinServerDao = mockk()
|
||||
private val userPreferencesService: UserPreferencesService = mockk()
|
||||
private val userLibraryApi: UserLibraryApi = mockk()
|
||||
|
||||
|
|
@ -64,7 +62,6 @@ class IntentServiceTest {
|
|||
intentService = IntentService(api, serverRepository, userPreferencesService)
|
||||
every { api.userLibraryApi } returns userLibraryApi
|
||||
coEvery { userLibraryApi.getItem(itemId) } returns successResponse(movie(itemId))
|
||||
every { serverRepository.serverDao } returns serverDao
|
||||
}
|
||||
|
||||
private fun setupPreferences(block: AppPreferences.Builder.() -> Unit) {
|
||||
|
|
@ -82,11 +79,11 @@ class IntentServiceTest {
|
|||
private fun setupAutoSignInUnprotected() {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(currentUser)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns currentUser
|
||||
coEvery { serverRepository.restoreLastSession() } returns
|
||||
RestoredSession.Success(currentUser)
|
||||
coEvery { serverRepository.tryChangeUser(serverId, userId) } returns currentUser
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -98,7 +95,7 @@ class IntentServiceTest {
|
|||
val result = intentService.prepare(intent)
|
||||
assertNull(result)
|
||||
|
||||
coVerify { serverRepository.restoreSession(serverId, userId) }
|
||||
coVerify { serverRepository.restoreLastSession() }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -106,17 +103,17 @@ class IntentServiceTest {
|
|||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = false
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(currentUser)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns currentUser
|
||||
coEvery { serverRepository.restoreLastSession() } returns
|
||||
RestoredSession.Success(currentUser)
|
||||
coEvery { serverRepository.tryChangeUser(serverId, userId) } returns currentUser
|
||||
|
||||
val intent = Intent()
|
||||
val result = intentService.prepare(intent)
|
||||
assertTrue(result is IntentResult.Error)
|
||||
|
||||
coVerify(exactly = 0) { serverRepository.restoreSession(serverId, userId) }
|
||||
coVerify(exactly = 0) { serverRepository.tryChangeUser(serverId, userId) }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -124,17 +121,17 @@ class IntentServiceTest {
|
|||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(protectedCurrentUser)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns protectedCurrentUser
|
||||
coEvery { serverRepository.tryChangeUser(serverId, userId) } returns null
|
||||
coEvery { serverRepository.restoreLastSession() } returns
|
||||
RestoredSession.ServerOnly(protectedCurrentUser.server)
|
||||
|
||||
val intent = Intent()
|
||||
val result = intentService.prepare(intent)
|
||||
assertTrue(result is IntentResult.Error)
|
||||
|
||||
coVerify(exactly = 0) { serverRepository.restoreSession(serverId, userId) }
|
||||
coVerify(exactly = 0) { serverRepository.tryChangeUser(serverId, userId) }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -142,17 +139,17 @@ class IntentServiceTest {
|
|||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = serverId.toServerString()
|
||||
currentUserId = userId.toServerString()
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(null)
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns protectedCurrentUser
|
||||
coEvery { serverRepository.tryChangeUser(serverId, userId) } returns null
|
||||
coEvery { serverRepository.restoreLastSession() } returns
|
||||
RestoredSession.ServerOnly(protectedCurrentUser.server)
|
||||
|
||||
val intent = Intent()
|
||||
val result = intentService.prepare(intent)
|
||||
assertTrue(result is IntentResult.Error)
|
||||
|
||||
coVerify(exactly = 1) { serverRepository.restoreSession(serverId, userId) }
|
||||
coVerify(exactly = 1) { serverRepository.restoreLastSession() }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -160,17 +157,16 @@ class IntentServiceTest {
|
|||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = ""
|
||||
currentUserId = ""
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(null)
|
||||
coEvery { serverRepository.restoreLastSession() } returns RestoredSession.None
|
||||
// coEvery { serverRepository.restoreSession(serverId, userId) } returns protectedCurrentUser
|
||||
|
||||
val intent = Intent()
|
||||
val result = intentService.prepare(intent)
|
||||
assertTrue(result is IntentResult.Error)
|
||||
|
||||
coVerify(exactly = 0) { serverRepository.restoreSession(serverId, userId) }
|
||||
coVerify(exactly = 0) { serverRepository.tryChangeUser(serverId, userId) }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -178,12 +174,11 @@ class IntentServiceTest {
|
|||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = ""
|
||||
currentUserId = ""
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(null)
|
||||
coEvery { serverRepository.serverDao.getUser(serverId, userId) } returns currentUser.user
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns currentUser
|
||||
coEvery { serverRepository.tryChangeUser(serverId, userId) } returns currentUser
|
||||
coEvery { serverRepository.restoreLastSession() } returns
|
||||
RestoredSession.Success(currentUser)
|
||||
|
||||
val intent =
|
||||
Intent().apply {
|
||||
|
|
@ -193,7 +188,7 @@ class IntentServiceTest {
|
|||
val result = intentService.prepare(intent)
|
||||
assertNull(result)
|
||||
|
||||
coVerify(exactly = 1) { serverRepository.restoreSession(serverId, userId) }
|
||||
coVerify(exactly = 1) { serverRepository.tryChangeUser(serverId, userId) }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -201,12 +196,11 @@ class IntentServiceTest {
|
|||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = ""
|
||||
currentUserId = ""
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(null)
|
||||
coEvery { serverRepository.serverDao.getUser(serverId, userId) } returns protectedCurrentUser.user
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns protectedCurrentUser
|
||||
coEvery { serverRepository.tryChangeUser(serverId, userId) } returns null
|
||||
// coEvery { serverRepository.restoreLastSession() } returns
|
||||
// RestoredSession.ServerOnly(protectedCurrentUser.server)
|
||||
|
||||
val intent =
|
||||
Intent().apply {
|
||||
|
|
@ -216,7 +210,7 @@ class IntentServiceTest {
|
|||
val result = intentService.prepare(intent)
|
||||
assertTrue(result is IntentResult.Error)
|
||||
|
||||
coVerify(exactly = 0) { serverRepository.restoreSession(serverId, userId) }
|
||||
coVerify(exactly = 1) { serverRepository.tryChangeUser(serverId, userId) }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -224,12 +218,9 @@ class IntentServiceTest {
|
|||
runTest {
|
||||
setupPreferences {
|
||||
signInAutomatically = true
|
||||
currentServerId = ""
|
||||
currentUserId = ""
|
||||
}
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(null)
|
||||
coEvery { serverRepository.serverDao.getUser(serverId, userId) } returns null
|
||||
coEvery { serverRepository.restoreSession(serverId, userId) } returns null
|
||||
coEvery { serverRepository.tryChangeUser(serverId, userId) } returns null
|
||||
|
||||
val intent =
|
||||
Intent().apply {
|
||||
|
|
@ -239,7 +230,7 @@ class IntentServiceTest {
|
|||
val result = intentService.prepare(intent)
|
||||
assertTrue(result is IntentResult.Error)
|
||||
|
||||
coVerify(exactly = 0) { serverRepository.restoreSession(serverId, userId) }
|
||||
coVerify(exactly = 1) { serverRepository.tryChangeUser(serverId, userId) }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -296,12 +287,11 @@ class IntentServiceTest {
|
|||
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(currentUser)
|
||||
coEvery {
|
||||
serverRepository.restoreSession(
|
||||
serverRepository.tryChangeUser(
|
||||
newServerId,
|
||||
newUserId,
|
||||
)
|
||||
} returns newCurrentUser
|
||||
every { serverDao.getUser(newServerId, newUserId) } returns newCurrentUser.user
|
||||
|
||||
val intent =
|
||||
Intent().apply {
|
||||
|
|
@ -316,9 +306,8 @@ class IntentServiceTest {
|
|||
assertEquals(0, destinations.size)
|
||||
assertTrue(result.addHomeToBackStack)
|
||||
|
||||
coVerify(exactly = 0) { serverRepository.restoreSession(serverId, userId) }
|
||||
verify { serverDao.getUser(newServerId, newUserId) }
|
||||
coVerify { serverRepository.restoreSession(newServerId, newUserId) }
|
||||
coVerify(exactly = 0) { serverRepository.tryChangeUser(serverId, userId) }
|
||||
coVerify { serverRepository.tryChangeUser(newServerId, newUserId) }
|
||||
coVerify(exactly = 0) { userLibraryApi.getItem(itemId) }
|
||||
}
|
||||
|
||||
|
|
@ -333,12 +322,11 @@ class IntentServiceTest {
|
|||
|
||||
every { serverRepository.current } returns MutableStateFlow<CurrentUser?>(currentUser)
|
||||
coEvery {
|
||||
serverRepository.restoreSession(
|
||||
serverRepository.tryChangeUser(
|
||||
newServerId,
|
||||
newUserId,
|
||||
)
|
||||
} returns newCurrentUser
|
||||
every { serverDao.getUser(newServerId, newUserId) } returns newCurrentUser.user
|
||||
|
||||
val intent =
|
||||
Intent().apply {
|
||||
|
|
@ -358,9 +346,8 @@ class IntentServiceTest {
|
|||
|
||||
assertEquals(itemId, first.itemId)
|
||||
|
||||
coVerify(exactly = 0) { serverRepository.restoreSession(serverId, userId) }
|
||||
verify { serverDao.getUser(newServerId, newUserId) }
|
||||
coVerify { serverRepository.restoreSession(newServerId, newUserId) }
|
||||
coVerify(exactly = 0) { serverRepository.tryChangeUser(serverId, userId) }
|
||||
coVerify { serverRepository.tryChangeUser(newServerId, newUserId) }
|
||||
coVerify { userLibraryApi.getItem(itemId) }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
package com.github.damontecres.wholphin.services
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import androidx.datastore.core.DataStoreFactory
|
||||
import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler
|
||||
import com.github.damontecres.wholphin.data.CurrentUser
|
||||
import com.github.damontecres.wholphin.data.JellyfinServerDao
|
||||
import com.github.damontecres.wholphin.data.MostRecentServer
|
||||
import com.github.damontecres.wholphin.data.MostRecentServerProvider
|
||||
import com.github.damontecres.wholphin.data.RestoredSession
|
||||
import com.github.damontecres.wholphin.data.ServerRepository
|
||||
import com.github.damontecres.wholphin.data.model.JellyfinServer
|
||||
import com.github.damontecres.wholphin.data.model.JellyfinServerUsers
|
||||
|
|
@ -14,6 +16,7 @@ import com.github.damontecres.wholphin.data.model.ServerUserConfig
|
|||
import com.github.damontecres.wholphin.preferences.AppPreferences
|
||||
import com.github.damontecres.wholphin.preferences.AppPreferencesSerializer
|
||||
import com.github.damontecres.wholphin.test.nonBlankString
|
||||
import com.github.damontecres.wholphin.ui.isNotNullOrBlank
|
||||
import com.github.damontecres.wholphin.ui.successResponse
|
||||
import com.github.damontecres.wholphin.ui.toServerString
|
||||
import com.github.damontecres.wholphin.util.WholphinDispatchers
|
||||
|
|
@ -21,6 +24,7 @@ import com.github.damontecres.wholphin.util.configure
|
|||
import com.github.damontecres.wholphin.util.reset
|
||||
import io.mockk.Runs
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
|
|
@ -29,7 +33,6 @@ import io.mockk.verify
|
|||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||
import kotlinx.coroutines.test.runTest
|
||||
|
|
@ -48,6 +51,8 @@ import org.jellyfin.sdk.model.api.PublicSystemInfo
|
|||
import org.jellyfin.sdk.model.api.UserDto
|
||||
import org.junit.After
|
||||
import org.junit.Assert
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
|
@ -80,14 +85,13 @@ class ServerRepositoryTest {
|
|||
|
||||
private val mockUserApi = mockk<UserApi>()
|
||||
private val mockSystemApi = mockk<SystemApi>()
|
||||
private val mockSharedPreferences = mockk<SharedPreferences>(relaxed = true)
|
||||
private val mockMostRecentServerProvider = mockk<MostRecentServerProvider>()
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Before
|
||||
fun setup() {
|
||||
WholphinDispatchers.configure(testDispatcher)
|
||||
|
||||
every { mockContext.getSharedPreferences(any(), any()) } returns mockSharedPreferences
|
||||
every { mockApiClient.userApi } returns mockUserApi
|
||||
every { mockApiClient.systemApi } returns mockSystemApi
|
||||
coEvery { mockUserApi.getCurrentUser() } returns successResponse(userDto)
|
||||
|
|
@ -102,9 +106,15 @@ class ServerRepositoryTest {
|
|||
emptyMap(),
|
||||
)
|
||||
coEvery { mockJellyfinServerDao.addOrUpdateUser(user) } returns user
|
||||
coEvery { mockJellyfinServerDao.getServer(serverId) } returns
|
||||
JellyfinServerUsers(server, listOf(user))
|
||||
coEvery { mockJellyfinServerDao.addOrUpdateServer(server) } just Runs
|
||||
every { mockApiClient.clientInfo } returns ClientInfo("Wholphin test", "0.0.1")
|
||||
every { mockApiClient.deviceInfo } returns DeviceInfo("Wholphin test ID", "Wholphin test device")
|
||||
every { mockApiClient.update(any(), any(), any(), any()) } just Runs
|
||||
coEvery { mockMostRecentServerProvider.save(any()) } just Runs
|
||||
coEvery { mockMostRecentServerProvider.clear() } just Runs
|
||||
coEvery { mockMostRecentServerProvider.clearUser() } just Runs
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
|
|
@ -119,8 +129,8 @@ class ServerRepositoryTest {
|
|||
mockJellyfin,
|
||||
mockJellyfinServerDao,
|
||||
mockApiClient,
|
||||
dataStore,
|
||||
testDispatcher,
|
||||
mockMostRecentServerProvider,
|
||||
)
|
||||
|
||||
private val serverId = UUID.randomUUID()
|
||||
|
|
@ -194,24 +204,24 @@ class ServerRepositoryTest {
|
|||
Assert.assertEquals(user, serverRepository.currentUser)
|
||||
Assert.assertEquals(serverUserConfig, serverRepository.currentUserDto)
|
||||
|
||||
val appPreferences = dataStore.data.first()
|
||||
Assert.assertEquals(serverId.toServerString(), appPreferences.currentServerId)
|
||||
Assert.assertEquals(userId.toServerString(), appPreferences.currentUserId)
|
||||
|
||||
verify(exactly = 1) { mockSharedPreferences.edit() }
|
||||
coVerify(exactly = 1) { mockMostRecentServerProvider.save(CurrentUser(server, user)) }
|
||||
verify(exactly = 1) { mockJellyfinServerDao.addOrUpdateUser(user) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test restoreUser via changeUser`() =
|
||||
runTest {
|
||||
val user = user.copy(pin = null)
|
||||
every { mockJellyfinServerDao.addOrUpdateServer(any()) } just Runs
|
||||
every { mockJellyfinServerDao.addOrUpdateUser(user) } returns user
|
||||
every { mockJellyfinServerDao.getServer(serverId) } returns JellyfinServerUsers(server, listOf(user))
|
||||
|
||||
val serverRepository = create()
|
||||
Assert.assertNull(serverRepository.currentUser)
|
||||
serverRepository.restoreSession(server.id, user.id)
|
||||
val result = serverRepository.tryChangeUser(server.id, user.id)
|
||||
assertTrue(result != null)
|
||||
assertEquals(serverId, result?.server?.id)
|
||||
assertEquals(user.id, result?.user?.id)
|
||||
|
||||
verify(exactly = 1) {
|
||||
mockApiClient.update(
|
||||
|
|
@ -226,34 +236,6 @@ class ServerRepositoryTest {
|
|||
Assert.assertEquals(serverUserConfig, serverRepository.currentUserDto)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test restoreUser via shortcut`() =
|
||||
runTest {
|
||||
every { mockJellyfinServerDao.getServer(serverId) } returns JellyfinServerUsers(server, listOf(user))
|
||||
|
||||
val serverRepository = create()
|
||||
setUpCurrentUser(serverRepository)
|
||||
|
||||
serverRepository.restoreSession(server.id, user.id)
|
||||
|
||||
verify(exactly = 1) {
|
||||
mockApiClient.update(
|
||||
baseUrl = server.url,
|
||||
accessToken = user.accessToken,
|
||||
clientInfo = any(),
|
||||
deviceInfo = any(),
|
||||
)
|
||||
}
|
||||
verify(exactly = 0) { mockJellyfinServerDao.addOrUpdateServer(any()) }
|
||||
verify(exactly = 0) { mockJellyfinServerDao.addOrUpdateUser(any()) }
|
||||
|
||||
Assert.assertEquals(server, serverRepository.currentServer)
|
||||
Assert.assertEquals(user, serverRepository.currentUser)
|
||||
|
||||
// TODO fix this, need to check userDto too
|
||||
// Assert.assertEquals(userDto, serverRepository.currentUserDto)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test remove user`() =
|
||||
runTest {
|
||||
|
|
@ -308,6 +290,7 @@ class ServerRepositoryTest {
|
|||
)
|
||||
}
|
||||
verify(exactly = 1) { mockJellyfinServerDao.deleteUser(serverId, userId) }
|
||||
coVerify { mockMostRecentServerProvider.clearUser() }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -351,6 +334,7 @@ class ServerRepositoryTest {
|
|||
)
|
||||
}
|
||||
verify(exactly = 1) { mockJellyfinServerDao.deleteServer(serverId) }
|
||||
coVerify { mockMostRecentServerProvider.clear() }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -387,11 +371,7 @@ class ServerRepositoryTest {
|
|||
Assert.assertEquals(user, serverRepository.currentUser)
|
||||
Assert.assertEquals(serverUserConfig, serverRepository.currentUserDto)
|
||||
|
||||
val appPreferences = dataStore.data.first()
|
||||
Assert.assertEquals(serverId.toServerString(), appPreferences.currentServerId)
|
||||
Assert.assertEquals(userId.toServerString(), appPreferences.currentUserId)
|
||||
|
||||
verify(exactly = 1) { mockSharedPreferences.edit() }
|
||||
coVerify(exactly = 1) { mockMostRecentServerProvider.save(CurrentUser(server, user)) }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -430,11 +410,7 @@ class ServerRepositoryTest {
|
|||
Assert.assertEquals(user, serverRepository.currentUser)
|
||||
Assert.assertEquals(serverUserConfig, serverRepository.currentUserDto)
|
||||
|
||||
val appPreferences = dataStore.data.first()
|
||||
Assert.assertEquals(serverId.toServerString(), appPreferences.currentServerId)
|
||||
Assert.assertEquals(userId.toServerString(), appPreferences.currentUserId)
|
||||
|
||||
verify(exactly = 1) { mockSharedPreferences.edit() }
|
||||
coVerify(exactly = 1) { mockMostRecentServerProvider.save(CurrentUser(server, user)) }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -484,4 +460,99 @@ class ServerRepositoryTest {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test restoreLastSession, success`() =
|
||||
runTest {
|
||||
val user = user.copy(pin = null)
|
||||
coEvery { mockJellyfinServerDao.addOrUpdateUser(user) } returns user
|
||||
coEvery { mockJellyfinServerDao.getServer(serverId) } returns
|
||||
JellyfinServerUsers(server, listOf(user))
|
||||
every { mockMostRecentServerProvider.get() } returns
|
||||
MostRecentServer.from(CurrentUser(server, user))
|
||||
|
||||
val result = create().restoreLastSession()
|
||||
assertTrue(result is RestoredSession.Success)
|
||||
val current = (result as RestoredSession.Success).currentUser
|
||||
assertEquals(server, current.server)
|
||||
assertEquals(user, current.user)
|
||||
|
||||
verify(exactly = 1) {
|
||||
mockApiClient.update(
|
||||
baseUrl = server.url,
|
||||
accessToken = user.accessToken,
|
||||
clientInfo = any(),
|
||||
deviceInfo = any(),
|
||||
)
|
||||
}
|
||||
coVerify { mockMostRecentServerProvider.save(any()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test restoreLastSession, user protected`() =
|
||||
runTest {
|
||||
every { mockMostRecentServerProvider.get() } returns
|
||||
MostRecentServer.ServerAndUser(serverId, server.url, userId, "token")
|
||||
|
||||
val result = create().restoreLastSession()
|
||||
assertTrue(result is RestoredSession.ServerOnly)
|
||||
val current = (result as RestoredSession.ServerOnly)
|
||||
assertEquals(server, current.server)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test restoreLastSession, server only`() =
|
||||
runTest {
|
||||
every { mockMostRecentServerProvider.get() } returns
|
||||
MostRecentServer.Server(server.id, server.url)
|
||||
|
||||
val result = create().restoreLastSession()
|
||||
assertTrue(result is RestoredSession.ServerOnly)
|
||||
val current = (result as RestoredSession.ServerOnly)
|
||||
assertEquals(server, current.server)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Test restoreLastSession, nothing to restore`() =
|
||||
runTest {
|
||||
every { mockMostRecentServerProvider.get() } returns MostRecentServer.None
|
||||
|
||||
val result = create().restoreLastSession()
|
||||
assertTrue(result is RestoredSession.None)
|
||||
}
|
||||
}
|
||||
|
||||
class TestMostRecentServerProvider : MostRecentServerProvider {
|
||||
var mostRecentServer: MostRecentServer = MostRecentServer.None
|
||||
|
||||
override fun get(): MostRecentServer = mostRecentServer
|
||||
|
||||
override suspend fun save(current: CurrentUser) {
|
||||
mostRecentServer =
|
||||
if (current.user.accessToken.isNotNullOrBlank()) {
|
||||
MostRecentServer.ServerAndUser(
|
||||
current.server.id,
|
||||
current.server.url,
|
||||
current.user.id,
|
||||
current.user.accessToken,
|
||||
)
|
||||
} else {
|
||||
MostRecentServer.Server(
|
||||
current.server.id,
|
||||
current.server.url,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun clear() {
|
||||
mostRecentServer = MostRecentServer.None
|
||||
}
|
||||
|
||||
override suspend fun clearUser() {
|
||||
when (val s = mostRecentServer) {
|
||||
MostRecentServer.None -> Unit
|
||||
is MostRecentServer.Server -> Unit
|
||||
is MostRecentServer.ServerAndUser -> MostRecentServer.Server(s.serverId, s.serverUrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@ import androidx.work.Data
|
|||
import androidx.work.ListenableWorker
|
||||
import androidx.work.WorkerParameters
|
||||
import com.github.damontecres.wholphin.data.CurrentUser
|
||||
import com.github.damontecres.wholphin.data.RestoredSession
|
||||
import com.github.damontecres.wholphin.data.ServerRepository
|
||||
import com.github.damontecres.wholphin.preferences.AppPreferences
|
||||
import com.github.damontecres.wholphin.test.currentUser
|
||||
import com.github.damontecres.wholphin.util.GetItemsRequestHandler
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
|
|
@ -113,16 +115,16 @@ class SuggestionsWorkerTest {
|
|||
val mockUser = mockk<CurrentUser>()
|
||||
var restored = false
|
||||
every { mockServerRepository.current } answers { MutableStateFlow(if (restored) mockUser else null) }
|
||||
coEvery { mockServerRepository.restoreSession(testServerId, testUserId) } coAnswers {
|
||||
coEvery { mockServerRepository.restoreLastSession() } coAnswers {
|
||||
restored = true
|
||||
mockUser
|
||||
RestoredSession.Success(currentUser())
|
||||
}
|
||||
every { mockPreferences.data } returns flowOf(mockPrefs())
|
||||
coEvery { mockUserViewsApi.getUserViews(userId = testUserId) } returns mockQueryResult()
|
||||
|
||||
val result = createWorker().doWork()
|
||||
|
||||
coVerify { mockServerRepository.restoreSession(testServerId, testUserId) }
|
||||
coVerify { mockServerRepository.restoreLastSession() }
|
||||
assertEquals(ListenableWorker.Result.success(), result)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import com.github.damontecres.wholphin.data.ItemPlaybackDao
|
|||
import com.github.damontecres.wholphin.data.JellyfinServerDao
|
||||
import com.github.damontecres.wholphin.data.LibraryDisplayInfoDao
|
||||
import com.github.damontecres.wholphin.data.Migrations
|
||||
import com.github.damontecres.wholphin.data.MostRecentServerProvider
|
||||
import com.github.damontecres.wholphin.data.PlaybackEffectDao
|
||||
import com.github.damontecres.wholphin.data.PlaybackLanguageChoiceDao
|
||||
import com.github.damontecres.wholphin.data.RememberedTabDao
|
||||
|
|
@ -26,6 +27,7 @@ import com.github.damontecres.wholphin.data.ServerRepository
|
|||
import com.github.damontecres.wholphin.preferences.AppPreferences
|
||||
import com.github.damontecres.wholphin.preferences.AppPreferencesSerializer
|
||||
import com.github.damontecres.wholphin.services.SeerrApi
|
||||
import com.github.damontecres.wholphin.services.TestMostRecentServerProvider
|
||||
import com.github.damontecres.wholphin.services.hilt.AppModule
|
||||
import com.github.damontecres.wholphin.services.hilt.AuthOkHttpClient
|
||||
import com.github.damontecres.wholphin.services.hilt.DatabaseModule
|
||||
|
|
@ -201,6 +203,10 @@ object TestModule {
|
|||
fun seerrApi(
|
||||
@StandardOkHttpClient okHttpClient: OkHttpClient,
|
||||
): SeerrApi = mockk()
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun mostRecentServerProvider(): MostRecentServerProvider = TestMostRecentServerProvider()
|
||||
}
|
||||
|
||||
@Module
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue