Instrumented test doubles for MondoNode plugin development.
Provides fake implementations of every SDK callback interface and the host interfaces, so you can test your plugin service logic in instrumented tests (androidTest) without a running host app.
// build.gradle.kts
dependencies {
implementation("com.systemhalted:mondonode-sdk:<version>")
androidTestImplementation("com.systemhalted:mondonode-sdk-testing:<version>")
}Both artifacts share the same version number. Replace <version> with the latest release
from Maven Central.
Extract your plugin's computation into a stateless Kotlin object (no Android imports).
Test it directly with JUnit from src/test/ — no device required.
// MyTransformerTransforms.kt — pure Kotlin, no Android
object MyTransformerTransforms {
fun process(input: String, params: Map<String, String>): Map<String, String> {
val result = /* your logic */
return mapOf("value" to result)
}
}
// src/test/MyTransformerTransformsTest.kt
class MyTransformerTransformsTest {
@Test fun `reverse returns reversed string`() {
val out = MyTransformerTransforms.process("hello", emptyMap())
assertEquals("olleh", out["value"])
}
}The official MondoNode transformer APKs all follow this pattern (see
mondonode-transformer-* repositories for examples).
Test your *Service class end-to-end on a device or emulator using the fakes
provided here. These verify AIDL wiring, threading behaviour, and Binder lifecycle
in addition to business logic.
// src/androidTest/MyTransformerServiceTest.kt
@RunWith(AndroidJUnit4::class)
class MyTransformerServiceTest {
@get:Rule
val serviceRule = ServiceTestRule()
@Test
fun `transform reverse returns reversed string`() {
val binder = serviceRule.bindService(
Intent(ApplicationProvider.getApplicationContext(), MyTransformerService::class.java)
)
val plugin = ITransformerPlugin.Stub.asInterface(binder)
val cb = FakeTransformCallback()
plugin.transform("""{"value":"hello"}""", """{"capability_id":"reverse"}""", cb)
assertTrue(cb.awaitResult())
assertTrue(cb.succeeded)
assertEquals("olleh", JSONObject(cb.result!!).getString("value"))
}
}| Class | Fakes | Use for |
|---|---|---|
FakeDataCallback |
IDataCallback |
Monitoring plugin metric delivery |
FakeTransformCallback |
ITransformCallback |
Transformer plugin results |
FakeOutputCallback |
IOutputCallback |
Output plugin write outcomes |
FakeRouteCallback |
IRouteCallback |
Router plugin routing decisions |
FakeStorageWriteCallback |
IStorageWriteCallback |
Storage plugin stream writes |
FakeStorageQueryCallback |
IStorageQueryCallback |
Storage plugin query results |
FakeStorageStreamCallback |
IStorageStreamCallback |
Storage plugin stream data |
FakeManagementCallback |
IManagementCallback |
Management app event delivery |
FakePluginDependencyCallback |
IPluginDependencyCallback |
Cross-plugin dependency results |
FakePluginHostBridge |
IPluginHostBridge |
Injecting mock cross-plugin calls |
FakeMondoNodeHost |
IMondoNodeHost |
Driving management plugin services |
FakeEventCallback |
IEventCallback |
Event plugin event/error/stopped delivery |
FakeEventPlugin |
IEventPlugin |
Driving host code that activates event sources |
All callback fakes provide an awaitResult() / awaitEvent() / awaitEnd() helper that
blocks up to a configurable timeout (default 5 s), returning false on timeout.
FakeMondoNodeHost drives ManagementServiceBase subclasses without a real host process.
Configure its response properties, call myManagementBinder.onHostConnected(host), then
use the fire* helpers to push events:
val host = FakeMondoNodeHost()
host.connectedPluginsJson = Json.encodeToString(listOf(myManifest))
val cb = FakeManagementCallback(expectedEvents = 1)
host.register(cb)
myManagementBinder.onHostConnected(host)
host.fireMetricReceived("com.example.plugin", metricJson)
assertTrue(cb.awaitEvent())
assertEquals(1, cb.receivedMetrics.size)Inject a FakePluginHostBridge to control cross-plugin dependency calls in monitoring
plugin tests:
val bridge = FakePluginHostBridge()
bridge.setAvailable("com.example.dep")
bridge.onRequestExecute("com.example.dep") { _, cb ->
cb.onResult("com.example.dep", """{"values":{"rtt":"12"}}""")
}
myPluginBinder.setHostBridge(bridge)MIT License — Copyright (c) 2025 SystemHalted