Files
rely/test/features/sync/sync_auto_trigger_controller_test.dart
T
2026-02-15 23:31:34 +01:00

111 lines
3.3 KiB
Dart

import 'dart:async';
import 'package:flutter_test/flutter_test.dart';
import 'package:relationship_saver/features/sync/sync_auto_trigger_controller.dart';
import 'package:relationship_saver/features/sync/sync_coordinator.dart';
void main() {
test('triggers sync once and respects cooldown interval', () async {
int callCount = 0;
DateTime now = DateTime(2026, 2, 15, 12);
final SyncAutoTriggerController controller = SyncAutoTriggerController(
syncNow: () async {
callCount += 1;
return _result(success: true);
},
now: () => now,
minimumInterval: const Duration(seconds: 60),
);
final bool first = await controller.trigger();
final bool second = await controller.trigger();
now = now.add(const Duration(seconds: 61));
final bool third = await controller.trigger();
expect(first, isTrue);
expect(second, isFalse);
expect(third, isTrue);
expect(callCount, 2);
expect(controller.lastTriggeredAt, now);
});
test('applies backoff after failed sync attempts', () async {
DateTime now = DateTime(2026, 2, 15, 14);
bool shouldFail = true;
final SyncAutoTriggerController controller = SyncAutoTriggerController(
syncNow: () async => _result(success: !shouldFail),
now: () => now,
minimumInterval: const Duration(seconds: 60),
);
final bool first = await controller.trigger();
now = now.add(const Duration(seconds: 61));
final bool second = await controller.trigger();
now = now.add(const Duration(seconds: 60));
shouldFail = false;
final bool third = await controller.trigger();
expect(first, isTrue);
expect(second, isFalse);
expect(third, isTrue);
expect(controller.consecutiveFailures, 0);
});
test('does not run a second sync while a run is still in progress', () async {
int callCount = 0;
final Completer<void> completer = Completer<void>();
final SyncAutoTriggerController controller = SyncAutoTriggerController(
syncNow: () async {
callCount += 1;
await completer.future;
return _result(success: true);
},
now: DateTime.now,
minimumInterval: Duration.zero,
);
final Future<bool> first = controller.trigger();
for (int i = 0; i < 20 && !controller.isRunning; i += 1) {
await Future<void>.delayed(const Duration(milliseconds: 1));
}
expect(controller.isRunning, isTrue);
final bool second = await controller.trigger();
completer.complete();
final bool firstCompleted = await first;
expect(firstCompleted, isTrue);
expect(second, isFalse);
expect(callCount, 1);
});
test('skips trigger when connectivity gate denies run', () async {
int callCount = 0;
final SyncAutoTriggerController controller = SyncAutoTriggerController(
syncNow: () async {
callCount += 1;
return _result(success: true);
},
now: DateTime.now,
canTrigger: () async => false,
minimumInterval: Duration.zero,
);
final bool executed = await controller.trigger();
expect(executed, isFalse);
expect(callCount, 0);
});
}
SyncRunResult _result({required bool success}) {
return SyncRunResult(
success: success,
operation: 'sync',
message: success ? 'ok' : 'fail',
pendingAfter: 0,
);
}