diff --git a/lib/src/simulator.dart b/lib/src/simulator.dart index 89a4aebbd..4c441cf0b 100644 --- a/lib/src/simulator.dart +++ b/lib/src/simulator.dart @@ -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; } @@ -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(); diff --git a/test/simulator_test.dart b/test/simulator_test.dart index f6ef041c4..e993fe205 100644 --- a/test/simulator_test.dart +++ b/test/simulator_test.dart @@ -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.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.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.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 { diff --git a/tool/gh_actions/run_tests.sh b/tool/gh_actions/run_tests.sh index d426240f3..160352cd2 100755 --- a/tool/gh_actions/run_tests.sh +++ b/tool/gh_actions/run_tests.sh @@ -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 \ No newline at end of file