| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library scheduled_process; | 5 library scheduled_process; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:io'; | 8 import 'dart:io'; |
| 9 | 9 |
| 10 import 'scheduled_test.dart'; | 10 import 'scheduled_test.dart'; |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 147 | 147 |
| 148 /// Listens for [_process] to exit and passes the exit code to | 148 /// Listens for [_process] to exit and passes the exit code to |
| 149 /// [exitCodeCompleter]. If the process completes earlier than expected, an | 149 /// [exitCodeCompleter]. If the process completes earlier than expected, an |
| 150 /// exception will be signaled to the schedule. | 150 /// exception will be signaled to the schedule. |
| 151 void _handleExit(Completer exitCodeCompleter) { | 151 void _handleExit(Completer exitCodeCompleter) { |
| 152 // We purposefully avoid using wrapFuture here. If an error occurs while a | 152 // We purposefully avoid using wrapFuture here. If an error occurs while a |
| 153 // process is running, we want the schedule to move to the onException | 153 // process is running, we want the schedule to move to the onException |
| 154 // queue where the process will be killed, rather than blocking the tasks | 154 // queue where the process will be killed, rather than blocking the tasks |
| 155 // queue waiting for the process to exit. | 155 // queue waiting for the process to exit. |
| 156 _process.then((p) => p.exitCode).then((exitCode) { | 156 _process.then((p) => p.exitCode).then((exitCode) { |
| 157 print("[$description] exitCode completed with value '$exitCode'"); |
| 157 if (_endExpected) { | 158 if (_endExpected) { |
| 159 print("[$description] expected the process to end, passing '$exitCode' t
o completer"); |
| 158 exitCodeCompleter.complete(exitCode); | 160 exitCodeCompleter.complete(exitCode); |
| 159 return; | 161 return; |
| 162 } else { |
| 163 print("[$description] did not expect the process to end, maybe we should
wait for the current task to end"); |
| 160 } | 164 } |
| 161 | 165 |
| 162 wrapFuture(pumpEventQueue().then((_) { | 166 wrapFuture(pumpEventQueue().then((_) { |
| 163 if (currentSchedule.currentTask != _taskBeforeEnd) return; | 167 if (currentSchedule.currentTask != _taskBeforeEnd) { |
| 168 print("[$description] not waiting for the current task to end"); |
| 169 return; |
| 170 } |
| 171 print("[$description] waiting for current task to end to see if the end
will be expected"); |
| 164 // If we're one task before the end was scheduled, wait for that task | 172 // If we're one task before the end was scheduled, wait for that task |
| 165 // to complete and pump the event queue so that _endExpected will be | 173 // to complete and pump the event queue so that _endExpected will be |
| 166 // set. | 174 // set. |
| 167 return _taskBeforeEnd.result.then((_) => pumpEventQueue()); | 175 return _taskBeforeEnd.result.then((_) => pumpEventQueue()); |
| 168 }).then((_) { | 176 }).then((_) { |
| 177 print("[$description] passing '$exitCode' to completer"); |
| 169 exitCodeCompleter.complete(exitCode); | 178 exitCodeCompleter.complete(exitCode); |
| 170 | 179 |
| 171 if (!_endExpected) { | 180 if (!_endExpected) { |
| 181 print("[$description] end not expected, throwing error"); |
| 172 throw "Process '${this.description}' ended earlier than scheduled " | 182 throw "Process '${this.description}' ended earlier than scheduled " |
| 173 "with exit code $exitCode."; | 183 "with exit code $exitCode."; |
| 184 } else { |
| 185 print("[$description] end expected, not throwing error"); |
| 174 } | 186 } |
| 175 })); | 187 })); |
| 176 }); | 188 }); |
| 177 } | 189 } |
| 178 | 190 |
| 179 /// Converts a stream of bytes to a stream of lines and returns that along | 191 /// Converts a stream of bytes to a stream of lines and returns that along |
| 180 /// with a [StreamSubscription] controlling it. | 192 /// with a [StreamSubscription] controlling it. |
| 181 Pair<Stream<String>, StreamSubscription<String>> _lineStreamWithSubscription( | 193 Pair<Stream<String>, StreamSubscription<String>> _lineStreamWithSubscription( |
| 182 Future<Stream<int>> streamFuture) { | 194 Future<Stream<int>> streamFuture) { |
| 183 return streamWithSubscription(futureStream(streamFuture) | 195 return streamWithSubscription(futureStream(streamFuture) |
| 184 .handleError((e) => currentSchedule.signalError(e)) | 196 .handleError((e) => currentSchedule.signalError(e)) |
| 185 .transform(new StringDecoder(_encoding)) | 197 .transform(new StringDecoder(_encoding)) |
| 186 .transform(new LineTransformer())); | 198 .transform(new LineTransformer())); |
| 187 } | 199 } |
| 188 | 200 |
| 189 /// Schedule an exception handler that will clean up the process and provide | 201 /// Schedule an exception handler that will clean up the process and provide |
| 190 /// debug information if an error occurs. | 202 /// debug information if an error occurs. |
| 191 void _scheduleExceptionCleanup() { | 203 void _scheduleExceptionCleanup() { |
| 192 currentSchedule.onException.schedule(() { | 204 currentSchedule.onException.schedule(() { |
| 205 print("[$description] cleaning up after exception"); |
| 193 _stdoutSubscription.cancel(); | 206 _stdoutSubscription.cancel(); |
| 194 _stderrSubscription.cancel(); | 207 _stderrSubscription.cancel(); |
| 195 | 208 |
| 196 if (!_process.hasValue) return; | 209 if (!_process.hasValue) return; |
| 197 | 210 |
| 198 var killedPrematurely = false; | 211 var killedPrematurely = false; |
| 199 if (!_exitCode.hasValue) { | 212 if (!_exitCode.hasValue) { |
| 213 print("[$description] exit code has not been set, killing process"); |
| 200 var killedPrematurely = true; | 214 var killedPrematurely = true; |
| 201 _endExpected = true; | 215 _endExpected = true; |
| 202 _process.value.kill(); | 216 _process.value.kill(); |
| 203 // Ensure that the onException queue waits for the process to actually | 217 // Ensure that the onException queue waits for the process to actually |
| 204 // exit after being killed. | 218 // exit after being killed. |
| 205 wrapFuture(_process.value.exitCode); | 219 wrapFuture(_process.value.exitCode); |
| 220 } else { |
| 221 print("[$description] exit code has been set to '${_process.value.exitCo
de.value}', process is dead"); |
| 206 } | 222 } |
| 207 | 223 |
| 208 return Future.wait([ | 224 return Future.wait([ |
| 209 _stdoutLog.toList(), | 225 _stdoutLog.toList(), |
| 210 _stderrLog.toList() | 226 _stderrLog.toList() |
| 211 ]).then((results) { | 227 ]).then((results) { |
| 228 print("[$description] got stdout/stderr, killedPrematurely=$killedPremat
urely, exitCode.value=${_exitCode.value}"); |
| 212 var stdout = results[0].join("\n"); | 229 var stdout = results[0].join("\n"); |
| 213 var stderr = results[1].join("\n"); | 230 var stderr = results[1].join("\n"); |
| 214 | 231 |
| 215 var exitDescription = killedPrematurely | 232 var exitDescription = killedPrematurely |
| 216 ? "Process was killed prematurely." | 233 ? "Process was killed prematurely." |
| 217 : "Process exited with exit code ${_exitCode.value}."; | 234 : "Process exited with exit code ${_exitCode.value}."; |
| 218 currentSchedule.addDebugInfo( | 235 currentSchedule.addDebugInfo( |
| 219 "Results of running '${this.description}':\n" | 236 "Results of running '${this.description}':\n" |
| 220 "$exitDescription\n" | 237 "$exitDescription\n" |
| 221 "Standard output:\n" | 238 "Standard output:\n" |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 schedule(() { | 314 schedule(() { |
| 298 _endExpected = true; | 315 _endExpected = true; |
| 299 return _exitCode.then((exitCode) { | 316 return _exitCode.then((exitCode) { |
| 300 if (expectedExitCode != null) { | 317 if (expectedExitCode != null) { |
| 301 expect(exitCode, equals(expectedExitCode)); | 318 expect(exitCode, equals(expectedExitCode)); |
| 302 } | 319 } |
| 303 }); | 320 }); |
| 304 }, "waiting for process '$description' to exit"); | 321 }, "waiting for process '$description' to exit"); |
| 305 } | 322 } |
| 306 } | 323 } |
| OLD | NEW |