refactor(firmware): Inject dispatcher into BleOtaTransport (#4339)

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
James Rich 2026-01-27 15:01:39 -06:00 committed by GitHub
parent 76b7798642
commit e2328adca2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 17 additions and 7 deletions

View file

@ -17,7 +17,9 @@
package org.meshtastic.feature.firmware.ota
import co.touchlab.kermit.Logger
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.filterNotNull
@ -47,9 +49,13 @@ import kotlin.uuid.toKotlinUuid
* - OTA Characteristic (Write): 62ec0272-3ec5-11eb-b378-0242ac130005
* - TX Characteristic (Notify): 62ec0272-3ec5-11eb-b378-0242ac130003
*/
class BleOtaTransport(private val centralManager: CentralManager, private val address: String) : UnifiedOtaProtocol {
class BleOtaTransport(
private val centralManager: CentralManager,
private val address: String,
dispatcher: CoroutineDispatcher = Dispatchers.Default,
) : UnifiedOtaProtocol {
private val transportScope = CoroutineScope(SupervisorJob())
private val transportScope = CoroutineScope(SupervisorJob() + dispatcher)
private var peripheral: Peripheral? = null
private var otaCharacteristic: RemoteCharacteristic? = null

View file

@ -24,6 +24,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import no.nordicsemi.kotlin.ble.client.RemoteCharacteristic
import no.nordicsemi.kotlin.ble.client.RemoteService
@ -45,10 +46,11 @@ class BleOtaTransportMtuTest {
private val centralManager: CentralManager = mockk(relaxed = true)
private val address = "00:11:22:33:44:55"
private val transport = BleOtaTransport(centralManager, address)
private val testDispatcher = UnconfinedTestDispatcher()
private val transport = BleOtaTransport(centralManager, address, testDispatcher)
@Test
fun `connect requests MTU`() = runTest {
fun `connect requests MTU`() = runTest(testDispatcher) {
val peripheral: Peripheral = mockk(relaxed = true)
val otaChar: RemoteCharacteristic = mockk(relaxed = true)
val txChar: RemoteCharacteristic = mockk(relaxed = true)

View file

@ -23,6 +23,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import no.nordicsemi.kotlin.ble.client.RemoteCharacteristic
import no.nordicsemi.kotlin.ble.client.RemoteService
@ -44,10 +45,11 @@ class BleOtaTransportTest {
private val centralManager: CentralManager = mockk()
private val address = "00:11:22:33:44:55"
private val transport = BleOtaTransport(centralManager, address)
private val testDispatcher = UnconfinedTestDispatcher()
private val transport = BleOtaTransport(centralManager, address, testDispatcher)
@Test
fun `race condition check - response before waitForResponse`() = runTest {
fun `race condition check - response before waitForResponse`() = runTest(testDispatcher) {
val peripheral: Peripheral = mockk(relaxed = true)
val otaChar: RemoteCharacteristic = mockk(relaxed = true)
val txChar: RemoteCharacteristic = mockk(relaxed = true)
@ -70,7 +72,7 @@ class BleOtaTransportTest {
coEvery { centralManager.connect(any(), any()) } returns Unit
val notificationFlow = MutableSharedFlow<ByteArray>()
val notificationFlow = MutableSharedFlow<ByteArray>(extraBufferCapacity = 1)
every { txChar.subscribe() } returns notificationFlow
// Connect