feat: separate session and credential actions
This commit is contained in:
+128
@@ -12,6 +12,7 @@ import com.flagship.abox.manager.domain.ProviderType
|
||||
import com.flagship.abox.manager.domain.SessionCoordinator
|
||||
import com.flagship.abox.manager.domain.SessionGateway
|
||||
import com.flagship.abox.manager.domain.Session
|
||||
import com.flagship.abox.manager.domain.SessionValidity
|
||||
import com.flagship.abox.manager.domain.Username
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.test.runTest
|
||||
@@ -133,6 +134,101 @@ class SessionCoordinatorTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun endActiveSessionKeepsAboxCredentials() = runTest {
|
||||
val fixture = Fixture()
|
||||
fixture.coordinator.selectProvider(remoteProfile)
|
||||
fixture.coordinator.login(
|
||||
remoteProfile.id,
|
||||
credentials,
|
||||
rememberUsername = true,
|
||||
autoLogin = true,
|
||||
)
|
||||
|
||||
val result = fixture.coordinator.endActiveSession()
|
||||
|
||||
assertTrue(result is DomainResult.Success)
|
||||
assertEquals(remoteProfile, fixture.profiles.activeProfile())
|
||||
assertNull(fixture.remote.observeSession(remoteProfile.id).first())
|
||||
assertEquals(
|
||||
credentials,
|
||||
(fixture.credentials.loadCredentials(remoteProfile.id) as DomainResult.Success).value,
|
||||
)
|
||||
assertTrue(fixture.profiles.loginPreferences(remoteProfile.id).autoLoginEnabled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun forgetSavedCredentialsDisablesAutoLoginAndKeepsSessionStateExplicit() = runTest {
|
||||
val fixture = Fixture()
|
||||
fixture.coordinator.selectProvider(remoteProfile)
|
||||
fixture.coordinator.login(
|
||||
remoteProfile.id,
|
||||
credentials,
|
||||
rememberUsername = true,
|
||||
autoLogin = true,
|
||||
)
|
||||
|
||||
val result = fixture.coordinator.forgetSavedCredentials()
|
||||
|
||||
assertTrue(result is DomainResult.Success)
|
||||
assertEquals(remoteProfile, fixture.profiles.activeProfile())
|
||||
assertEquals(
|
||||
remoteProfile.id,
|
||||
fixture.remote.observeSession(remoteProfile.id).first()?.profileId,
|
||||
)
|
||||
assertNull(
|
||||
(fixture.credentials.loadCredentials(remoteProfile.id) as DomainResult.Success).value,
|
||||
)
|
||||
val preferences = fixture.profiles.loginPreferences(remoteProfile.id)
|
||||
assertEquals(credentials.username, preferences.rememberedUsername)
|
||||
assertTrue(!preferences.autoLoginEnabled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun switchProviderClearsActiveProfileAfterGatewayLogout() = runTest {
|
||||
val profiles = FakeProviderProfileStore()
|
||||
val remote = RecordingSessionGateway(profiles)
|
||||
val coordinator = SessionCoordinator(
|
||||
profileStore = profiles,
|
||||
credentialStore = FakeCredentialStore(),
|
||||
remoteGateway = remote,
|
||||
localGateway = FakeLocalSessionGateway(),
|
||||
)
|
||||
coordinator.selectProvider(remoteProfile)
|
||||
remote.login(remoteProfile.id, credentials)
|
||||
|
||||
val result = coordinator.switchProvider()
|
||||
|
||||
assertTrue(result is DomainResult.Success)
|
||||
assertEquals(remoteProfile.id, remote.activeProfileAtLogout)
|
||||
assertNull(profiles.activeProfile())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun validateActiveSessionDoesNotRelogin() = runTest {
|
||||
val remote = CountingSessionGateway()
|
||||
val credentialsStore = CountingCredentialStore()
|
||||
val profiles = FakeProviderProfileStore()
|
||||
val coordinator = SessionCoordinator(
|
||||
profileStore = profiles,
|
||||
credentialStore = credentialsStore,
|
||||
remoteGateway = remote,
|
||||
localGateway = FakeLocalSessionGateway(),
|
||||
)
|
||||
profiles.saveProfile(remoteProfile)
|
||||
profiles.setActiveProfile(remoteProfile.id)
|
||||
remote.setValidationResult(
|
||||
remoteProfile.id,
|
||||
DomainResult.Success(SessionValidity.INVALID),
|
||||
)
|
||||
|
||||
val result = coordinator.validateActiveSession()
|
||||
|
||||
assertEquals(DomainResult.Success(SessionValidity.INVALID), result)
|
||||
assertEquals(0, remote.loginCalls)
|
||||
assertEquals(0, credentialsStore.loadCalls)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun authenticationFailureDuringRecoveryClearsSavedCredential() = runTest {
|
||||
val fixture = Fixture()
|
||||
@@ -189,6 +285,18 @@ class SessionCoordinatorTest {
|
||||
assertTrue(!fixture.profiles.loginPreferences(remoteProfile.id).autoLoginEnabled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun endActiveSessionClearsLocalActiveProfile() = runTest {
|
||||
val fixture = Fixture()
|
||||
fixture.coordinator.selectProvider(localProfile)
|
||||
|
||||
val result = fixture.coordinator.endActiveSession()
|
||||
|
||||
assertTrue(result is DomainResult.Success)
|
||||
assertNull(fixture.profiles.activeProfile())
|
||||
assertNull(fixture.local.observeSession(localProfile.id).first())
|
||||
}
|
||||
|
||||
private class Fixture {
|
||||
val profiles = FakeProviderProfileStore()
|
||||
val credentials = FakeCredentialStore()
|
||||
@@ -197,6 +305,19 @@ class SessionCoordinatorTest {
|
||||
val coordinator = SessionCoordinator(profiles, credentials, remote, local)
|
||||
}
|
||||
|
||||
private class RecordingSessionGateway(
|
||||
private val profileStore: FakeProviderProfileStore,
|
||||
private val delegate: FakeSessionGateway = FakeSessionGateway(),
|
||||
) : SessionGateway by delegate {
|
||||
var activeProfileAtLogout: ProviderProfileId? = null
|
||||
private set
|
||||
|
||||
override suspend fun logout(profileId: ProviderProfileId): DomainResult<Unit> {
|
||||
activeProfileAtLogout = profileStore.activeProfile()?.id
|
||||
return delegate.logout(profileId)
|
||||
}
|
||||
}
|
||||
|
||||
private class CountingSessionGateway(
|
||||
private val delegate: FakeSessionGateway = FakeSessionGateway(),
|
||||
) : SessionGateway by delegate {
|
||||
@@ -214,6 +335,13 @@ class SessionCoordinatorTest {
|
||||
fun failLogin(profileId: ProviderProfileId, error: DomainError) {
|
||||
delegate.failLogin(profileId, error)
|
||||
}
|
||||
|
||||
fun setValidationResult(
|
||||
profileId: ProviderProfileId,
|
||||
result: DomainResult<SessionValidity>,
|
||||
) {
|
||||
delegate.setValidationResult(profileId, result)
|
||||
}
|
||||
}
|
||||
|
||||
private class CountingCredentialStore(
|
||||
|
||||
Reference in New Issue
Block a user