| 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_test.scheduled_process; | 5 library scheduled_test.scheduled_process; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:convert'; | 8 import 'dart:convert'; |
| 9 import 'dart:io'; | 9 import 'dart:io'; |
| 10 | 10 |
| 11 import 'package:stack_trace/stack_trace.dart'; |
| 12 |
| 11 import 'scheduled_test.dart'; | 13 import 'scheduled_test.dart'; |
| 12 import 'src/utils.dart'; | 14 import 'src/utils.dart'; |
| 13 import 'src/value_future.dart'; | 15 import 'src/value_future.dart'; |
| 14 | 16 |
| 15 /// A class representing a [Process] that is scheduled to run in the course of | 17 /// A class representing a [Process] that is scheduled to run in the course of |
| 16 /// the test. This class allows actions on the process to be scheduled | 18 /// the test. This class allows actions on the process to be scheduled |
| 17 /// synchronously. All operations on this class are scheduled. | 19 /// synchronously. All operations on this class are scheduled. |
| 18 /// | 20 /// |
| 19 /// Before running the test, either [shouldExit] or [kill] must be called on | 21 /// Before running the test, either [shouldExit] or [kill] must be called on |
| 20 /// this to ensure that the process terminates when expected. Note that [kill] | 22 /// this to ensure that the process terminates when expected. Note that [kill] |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 _description = description { | 92 _description = description { |
| 91 assert(currentSchedule.state == ScheduleState.SET_UP); | 93 assert(currentSchedule.state == ScheduleState.SET_UP); |
| 92 | 94 |
| 93 _updateDescription(executable, arguments); | 95 _updateDescription(executable, arguments); |
| 94 | 96 |
| 95 _scheduleStartProcess(executable, arguments, workingDirectory, environment); | 97 _scheduleStartProcess(executable, arguments, workingDirectory, environment); |
| 96 | 98 |
| 97 _scheduleExceptionCleanup(); | 99 _scheduleExceptionCleanup(); |
| 98 | 100 |
| 99 var stdoutWithCanceller = _lineStreamWithCanceller( | 101 var stdoutWithCanceller = _lineStreamWithCanceller( |
| 100 _process.then((p) => p.stdout)); | 102 _process.then((p) => Chain.track(p.stdout))); |
| 101 _stdoutCanceller = stdoutWithCanceller.last; | 103 _stdoutCanceller = stdoutWithCanceller.last; |
| 102 _stdoutLog = stdoutWithCanceller.first; | 104 _stdoutLog = stdoutWithCanceller.first; |
| 103 | 105 |
| 104 var stderrWithCanceller = _lineStreamWithCanceller( | 106 var stderrWithCanceller = _lineStreamWithCanceller( |
| 105 _process.then((p) => p.stderr)); | 107 _process.then((p) => Chain.track(p.stderr))); |
| 106 _stderrCanceller = stderrWithCanceller.last; | 108 _stderrCanceller = stderrWithCanceller.last; |
| 107 _stderrLog = stderrWithCanceller.first; | 109 _stderrLog = stderrWithCanceller.first; |
| 108 | 110 |
| 109 _stdout = new StreamIterator<String>(stdoutStream()); | 111 _stdout = new StreamIterator<String>(stdoutStream()); |
| 110 _stderr = new StreamIterator<String>(stderrStream()); | 112 _stderr = new StreamIterator<String>(stderrStream()); |
| 111 } | 113 } |
| 112 | 114 |
| 113 /// Updates [_description] to reflect [executable] and [arguments], which are | 115 /// Updates [_description] to reflect [executable] and [arguments], which are |
| 114 /// the same values as in [start]. | 116 /// the same values as in [start]. |
| 115 void _updateDescription(executable, arguments) { | 117 void _updateDescription(executable, arguments) { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 143 new Future.sync(() => executable), | 145 new Future.sync(() => executable), |
| 144 awaitObject(arguments), | 146 awaitObject(arguments), |
| 145 new Future.sync(() => workingDirectory), | 147 new Future.sync(() => workingDirectory), |
| 146 new Future.sync(() => environment) | 148 new Future.sync(() => environment) |
| 147 ]).then((results) { | 149 ]).then((results) { |
| 148 executable = results[0]; | 150 executable = results[0]; |
| 149 arguments = results[1]; | 151 arguments = results[1]; |
| 150 workingDirectory = results[2]; | 152 workingDirectory = results[2]; |
| 151 environment = results[3]; | 153 environment = results[3]; |
| 152 _updateDescription(executable, arguments); | 154 _updateDescription(executable, arguments); |
| 153 return Process.start(executable, | 155 return Chain.track( |
| 154 arguments, | 156 Process.start(executable, |
| 155 workingDirectory: workingDirectory, | 157 arguments, |
| 156 environment: environment).then((process) { | 158 workingDirectory: workingDirectory, |
| 159 environment: environment)).then((process) { |
| 157 process.stdin.encoding = UTF8; | 160 process.stdin.encoding = UTF8; |
| 158 return process; | 161 return process; |
| 159 }); | 162 }); |
| 160 }); | 163 }); |
| 161 }, "starting process '$description'")); | 164 }, "starting process '$description'")); |
| 162 } | 165 } |
| 163 | 166 |
| 164 /// Listens for [_process] to exit and passes the exit code to | 167 /// Listens for [_process] to exit and passes the exit code to |
| 165 /// [exitCodeCompleter]. If the process completes earlier than expected, an | 168 /// [exitCodeCompleter]. If the process completes earlier than expected, an |
| 166 /// exception will be signaled to the schedule. | 169 /// exception will be signaled to the schedule. |
| 167 void _handleExit(Completer exitCodeCompleter) { | 170 void _handleExit(Completer exitCodeCompleter) { |
| 168 // We purposefully avoid using wrapFuture here. If an error occurs while a | 171 // We purposefully avoid using wrapFuture here. If an error occurs while a |
| 169 // process is running, we want the schedule to move to the onException | 172 // process is running, we want the schedule to move to the onException |
| 170 // queue where the process will be killed, rather than blocking the tasks | 173 // queue where the process will be killed, rather than blocking the tasks |
| 171 // queue waiting for the process to exit. | 174 // queue waiting for the process to exit. |
| 172 _process.then((p) => p.exitCode).then((exitCode) { | 175 _process.then((p) => Chain.track(p.exitCode)).then((exitCode) { |
| 173 if (_endExpected) { | 176 if (_endExpected) { |
| 174 exitCodeCompleter.complete(exitCode); | 177 exitCodeCompleter.complete(exitCode); |
| 175 return; | 178 return; |
| 176 } | 179 } |
| 177 | 180 |
| 178 wrapFuture(pumpEventQueue().then((_) { | 181 wrapFuture(pumpEventQueue().then((_) { |
| 179 if (currentSchedule.currentTask != _taskBeforeEnd) return null; | 182 if (currentSchedule.currentTask != _taskBeforeEnd) return null; |
| 180 // If we're one task before the end was scheduled, wait for that task | 183 // If we're one task before the end was scheduled, wait for that task |
| 181 // to complete and pump the event queue so that _endExpected will be | 184 // to complete and pump the event queue so that _endExpected will be |
| 182 // set. | 185 // set. |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 348 schedule(() { | 351 schedule(() { |
| 349 _endExpected = true; | 352 _endExpected = true; |
| 350 return _exitCode.then((exitCode) { | 353 return _exitCode.then((exitCode) { |
| 351 if (expectedExitCode != null) { | 354 if (expectedExitCode != null) { |
| 352 expect(exitCode, equals(expectedExitCode)); | 355 expect(exitCode, equals(expectedExitCode)); |
| 353 } | 356 } |
| 354 }); | 357 }); |
| 355 }, "waiting for process '$description' to exit"); | 358 }, "waiting for process '$description' to exit"); |
| 356 } | 359 } |
| 357 } | 360 } |
| OLD | NEW |