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'; |
11 import 'src/utils.dart'; | 11 import 'src/utils.dart'; |
12 import 'src/value_future.dart'; | 12 import 'src/value_future.dart'; |
13 | 13 |
14 /// A class representing a [Process] that is scheduled to run in the course of | 14 /// A class representing a [Process] that is scheduled to run in the course of |
15 /// the test. This class allows actions on the process to be scheduled | 15 /// the test. This class allows actions on the process to be scheduled |
16 /// synchronously. All operations on this class are scheduled. | 16 /// synchronously. All operations on this class are scheduled. |
17 /// | 17 /// |
18 /// Before running the test, either [shouldExit] or [kill] must be called on | 18 /// Before running the test, either [shouldExit] or [kill] must be called on |
19 /// this to ensure that the process terminates when expected. | 19 /// this to ensure that the process terminates when expected. |
20 /// | 20 /// |
21 /// If the test fails, this will automatically print out any stdout and stderr | 21 /// If the test fails, this will automatically print out any stdout and stderr |
22 /// from the process to aid debugging. | 22 /// from the process to aid debugging. |
23 class ScheduledProcess { | 23 class ScheduledProcess { |
24 // A description of the process. Used for error reporting. | 24 /// A description of the process. Used for error reporting. |
25 String get description => _description; | 25 String get description => _description; |
26 String _description; | 26 String _description; |
27 | 27 |
| 28 /// Whether a description was passed explicitly by the user. |
| 29 bool _explicitDescription; |
| 30 |
28 /// The encoding used for the process's input and output streams. | 31 /// The encoding used for the process's input and output streams. |
29 final Encoding _encoding; | 32 final Encoding _encoding; |
30 | 33 |
31 /// The process that's scheduled to run. | 34 /// The process that's scheduled to run. |
32 ValueFuture<Process> _process; | 35 ValueFuture<Process> _process; |
33 | 36 |
34 /// A fork of [_stdout] that records the standard output of the process. Used | 37 /// A fork of [_stdout] that records the standard output of the process. Used |
35 /// for debugging information. | 38 /// for debugging information. |
36 Stream<String> _stdoutLog; | 39 Stream<String> _stdoutLog; |
37 | 40 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
71 /// description of this process; it defaults to the command-line invocation. | 74 /// description of this process; it defaults to the command-line invocation. |
72 /// [encoding] is the [Encoding] that will be used for the process's input and | 75 /// [encoding] is the [Encoding] that will be used for the process's input and |
73 /// output. | 76 /// output. |
74 /// | 77 /// |
75 /// [executable], [arguments], and [options] may be either a [Future] or a | 78 /// [executable], [arguments], and [options] may be either a [Future] or a |
76 /// concrete value. If any are [Future]s, the process won't start until the | 79 /// concrete value. If any are [Future]s, the process won't start until the |
77 /// [Future]s have completed. In addition, [arguments] may be a [List] | 80 /// [Future]s have completed. In addition, [arguments] may be a [List] |
78 /// containing a mix of strings and [Future]s. | 81 /// containing a mix of strings and [Future]s. |
79 ScheduledProcess.start(executable, arguments, | 82 ScheduledProcess.start(executable, arguments, |
80 {options, String description, Encoding encoding: Encoding.UTF_8}) | 83 {options, String description, Encoding encoding: Encoding.UTF_8}) |
81 : _encoding = encoding { | 84 : _encoding = encoding, |
| 85 _explicitDescription = description != null, |
| 86 _description = description { |
82 assert(currentSchedule.state == ScheduleState.SET_UP); | 87 assert(currentSchedule.state == ScheduleState.SET_UP); |
83 | 88 |
84 _updateDescription(executable, arguments); | 89 _updateDescription(executable, arguments); |
85 | 90 |
86 _scheduleStartProcess(executable, arguments, options); | 91 _scheduleStartProcess(executable, arguments, options); |
87 | 92 |
88 _scheduleExceptionCleanup(); | 93 _scheduleExceptionCleanup(); |
89 | 94 |
90 var stdoutWithCanceller = _lineStreamWithCanceller( | 95 var stdoutWithCanceller = _lineStreamWithCanceller( |
91 _process.then((p) => p.stdout)); | 96 _process.then((p) => p.stdout)); |
92 _stdoutCanceller = stdoutWithCanceller.last; | 97 _stdoutCanceller = stdoutWithCanceller.last; |
93 var stdoutTee = tee(stdoutWithCanceller.first); | 98 var stdoutTee = tee(stdoutWithCanceller.first); |
94 _stdout = stdoutTee.first; | 99 _stdout = stdoutTee.first; |
95 _stdoutLog = stdoutTee.last; | 100 _stdoutLog = stdoutTee.last; |
96 | 101 |
97 var stderrWithCanceller = _lineStreamWithCanceller( | 102 var stderrWithCanceller = _lineStreamWithCanceller( |
98 _process.then((p) => p.stderr)); | 103 _process.then((p) => p.stderr)); |
99 _stderrCanceller = stderrWithCanceller.last; | 104 _stderrCanceller = stderrWithCanceller.last; |
100 var stderrTee = tee(stderrWithCanceller.first); | 105 var stderrTee = tee(stderrWithCanceller.first); |
101 _stderr = stderrTee.first; | 106 _stderr = stderrTee.first; |
102 _stderrLog = stderrTee.last; | 107 _stderrLog = stderrTee.last; |
103 } | 108 } |
104 | 109 |
105 /// Updates [_description] to reflect [executable] and [arguments], which are | 110 /// Updates [_description] to reflect [executable] and [arguments], which are |
106 /// the same values as in [start]. | 111 /// the same values as in [start]. |
107 void _updateDescription(executable, arguments) { | 112 void _updateDescription(executable, arguments) { |
| 113 if (_explicitDescription) return; |
108 if (executable is Future) { | 114 if (executable is Future) { |
109 _description = "future process"; | 115 _description = "future process"; |
110 } else if (arguments is Future || arguments.any((e) => e is Future)) { | 116 } else if (arguments is Future || arguments.any((e) => e is Future)) { |
111 _description = executable; | 117 _description = executable; |
112 } else { | 118 } else { |
113 _description = "$executable ${arguments.map((a) => '"$a"').join(' ')}"; | 119 _description = "$executable ${arguments.map((a) => '"$a"').join(' ')}"; |
114 } | 120 } |
115 } | 121 } |
116 | 122 |
117 /// Schedules the process to start and sets [_process]. | 123 /// Schedules the process to start and sets [_process]. |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
299 schedule(() { | 305 schedule(() { |
300 _endExpected = true; | 306 _endExpected = true; |
301 return _exitCode.then((exitCode) { | 307 return _exitCode.then((exitCode) { |
302 if (expectedExitCode != null) { | 308 if (expectedExitCode != null) { |
303 expect(exitCode, equals(expectedExitCode)); | 309 expect(exitCode, equals(expectedExitCode)); |
304 } | 310 } |
305 }); | 311 }); |
306 }, "waiting for process '$description' to exit"); | 312 }, "waiting for process '$description' to exit"); |
307 } | 313 } |
308 } | 314 } |
OLD | NEW |