feat: add provider login flow #4

Merged
KremeCN merged 26 commits from feat/provider-login into main 2026-08-25 01:59:00 +08:00
3 changed files with 51 additions and 7 deletions
Showing only changes of commit ae5bc871e8 - Show all commits
@@ -71,8 +71,10 @@ internal class RoutingSocketGateway(
is DomainResult.Success -> delegate(provider.value).setPower(profileId, deviceName, powerState)
}
private fun delegate(type: ProviderType): SocketGateway =
if (type == ProviderType.ABOX) real else simulation
private fun delegate(type: ProviderType): SocketGateway = when (type) {
ProviderType.ABOX -> real
ProviderType.LOCAL_EXPERIENCE -> simulation
}
}
/** Routes temperature/humidity operations by active provider, mirroring [RoutingSocketGateway]. */
@@ -91,8 +93,10 @@ internal class RoutingTemperatureHumidityGateway(
is DomainResult.Success -> delegate(provider.value).getReading(profileId, deviceName)
}
private fun delegate(type: ProviderType): TemperatureHumidityGateway =
if (type == ProviderType.ABOX) real else simulation
private fun delegate(type: ProviderType): TemperatureHumidityGateway = when (type) {
ProviderType.ABOX -> real
ProviderType.LOCAL_EXPERIENCE -> simulation
}
}
/** Routes infrared operations by active provider, mirroring [RoutingSocketGateway]. */
@@ -129,6 +133,8 @@ internal class RoutingInfraredGateway(
is DomainResult.Success -> delegate(provider.value).downloadCodes(profileId, codes)
}
private fun delegate(type: ProviderType): InfraredGateway =
if (type == ProviderType.ABOX) real else simulation
private fun delegate(type: ProviderType): InfraredGateway = when (type) {
ProviderType.ABOX -> real
ProviderType.LOCAL_EXPERIENCE -> simulation
}
}
@@ -7,6 +7,7 @@ import com.flagship.abox.manager.testing.fakes.FakeCredentialStore
import com.flagship.abox.manager.testing.fakes.FakeLocalSessionGateway
import com.flagship.abox.manager.testing.fakes.FakeProviderProfileStore
import com.flagship.abox.manager.testing.fakes.FakeSessionGateway
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
@@ -14,6 +15,7 @@ import org.junit.Assert.assertEquals
import org.junit.Rule
import org.junit.Test
@OptIn(ExperimentalCoroutinesApi::class)
class ProviderSelectionViewModelTest {
@get:Rule
val mainDispatcherRule = MainDispatcherRule()
@@ -153,11 +153,47 @@ class SessionCoordinatorTest {
assertTrue(!fixture.profiles.loginPreferences(remoteProfile.id).autoLoginEnabled)
}
@Test
fun switchingFromAuthenticatedAboxToLocalClearsRemoteSessionAndIsolatesState() = runTest {
val fixture = Fixture()
fixture.coordinator.selectProvider(remoteProfile)
val loginResult = fixture.coordinator.login(
remoteProfile.id,
credentials,
rememberUsername = true,
autoLogin = true,
)
val switchResult = fixture.coordinator.selectProvider(localProfile)
assertTrue(loginResult is DomainResult.Success)
assertTrue(switchResult is DomainResult.Success)
assertEquals(
localProfile.id,
(switchResult as DomainResult.Success).value?.profileId,
)
assertEquals(localProfile.id, fixture.profiles.activeProfile()?.id)
assertEquals(
localProfile.id,
fixture.coordinator.observeActiveSession().first()?.profileId,
)
assertNull(fixture.remote.observeSession(remoteProfile.id).first())
assertNull(fixture.remote.observeSession(localProfile.id).first())
assertEquals(
localProfile.id,
fixture.local.observeSession(localProfile.id).first()?.profileId,
)
assertNull(
(fixture.credentials.loadCredentials(remoteProfile.id) as DomainResult.Success).value,
)
assertTrue(!fixture.profiles.loginPreferences(remoteProfile.id).autoLoginEnabled)
}
private class Fixture {
val profiles = FakeProviderProfileStore()
val credentials = FakeCredentialStore()
val remote = FakeSessionGateway()
private val local = FakeLocalSessionGateway()
val local = FakeLocalSessionGateway()
val coordinator = SessionCoordinator(profiles, credentials, remote, local)
}