113 lines
3.5 KiB
Dart
113 lines
3.5 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:ground_suite/core/observations/observed_event.dart';
|
|
import 'package:ground_suite/core/observations/vehicle_data_port.dart';
|
|
import 'package:ground_suite/core/observations/vehicle_data_update.dart';
|
|
import 'package:ground_suite/features/observability/presentation/observability_controller.dart';
|
|
|
|
void main() {
|
|
test('coalesces rapid critical accessibility announcements', () async {
|
|
final port = _ControlledDataPort();
|
|
final container = ProviderContainer(
|
|
overrides: [vehicleDataPortProvider.overrideWithValue(port)],
|
|
);
|
|
addTearDown(container.dispose);
|
|
|
|
container.read(observabilityControllerProvider);
|
|
await Future<void>.delayed(Duration.zero);
|
|
|
|
port.events.add(
|
|
ObservationReceived(
|
|
ErrorEvent(
|
|
receivedAt: DateTime.utc(2026, 8, 10),
|
|
path: 'kaptan_drivers::lidar_lite_v3::error::Error::TransferFault',
|
|
),
|
|
),
|
|
);
|
|
await Future<void>.delayed(Duration.zero);
|
|
|
|
expect(
|
|
container.read(observabilityControllerProvider).accessibilityAnnouncement,
|
|
'Error received: kaptan_drivers::lidar_lite_v3::error::Error::TransferFault',
|
|
);
|
|
|
|
port.events.add(
|
|
ObservationReceived(
|
|
ShutdownEvent(
|
|
receivedAt: DateTime.utc(2026, 8, 10, 0, 0, 1),
|
|
reason: KaptanShutdownReason.safety,
|
|
),
|
|
),
|
|
);
|
|
await Future<void>.delayed(Duration.zero);
|
|
|
|
final state = container.read(observabilityControllerProvider);
|
|
expect(state.accessibilityAnnouncement, isNull);
|
|
expect(state.coalescedAlertCount, 1);
|
|
});
|
|
|
|
test(
|
|
'retains expected parser and semantic drops without ending observation',
|
|
() async {
|
|
final port = _ControlledDataPort();
|
|
final container = ProviderContainer(
|
|
overrides: [vehicleDataPortProvider.overrideWithValue(port)],
|
|
);
|
|
addTearDown(container.dispose);
|
|
|
|
container.read(observabilityControllerProvider);
|
|
await Future<void>.delayed(Duration.zero);
|
|
|
|
port.events.add(
|
|
const ObservationDropped(kind: ObservationDropKind.parser, count: 2),
|
|
);
|
|
port.events.add(
|
|
const ObservationDropped(kind: ObservationDropKind.semantic),
|
|
);
|
|
await Future<void>.delayed(Duration.zero);
|
|
|
|
final state = container.read(observabilityControllerProvider);
|
|
expect(state.status, ObservationStatus.receiving);
|
|
expect(state.parserDropCount, 2);
|
|
expect(state.semanticDropCount, 1);
|
|
},
|
|
);
|
|
|
|
test('treats a transport stream failure as a disconnected link', () async {
|
|
final port = _ControlledDataPort();
|
|
final container = ProviderContainer(
|
|
overrides: [vehicleDataPortProvider.overrideWithValue(port)],
|
|
);
|
|
addTearDown(container.dispose);
|
|
|
|
container.read(observabilityControllerProvider);
|
|
await Future<void>.delayed(Duration.zero);
|
|
|
|
port.events.addError(StateError('serial endpoint closed'));
|
|
await Future<void>.delayed(Duration.zero);
|
|
|
|
final state = container.read(observabilityControllerProvider);
|
|
expect(state.status, ObservationStatus.disconnected);
|
|
expect(state.parserDropCount, 0);
|
|
expect(state.semanticDropCount, 0);
|
|
});
|
|
}
|
|
|
|
class _ControlledDataPort implements VehicleDataPort {
|
|
final events = StreamController<VehicleDataUpdate>();
|
|
|
|
@override
|
|
bool get isReplay => false;
|
|
|
|
@override
|
|
String get label => 'Test transport';
|
|
|
|
@override
|
|
Future<void> close() => events.close();
|
|
|
|
@override
|
|
Stream<VehicleDataUpdate> observe() => events.stream;
|
|
}
|