Skip to content

Commit

Permalink
Fix bugs in Simulator error handling and end of simulation (#515)
Browse files Browse the repository at this point in the history
  • Loading branch information
mkorbel1 authored Dec 17, 2024
1 parent ea893bb commit 2827e9c
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 20 deletions.
23 changes: 21 additions & 2 deletions lib/src/simulator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -395,11 +395,22 @@ abstract class Simulator {
_simExceptions.isEmpty &&
!_simulationEndRequested &&
(_maxSimTime < 0 || _currentTimestamp < _maxSimTime)) {
await tick();
try {
await tick();
} catch (_, __) {
// trigger the end of simulation if an error occurred
_simulationEndedCompleter.complete();

rethrow;
}
}

for (final err in _simExceptions) {
logger.severe(err.exception.toString(), err.exception, err.stackTrace);

// trigger the end of simulation if an error occurred
_simulationEndedCompleter.complete();

throw err.exception;
}

Expand All @@ -409,7 +420,15 @@ abstract class Simulator {

while (_endOfSimulationActions.isNotEmpty) {
final endOfSimAction = _endOfSimulationActions.removeFirst();
await endOfSimAction();

try {
await endOfSimAction();
} catch (_) {
// trigger the end of simulation if an error occurred
_simulationEndedCompleter.complete();

rethrow;
}
}

_simulationEndedCompleter.complete();
Expand Down
110 changes: 93 additions & 17 deletions test/simulator_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -81,25 +81,101 @@ void main() {
await Simulator.run();
});

test('simulator end of action waits before ending', () async {
var endOfSimActionExecuted = false;
Simulator.registerAction(100, () => true);
Simulator.registerEndOfSimulationAction(
() => endOfSimActionExecuted = true);
unawaited(Simulator.simulationEnded
.then((value) => expect(endOfSimActionExecuted, isTrue)));
await Simulator.run();
});
group('simulator end of', () {
test('action waits before ending', () async {
var endOfSimActionExecuted = false;
Simulator.registerAction(100, () => true);
Simulator.registerEndOfSimulationAction(
() => endOfSimActionExecuted = true);
unawaited(Simulator.simulationEnded
.then((value) => expect(endOfSimActionExecuted, isTrue)));
await Simulator.run();
});

test('simulator end of action waits async before ending', () async {
var endOfSimActionExecuted = false;
Simulator.registerAction(100, () => true);
Simulator.registerEndOfSimulationAction(() async {
await Future<void>.delayed(const Duration(microseconds: 10));
endOfSimActionExecuted = true;
test('action waits async before ending', () async {
var endOfSimActionExecuted = false;
Simulator.registerAction(100, () => true);
Simulator.registerEndOfSimulationAction(() async {
await Future<void>.delayed(const Duration(microseconds: 10));
endOfSimActionExecuted = true;
});
await Simulator.run();
expect(endOfSimActionExecuted, isTrue);
});
await Simulator.run();
expect(endOfSimActionExecuted, isTrue);

test('action throws', () async {
var endOfSimActionExecuted = false;
var errorThrown = false;

Simulator.registerAction(100, () => true);
Simulator.registerEndOfSimulationAction(() {
endOfSimActionExecuted = true;
throw Exception('End of sim action failed');
});

// the Future will hang if we don't properly trigger the completion
unawaited(Simulator.run().onError((_, __) {
errorThrown = true;
}));
await Simulator.simulationEnded;

expect(endOfSimActionExecuted, isTrue);
expect(errorThrown, isTrue);
});

test('action async throws', () async {
var endOfSimActionExecuted = false;
var errorThrown = false;

Simulator.registerAction(100, () => true);
Simulator.registerEndOfSimulationAction(() async {
await Future<void>.delayed(const Duration(microseconds: 10));
endOfSimActionExecuted = true;
throw Exception('End of sim action failed');
});

// the Future will hang if we don't properly trigger the completion
unawaited(Simulator.run().onError((_, __) {
errorThrown = true;
}));
await Simulator.simulationEnded;

expect(endOfSimActionExecuted, isTrue);
expect(errorThrown, isTrue);
});
});

test('registered action exception in simulator ends simulation', () async {
var errorThrown = false;

Simulator.registerAction(100, () => throw Exception('failed action'));
Simulator.registerAction(200, () => true);

unawaited(Simulator.run().onError((_, __) {
errorThrown = true;
}));

await Simulator.simulationEnded;

expect(errorThrown, isTrue);
});

test('simulator thrown exception ends simulation', () async {
var errorThrown = false;

Simulator.registerAction(
100,
() => Simulator.throwException(
Exception('simulator thrown exception'), StackTrace.current));
Simulator.registerAction(200, () => true);

unawaited(Simulator.run().onError((_, __) {
errorThrown = true;
}));

await Simulator.simulationEnded;

expect(errorThrown, isTrue);
});

test('simulator end simulation waits for simulation to end', () async {
Expand Down
2 changes: 1 addition & 1 deletion tool/gh_actions/run_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ set -euo pipefail
dart test

# run tests in JS (increase heap size also)
export NODE_OPTIONS="--max-old-space-size=6144"
export NODE_OPTIONS="--max-old-space-size=8192"
dart test --platform node

0 comments on commit 2827e9c

Please sign in to comment.