feat(service): Overhaul MeshServiceExample (#4263)

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
James Rich 2026-01-19 18:58:26 -06:00 committed by GitHub
parent 8e4541c147
commit 4e2c429180
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 1156 additions and 236 deletions

View file

@ -38,6 +38,8 @@ plugins { alias(libs.plugins.meshtastic.android.library) }
configure<LibraryExtension> {
buildFeatures { aidl = true }
namespace = "org.meshtastic.core.service"
testOptions { unitTests.isReturnDefaultValues = true }
}
dependencies {

View file

@ -0,0 +1,123 @@
/*
* Copyright (c) 2025-2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.meshtastic.core.service.testing
import org.meshtastic.core.model.DataPacket
import org.meshtastic.core.model.MeshUser
import org.meshtastic.core.model.MyNodeInfo
import org.meshtastic.core.model.NodeInfo
import org.meshtastic.core.model.Position
import org.meshtastic.core.service.IMeshService
/**
* A fake implementation of [IMeshService] for testing purposes. This also serves as a contract verification: if the
* AIDL changes, this class will fail to compile.
*
* Developers can use this to mock the MeshService in their unit tests.
*/
@Suppress("TooManyFunctions", "EmptyFunctionBlock")
open class FakeIMeshService : IMeshService.Stub() {
override fun subscribeReceiver(packageName: String?, receiverName: String?) {}
override fun setOwner(user: MeshUser?) {}
override fun setRemoteOwner(requestId: Int, payload: ByteArray?) {}
override fun getRemoteOwner(requestId: Int, destNum: Int) {}
override fun getMyId(): String = "fake_id"
override fun getPacketId(): Int = 1234
override fun send(packet: DataPacket?) {}
override fun getNodes(): List<NodeInfo> = emptyList()
override fun getConfig(): ByteArray = byteArrayOf()
override fun setConfig(payload: ByteArray?) {}
override fun setRemoteConfig(requestId: Int, destNum: Int, payload: ByteArray?) {}
override fun getRemoteConfig(requestId: Int, destNum: Int, configTypeValue: Int) {}
override fun setModuleConfig(requestId: Int, destNum: Int, payload: ByteArray?) {}
override fun getModuleConfig(requestId: Int, destNum: Int, moduleConfigTypeValue: Int) {}
override fun setRingtone(destNum: Int, ringtone: String?) {}
override fun getRingtone(requestId: Int, destNum: Int) {}
override fun setCannedMessages(destNum: Int, messages: String?) {}
override fun getCannedMessages(requestId: Int, destNum: Int) {}
override fun setChannel(payload: ByteArray?) {}
override fun setRemoteChannel(requestId: Int, destNum: Int, payload: ByteArray?) {}
override fun getRemoteChannel(requestId: Int, destNum: Int, channelIndex: Int) {}
override fun beginEditSettings() {}
override fun commitEditSettings() {}
override fun removeByNodenum(requestID: Int, nodeNum: Int) {}
override fun requestPosition(destNum: Int, position: Position?) {}
override fun setFixedPosition(destNum: Int, position: Position?) {}
override fun requestTraceroute(requestId: Int, destNum: Int) {}
override fun requestNeighborInfo(requestId: Int, destNum: Int) {}
override fun requestShutdown(requestId: Int, destNum: Int) {}
override fun requestReboot(requestId: Int, destNum: Int) {}
override fun requestFactoryReset(requestId: Int, destNum: Int) {}
override fun rebootToDfu() {}
override fun requestNodedbReset(requestId: Int, destNum: Int, preserveFavorites: Boolean) {}
override fun getChannelSet(): ByteArray = byteArrayOf()
override fun connectionState(): String = "CONNECTED"
override fun setDeviceAddress(deviceAddr: String?): Boolean = true
override fun getMyNodeInfo(): MyNodeInfo? = null
override fun startFirmwareUpdate() {}
override fun getUpdateStatus(): Int = 0
override fun startProvideLocation() {}
override fun stopProvideLocation() {}
override fun requestUserInfo(destNum: Int) {}
override fun getDeviceConnectionStatus(requestId: Int, destNum: Int) {}
override fun requestTelemetry(requestId: Int, destNum: Int, type: Int) {}
override fun requestRebootOta(requestId: Int, destNum: Int, mode: Int, hash: ByteArray?) {}
}

View file

@ -0,0 +1,120 @@
/*
* Copyright (c) 2025-2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.meshtastic.core.service
import org.meshtastic.core.model.DataPacket
import org.meshtastic.core.model.MeshUser
import org.meshtastic.core.model.MyNodeInfo
import org.meshtastic.core.model.NodeInfo
import org.meshtastic.core.model.Position
/**
* A fake implementation of [IMeshService] for testing purposes. This also serves as a contract verification: if the
* AIDL changes, this class will fail to compile.
*/
@Suppress("TooManyFunctions", "EmptyFunctionBlock")
open class FakeIMeshService : IMeshService.Stub() {
override fun subscribeReceiver(packageName: String?, receiverName: String?) {}
override fun setOwner(user: MeshUser?) {}
override fun setRemoteOwner(requestId: Int, payload: ByteArray?) {}
override fun getRemoteOwner(requestId: Int, destNum: Int) {}
override fun getMyId(): String = "fake_id"
override fun getPacketId(): Int = 1234
override fun send(packet: DataPacket?) {}
override fun getNodes(): List<NodeInfo> = emptyList()
override fun getConfig(): ByteArray = byteArrayOf()
override fun setConfig(payload: ByteArray?) {}
override fun setRemoteConfig(requestId: Int, destNum: Int, payload: ByteArray?) {}
override fun getRemoteConfig(requestId: Int, destNum: Int, configTypeValue: Int) {}
override fun setModuleConfig(requestId: Int, destNum: Int, payload: ByteArray?) {}
override fun getModuleConfig(requestId: Int, destNum: Int, moduleConfigTypeValue: Int) {}
override fun setRingtone(destNum: Int, ringtone: String?) {}
override fun getRingtone(requestId: Int, destNum: Int) {}
override fun setCannedMessages(destNum: Int, messages: String?) {}
override fun getCannedMessages(requestId: Int, destNum: Int) {}
override fun setChannel(payload: ByteArray?) {}
override fun setRemoteChannel(requestId: Int, destNum: Int, payload: ByteArray?) {}
override fun getRemoteChannel(requestId: Int, destNum: Int, channelIndex: Int) {}
override fun beginEditSettings() {}
override fun commitEditSettings() {}
override fun removeByNodenum(requestID: Int, nodeNum: Int) {}
override fun requestPosition(destNum: Int, position: Position?) {}
override fun setFixedPosition(destNum: Int, position: Position?) {}
override fun requestTraceroute(requestId: Int, destNum: Int) {}
override fun requestNeighborInfo(requestId: Int, destNum: Int) {}
override fun requestShutdown(requestId: Int, destNum: Int) {}
override fun requestReboot(requestId: Int, destNum: Int) {}
override fun requestFactoryReset(requestId: Int, destNum: Int) {}
override fun rebootToDfu() {}
override fun requestNodedbReset(requestId: Int, destNum: Int, preserveFavorites: Boolean) {}
override fun getChannelSet(): ByteArray = byteArrayOf()
override fun connectionState(): String = "CONNECTED"
override fun setDeviceAddress(deviceAddr: String?): Boolean = true
override fun getMyNodeInfo(): MyNodeInfo? = null
override fun startFirmwareUpdate() {}
override fun getUpdateStatus(): Int = 0
override fun startProvideLocation() {}
override fun stopProvideLocation() {}
override fun requestUserInfo(destNum: Int) {}
override fun getDeviceConnectionStatus(requestId: Int, destNum: Int) {}
override fun requestTelemetry(requestId: Int, destNum: Int, type: Int) {}
override fun requestRebootOta(requestId: Int, destNum: Int, mode: Int, hash: ByteArray?) {}
}

View file

@ -0,0 +1,37 @@
/*
* Copyright (c) 2025-2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.meshtastic.core.service
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Test
import org.meshtastic.core.service.testing.FakeIMeshService
/** Test to verify that the AIDL contract is correctly implemented by our test harness. */
class IMeshServiceContractTest {
@Test
fun `verify fake implementation matches aidl contract`() {
val service: IMeshService = FakeIMeshService()
// Basic verification that we can call methods and get expected results
assertEquals("fake_id", service.myId)
assertEquals(1234, service.packetId)
assertEquals("CONNECTED", service.connectionState())
assertNotNull(service.nodes)
}
}