fix(scene): address bot review on fake executor delays, time input validation, and localization
This commit is contained in:
+64
-27
@@ -25,6 +25,7 @@ import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
@@ -201,13 +202,17 @@ class FakeSceneRepository : SceneRepository {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fake [SceneExecutor] that drives the existing [SocketGateway] and [InfraredGateway] fakes.
|
||||
* Fake [SceneExecutor] that drives the existing [SocketGateway] and [InfraredGateway] fakes,
|
||||
* respecting delays and recording virtual remote / notification actions.
|
||||
*/
|
||||
class FakeSceneExecutor(
|
||||
private val socketGateway: SocketGateway,
|
||||
private val infraredGateway: InfraredGateway,
|
||||
private val delayDurationProvider: suspend (Long) -> Unit = { delay(it) },
|
||||
) : SceneExecutor {
|
||||
private val running = ConcurrentHashMap<SceneId, Boolean>()
|
||||
val executedRemoteButtons = mutableListOf<SceneAction.VirtualRemoteButton>()
|
||||
val sentNotifications = mutableListOf<SceneAction.Notification>()
|
||||
|
||||
override suspend fun execute(scene: Scene): DomainResult<SceneExecutionResult> {
|
||||
val alreadyRunning = running.putIfAbsent(scene.id, true) != null
|
||||
@@ -277,35 +282,51 @@ class FakeSceneExecutor(
|
||||
action: SceneAction,
|
||||
): SceneActionExecutionResult {
|
||||
return try {
|
||||
val result = when (action) {
|
||||
is SceneAction.SocketPower -> socketGateway.setPower(
|
||||
profileId = profileId,
|
||||
deviceName = action.deviceName,
|
||||
powerState = action.powerState,
|
||||
)
|
||||
when (action) {
|
||||
is SceneAction.SocketPower -> {
|
||||
val result = socketGateway.setPower(
|
||||
profileId = profileId,
|
||||
deviceName = action.deviceName,
|
||||
powerState = action.powerState,
|
||||
)
|
||||
toExecutionResult(action, result)
|
||||
}
|
||||
|
||||
is SceneAction.InfraredKey -> infraredGateway.sendKey(
|
||||
profileId = profileId,
|
||||
deviceName = action.deviceName,
|
||||
key = action.key,
|
||||
)
|
||||
is SceneAction.InfraredKey -> {
|
||||
val result = infraredGateway.sendKey(
|
||||
profileId = profileId,
|
||||
deviceName = action.deviceName,
|
||||
key = action.key,
|
||||
)
|
||||
toExecutionResult(action, result)
|
||||
}
|
||||
|
||||
is SceneAction.VirtualRemoteButton,
|
||||
is SceneAction.Delay,
|
||||
is SceneAction.Notification -> DomainResult.Success(Unit)
|
||||
}
|
||||
when (result) {
|
||||
is DomainResult.Success -> SceneActionExecutionResult(
|
||||
action = action,
|
||||
outcome = SceneActionOutcome.SUCCESS,
|
||||
error = null,
|
||||
)
|
||||
is SceneAction.VirtualRemoteButton -> {
|
||||
executedRemoteButtons.add(action)
|
||||
SceneActionExecutionResult(
|
||||
action = action,
|
||||
outcome = SceneActionOutcome.SUCCESS,
|
||||
error = null,
|
||||
)
|
||||
}
|
||||
|
||||
is DomainResult.Failure -> SceneActionExecutionResult(
|
||||
action = action,
|
||||
outcome = SceneActionOutcome.FAILURE,
|
||||
error = result.error,
|
||||
)
|
||||
is SceneAction.Delay -> {
|
||||
delayDurationProvider(action.durationSeconds * 1000L)
|
||||
SceneActionExecutionResult(
|
||||
action = action,
|
||||
outcome = SceneActionOutcome.SUCCESS,
|
||||
error = null,
|
||||
)
|
||||
}
|
||||
|
||||
is SceneAction.Notification -> {
|
||||
sentNotifications.add(action)
|
||||
SceneActionExecutionResult(
|
||||
action = action,
|
||||
outcome = SceneActionOutcome.SUCCESS,
|
||||
error = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (e: CancellationException) {
|
||||
throw e
|
||||
@@ -317,4 +338,20 @@ class FakeSceneExecutor(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun toExecutionResult(action: SceneAction, result: DomainResult<*>): SceneActionExecutionResult {
|
||||
return when (result) {
|
||||
is DomainResult.Success -> SceneActionExecutionResult(
|
||||
action = action,
|
||||
outcome = SceneActionOutcome.SUCCESS,
|
||||
error = null,
|
||||
)
|
||||
|
||||
is DomainResult.Failure -> SceneActionExecutionResult(
|
||||
action = action,
|
||||
outcome = SceneActionOutcome.FAILURE,
|
||||
error = result.error,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+40
@@ -116,6 +116,46 @@ class FakeSceneExecutorTest {
|
||||
assertFalse(executionResult.allSucceeded)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun executesDelayVirtualRemoteAndNotification() = runTest {
|
||||
val delays = mutableListOf<Long>()
|
||||
val executor = FakeSceneExecutor(
|
||||
socketGateway = FakeSocketGateway(),
|
||||
infraredGateway = FakeInfraredGateway(),
|
||||
delayDurationProvider = { delays.add(it) },
|
||||
)
|
||||
|
||||
val remoteAction = SceneAction.VirtualRemoteButton(
|
||||
id = SceneActionId("abox:btn-1"),
|
||||
profileId = profileId,
|
||||
remoteId = "remote-1",
|
||||
remoteDisplayName = "TV Remote",
|
||||
buttonId = "power",
|
||||
buttonDisplayName = "Power",
|
||||
)
|
||||
val delayAction = SceneAction.Delay(
|
||||
id = SceneActionId("abox:delay-1"),
|
||||
profileId = profileId,
|
||||
durationSeconds = 5,
|
||||
)
|
||||
val notificationAction = SceneAction.Notification(
|
||||
id = SceneActionId("abox:notif-1"),
|
||||
profileId = profileId,
|
||||
title = "Test Done",
|
||||
message = "Success",
|
||||
)
|
||||
|
||||
val scene = scene(listOf(remoteAction, delayAction, notificationAction))
|
||||
val result = executor.execute(scene)
|
||||
|
||||
assertTrue(result is DomainResult.Success)
|
||||
val execResult = (result as DomainResult.Success).value
|
||||
assertTrue(execResult.allSucceeded)
|
||||
assertEquals(listOf(5000L), delays)
|
||||
assertEquals(listOf(remoteAction), executor.executedRemoteButtons)
|
||||
assertEquals(listOf(notificationAction), executor.sentNotifications)
|
||||
}
|
||||
|
||||
private fun scene(actions: List<SceneAction>): Scene = Scene(
|
||||
id = SceneId("${profileId.value}:scene-test"),
|
||||
profileId = profileId,
|
||||
|
||||
Reference in New Issue
Block a user