test(ble): fix BleRadioTransportTest virtual-time budgets for 3 s settle

The settle-delay bump in 3bf1dd868 changed the iteration cadence but the
two virtual-time budgets in BleRadioTransportTest still assumed 1 s
settles, so the threshold/max-failure assertions fired before any
onDisconnect call had been made. Recompute the budgets (3 iterations now
finish at ~24 001 ms; 10 iterations at ~405 000 ms) and update the KDoc
breakdowns to match. Also picks up a trivial spotless reflow in
BleReconnectPolicy's KDoc.
This commit is contained in:
James Rich 2026-04-19 12:23:42 -05:00
parent d16b04382f
commit 6135166ea5
2 changed files with 12 additions and 12 deletions

View file

@ -156,8 +156,8 @@ class BleReconnectPolicy(
* Empirically validated against the meshtastic-client KMP SDK probes (Apr 2026): with a 1.5 s pause between
* disconnectreconnect cycles, 3/54/5 attempts failed mid-handshake (Stage1Draining timeouts) because the
* firmware had not yet released its GATT session from the previous cycle. With 5 s pause, success rate rose
* to 5/5 against a strong (-53 dBm) link. 3 s is a conservative compromise on Android, whose BLE stack is
* more mature than btleplug+CoreBluetooth, but the firmware-side cleanup constraint is the same.
* to 5/5 against a strong (-53 dBm) link. 3 s is a conservative compromise on Android, whose BLE stack is more
* mature than btleplug+CoreBluetooth, but the firmware-side cleanup constraint is the same.
*/
val DEFAULT_SETTLE_DELAY = 3.seconds
val DEFAULT_MIN_STABLE_CONNECTION = 5.seconds

View file

@ -95,10 +95,10 @@ class BleRadioTransportTest {
* [RadioInterfaceService.onDisconnect] must be called so the higher layers can react (e.g. start the device-sleep
* timeout in [MeshConnectionManagerImpl]).
*
* Virtual-time breakdown (DEFAULT_FAILURE_THRESHOLD = 3): t = 1 000 ms iteration 1 settle delay elapses,
* connectAndAwait throws, backoff 5 s starts t = 6 000 ms backoff ends t = 7 000 ms iteration 2 settle delay
* elapses, connectAndAwait throws, backoff 10 s starts t = 17 000 ms backoff ends t = 18 000 ms iteration 3
* settle delay elapses, connectAndAwait throws onDisconnect called
* Virtual-time breakdown (DEFAULT_FAILURE_THRESHOLD = 3, DEFAULT_SETTLE_DELAY = 3 s): t = 3 000 ms iteration 1
* settle delay elapses, connectAndAwait throws, backoff 5 s starts t = 8 000 ms backoff ends t = 11 000 ms
* iteration 2 settle delay elapses, connectAndAwait throws, backoff 10 s starts t = 21 000 ms backoff ends t = 24
* 000 ms iteration 3 settle delay elapses, connectAndAwait throws onDisconnect called
*/
@Test
fun `onDisconnect is called after DEFAULT_FAILURE_THRESHOLD consecutive failures`() = runTest {
@ -119,10 +119,10 @@ class BleRadioTransportTest {
)
bleTransport.start()
// Advance through exactly 3 failure iterations (≈18 001 ms virtual time).
// Advance through exactly 3 failure iterations (≈24 001 ms virtual time).
// The 4th iteration's backoff hasn't elapsed yet, so the coroutine is suspended
// and advanceTimeBy returns cleanly.
advanceTimeBy(18_001L)
advanceTimeBy(24_001L)
verify { service.onDisconnect(any(), any()) }
@ -134,9 +134,9 @@ class BleRadioTransportTest {
* After [BleReconnectPolicy.DEFAULT_MAX_FAILURES] (10) consecutive failures, the reconnect loop should stop and
* signal a permanent disconnect. This prevents infinite battery drain when the device is genuinely offline.
*
* Time budget for 10 failures with bonded device (no scan): Each iteration = 1s settle + connectAndAwait throw +
* backoff Backoffs: 5s, 10s, 20s, 40s, 60s, 60s, 60s, 60s, 60s, (exit at failure 10 before backoff) Total 10×1s
* settle + 5+10+20+40+60+60+60+60+60 = 10 + 375 = 385s 385_000ms We use a generous 400_000ms to cover any timing
* Time budget for 10 failures with bonded device (no scan): Each iteration = 3s settle + connectAndAwait throw +
* backoff Backoffs: 5s, 10s, 20s, 40s, 60s, 60s, 60s, 60s, 60s, (exit at failure 10 before backoff) Total 10×3s
* settle + 5+10+20+40+60+60+60+60+60 = 30 + 375 = 405s 405_000ms We use a generous 410_000ms to cover any timing
* variance.
*/
@Test
@ -159,7 +159,7 @@ class BleRadioTransportTest {
bleTransport.start()
// Advance enough time for all 10 failures to occur.
advanceTimeBy(400_001L)
advanceTimeBy(410_001L)
// Should have been called with isPermanent=true at least once (the final call).
verify { service.onDisconnect(isPermanent = true, errorMessage = any()) }