diff --git a/lib/services/path_history_service.dart b/lib/services/path_history_service.dart index bce4975..c3fed04 100644 --- a/lib/services/path_history_service.dart +++ b/lib/services/path_history_service.dart @@ -113,15 +113,16 @@ class PathHistoryService { await initialize(); await recordLearnedPath(contact); + if (contact.routeHasPath && contact.routeHopCount > 0) { + return PathSelection( + mode: PathSelectionMode.directCurrent, + pathBytes: Uint8List.fromList(contact.routePathBytes), + hopCount: contact.routeHopCount, + hashSize: contact.routeHashSize, + ); + } + if (!autoRouteRotationEnabled) { - if (contact.routeHasPath && contact.routeHopCount > 0) { - return PathSelection( - mode: PathSelectionMode.directCurrent, - pathBytes: Uint8List.fromList(contact.routePathBytes), - hopCount: contact.routeHopCount, - hashSize: contact.routeHashSize, - ); - } return PathSelection.flood(); } diff --git a/test/services/path_history_service_test.dart b/test/services/path_history_service_test.dart index fa8ca9c..d7fc26e 100644 --- a/test/services/path_history_service_test.dart +++ b/test/services/path_history_service_test.dart @@ -31,6 +31,21 @@ Contact _buildContact({ ); } +Contact _buildContactWithoutRoute({required int seed}) { + return Contact( + publicKey: Uint8List.fromList(List.generate(32, (i) => i + seed)), + type: ContactType.chat, + flags: 0, + outPathLen: -1, + outPath: Uint8List(0), + advName: 'Contact $seed', + lastAdvert: DateTime.now().millisecondsSinceEpoch ~/ 1000, + advLat: 0, + advLon: 0, + lastMod: DateTime.now().millisecondsSinceEpoch ~/ 1000, + ); +} + void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -40,12 +55,7 @@ void main() { test('auto rotation ranks best paths before flood', () async { final service = PathHistoryService(); - final contact = _buildContact( - seed: 0, - pathBytes: [0xAA, 0xBB], - hopCount: 2, - hashSize: 1, - ); + final contact = _buildContactWithoutRoute(seed: 0); final best = PathSelection( mode: PathSelectionMode.directHistorical, pathBytes: Uint8List.fromList([0xAA, 0xBB]), @@ -105,20 +115,43 @@ void main() { expect(secondPick.mode, PathSelectionMode.flood); }); + test( + 'current learned route is reused first even with rotation enabled', + () async { + final service = PathHistoryService(); + final contact = _buildContact( + seed: 9, + pathBytes: [0xAA, 0xBB, 0xCC], + hopCount: 1, + hashSize: 3, + ); + + await service.initialize(); + await service.recordPathResult( + contact.publicKeyHex, + PathSelection( + mode: PathSelectionMode.directHistorical, + pathBytes: Uint8List.fromList([0x11, 0x22, 0x33]), + hopCount: 1, + hashSize: 3, + ), + success: true, + roundTripTimeMs: 90, + ); + + final selection = await service.getSelectionForContact( + contact, + autoRouteRotationEnabled: true, + ); + + expect(selection.mode, PathSelectionMode.directCurrent); + expect(selection.canonicalPath, 'AABBCC'); + }, + ); + test('no history falls back to flood', () async { final service = PathHistoryService(); - final contact = Contact( - publicKey: Uint8List.fromList(List.generate(32, (i) => i)), - type: ContactType.chat, - flags: 0, - outPathLen: -1, - outPath: Uint8List(0), - advName: 'No Route', - lastAdvert: DateTime.now().millisecondsSinceEpoch ~/ 1000, - advLat: 0, - advLon: 0, - lastMod: DateTime.now().millisecondsSinceEpoch ~/ 1000, - ); + final contact = _buildContactWithoutRoute(seed: 0); final selection = await service.getSelectionForContact( contact,