Fix bizzare NPE in context generation for DeviceClient.
Add test for remote client
This commit is contained in:
parent
b1121d61cb
commit
8bd9bcc6a6
@ -12,6 +12,7 @@ description = """
|
|||||||
kscience {
|
kscience {
|
||||||
jvm()
|
jvm()
|
||||||
js()
|
js()
|
||||||
|
useCoroutines("1.8.0")
|
||||||
useSerialization {
|
useSerialization {
|
||||||
json()
|
json()
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package space.kscience.controls.client
|
package space.kscience.controls.client
|
||||||
|
|
||||||
import com.benasher44.uuid.uuid4
|
import com.benasher44.uuid.uuid4
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.newCoroutineContext
|
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import space.kscience.controls.api.*
|
import space.kscience.controls.api.*
|
||||||
@ -28,8 +28,8 @@ public class DeviceClient(
|
|||||||
private val send: suspend (DeviceMessage) -> Unit,
|
private val send: suspend (DeviceMessage) -> Unit,
|
||||||
) : CachingDevice {
|
) : CachingDevice {
|
||||||
|
|
||||||
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
|
|
||||||
override val coroutineContext: CoroutineContext = newCoroutineContext(context.coroutineContext)
|
override val coroutineContext: CoroutineContext = context.coroutineContext + Job(context.coroutineContext[Job])
|
||||||
|
|
||||||
private val mutex = Mutex()
|
private val mutex = Mutex()
|
||||||
|
|
||||||
|
@ -0,0 +1,87 @@
|
|||||||
|
package space.kscience.controls.client
|
||||||
|
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import space.kscience.controls.api.Device
|
||||||
|
import space.kscience.controls.manager.DeviceManager
|
||||||
|
import space.kscience.controls.manager.install
|
||||||
|
import space.kscience.controls.manager.respondMessage
|
||||||
|
import space.kscience.controls.spec.*
|
||||||
|
import space.kscience.dataforge.context.Context
|
||||||
|
import space.kscience.dataforge.context.Factory
|
||||||
|
import space.kscience.dataforge.context.request
|
||||||
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.meta.get
|
||||||
|
import space.kscience.dataforge.meta.int
|
||||||
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.magix.api.MagixEndpoint
|
||||||
|
import space.kscience.magix.api.MagixMessage
|
||||||
|
import space.kscience.magix.api.MagixMessageFilter
|
||||||
|
import kotlin.random.Random
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertContains
|
||||||
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
|
|
||||||
|
public suspend fun <T> Device.readUnsafe(propertySpec: DevicePropertySpec<*, T>): T =
|
||||||
|
propertySpec.converter.metaToObject(readProperty(propertySpec.name)) ?: error("Property read result is not valid")
|
||||||
|
|
||||||
|
internal class RemoteDeviceConnect {
|
||||||
|
|
||||||
|
class TestDevice(context: Context, meta: Meta) : DeviceBySpec<TestDevice>(TestDevice, context, meta) {
|
||||||
|
private val rng = Random(meta["seed"].int ?: 0)
|
||||||
|
|
||||||
|
private val randomValue get() = rng.nextDouble()
|
||||||
|
|
||||||
|
companion object : DeviceSpec<TestDevice>(), Factory<TestDevice> {
|
||||||
|
|
||||||
|
override fun build(context: Context, meta: Meta): TestDevice = TestDevice(context, meta)
|
||||||
|
|
||||||
|
val value by doubleProperty { randomValue }
|
||||||
|
|
||||||
|
override suspend fun TestDevice.onOpen() {
|
||||||
|
doRecurring((meta["delay"].int ?: 10).milliseconds) {
|
||||||
|
read(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun wrapper() = runTest {
|
||||||
|
val context = Context {
|
||||||
|
plugin(DeviceManager)
|
||||||
|
}
|
||||||
|
|
||||||
|
val device = context.request(DeviceManager).install("test", TestDevice)
|
||||||
|
|
||||||
|
val virtualMagixEndpoint = object : MagixEndpoint {
|
||||||
|
|
||||||
|
|
||||||
|
override fun subscribe(filter: MagixMessageFilter): Flow<MagixMessage> = device.messageFlow.map {
|
||||||
|
MagixMessage(
|
||||||
|
format = DeviceManager.magixFormat.defaultFormat,
|
||||||
|
payload = MagixEndpoint.magixJson.encodeToJsonElement(DeviceManager.magixFormat.serializer, it),
|
||||||
|
sourceEndpoint = "test",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun broadcast(message: MagixMessage) {
|
||||||
|
device.respondMessage(
|
||||||
|
Name.EMPTY,
|
||||||
|
Json.decodeFromJsonElement(DeviceManager.magixFormat.serializer, message.payload)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val remoteDevice = virtualMagixEndpoint.remoteDevice(context, "test", Name.EMPTY)
|
||||||
|
|
||||||
|
assertContains(0.0..1.0, remoteDevice.readUnsafe(TestDevice.value))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user