Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(242)

Side by Side Diff: utils/tests/pub/test_pub.dart

Issue 12095050: Roll back Pub stream changes. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Actually roll back changes Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « utils/tests/pub/pub_uploader_test.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 /// Test infrastructure for testing pub. Unlike typical unit tests, most pub 5 /// Test infrastructure for testing pub. Unlike typical unit tests, most pub
6 /// tests are integration tests that stage some stuff on the file system, run 6 /// tests are integration tests that stage some stuff on the file system, run
7 /// pub, and then validate the results. This library provides an API to build 7 /// pub, and then validate the results. This library provides an API to build
8 /// tests like that. 8 /// tests like that.
9 library test_pub; 9 library test_pub;
10 10
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
103 var stream; 103 var stream;
104 try { 104 try {
105 stream = baseDir.load(path); 105 stream = baseDir.load(path);
106 } catch (e) { 106 } catch (e) {
107 response.statusCode = 404; 107 response.statusCode = 404;
108 response.contentLength = 0; 108 response.contentLength = 0;
109 response.outputStream.close(); 109 response.outputStream.close();
110 return; 110 return;
111 } 111 }
112 112
113 stream.toBytes().then((data) { 113 var future = consumeInputStream(stream);
114 future.then((data) {
114 response.statusCode = 200; 115 response.statusCode = 200;
115 response.contentLength = data.length; 116 response.contentLength = data.length;
116 response.outputStream.write(data); 117 response.outputStream.write(data);
117 response.outputStream.close(); 118 response.outputStream.close();
118 }).catchError((e) { 119 }).catchError((e) {
119 print("Exception while handling ${request.uri}: $e"); 120 print("Exception while handling ${request.uri}: $e");
120 response.statusCode = 500; 121 response.statusCode = 500;
121 response.reasonPhrase = e.message; 122 response.reasonPhrase = e.message;
122 response.outputStream.close(); 123 response.outputStream.close();
123 }); 124 });
(...skipping 646 matching lines...) Expand 10 before | Expand all | Expand 10 after
770 /// system entry within [dir]. Returns a [Future] that completes to `null` if 771 /// system entry within [dir]. Returns a [Future] that completes to `null` if
771 /// the entry is valid, or throws an error if it failed. 772 /// the entry is valid, or throws an error if it failed.
772 Future validate(String dir); 773 Future validate(String dir);
773 774
774 /// Deletes the file or directory within [dir]. Returns a [Future] that is 775 /// Deletes the file or directory within [dir]. Returns a [Future] that is
775 /// completed after the deletion is done. 776 /// completed after the deletion is done.
776 Future delete(String dir); 777 Future delete(String dir);
777 778
778 /// Loads the file at [path] from within this descriptor. If [path] is empty, 779 /// Loads the file at [path] from within this descriptor. If [path] is empty,
779 /// loads the contents of the descriptor itself. 780 /// loads the contents of the descriptor itself.
780 ByteStream load(List<String> path); 781 InputStream load(List<String> path);
781 782
782 /// Schedules the directory to be created before Pub is run with 783 /// Schedules the directory to be created before Pub is run with
783 /// [schedulePub]. The directory will be created relative to the sandbox 784 /// [schedulePub]. The directory will be created relative to the sandbox
784 /// directory. 785 /// directory.
785 // TODO(nweiz): Use implicit closurization once issue 2984 is fixed. 786 // TODO(nweiz): Use implicit closurization once issue 2984 is fixed.
786 void scheduleCreate() => _schedule((dir) => this.create(dir)); 787 void scheduleCreate() => _schedule((dir) => this.create(dir));
787 788
788 /// Schedules the file or directory to be deleted recursively. 789 /// Schedules the file or directory to be deleted recursively.
789 void scheduleDelete() => _schedule((dir) => this.delete(dir)); 790 void scheduleDelete() => _schedule((dir) => this.delete(dir));
790 791
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
890 if (text == contents) return null; 891 if (text == contents) return null;
891 892
892 throw new ExpectException( 893 throw new ExpectException(
893 'File $file should contain:\n\n$contents\n\n' 894 'File $file should contain:\n\n$contents\n\n'
894 'but contained:\n\n$text'); 895 'but contained:\n\n$text');
895 }); 896 });
896 }); 897 });
897 } 898 }
898 899
899 /// Loads the contents of the file. 900 /// Loads the contents of the file.
900 ByteStream load(List<String> path) { 901 InputStream load(List<String> path) {
901 if (!path.isEmpty) { 902 if (!path.isEmpty) {
902 var joinedPath = Strings.join(path, '/'); 903 var joinedPath = Strings.join(path, '/');
903 throw "Can't load $joinedPath from within $name: not a directory."; 904 throw "Can't load $joinedPath from within $name: not a directory.";
904 } 905 }
905 906
906 return new ByteStream.fromBytes(contents.charCodes); 907 var stream = new ListInputStream();
908 stream.write(contents.charCodes);
909 stream.markEndOfStream();
910 return stream;
907 } 911 }
908 } 912 }
909 913
910 /// Describes a directory and its contents. These are used both for setting up 914 /// Describes a directory and its contents. These are used both for setting up
911 /// an expected directory tree before running a test, and for validating that 915 /// an expected directory tree before running a test, and for validating that
912 /// the file system matches some expectations after running it. 916 /// the file system matches some expectations after running it.
913 class DirectoryDescriptor extends Descriptor { 917 class DirectoryDescriptor extends Descriptor {
914 /// The files and directories contained in this directory. 918 /// The files and directories contained in this directory.
915 final List<Descriptor> contents; 919 final List<Descriptor> contents;
916 920
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
948 // Validate each of the items in this directory. 952 // Validate each of the items in this directory.
949 final entryFutures = 953 final entryFutures =
950 contents.mappedBy((entry) => entry.validate(dir)).toList(); 954 contents.mappedBy((entry) => entry.validate(dir)).toList();
951 955
952 // If they are all valid, the directory is valid. 956 // If they are all valid, the directory is valid.
953 return Future.wait(entryFutures).then((entries) => null); 957 return Future.wait(entryFutures).then((entries) => null);
954 }); 958 });
955 } 959 }
956 960
957 /// Loads [path] from within this directory. 961 /// Loads [path] from within this directory.
958 ByteStream load(List<String> path) { 962 InputStream load(List<String> path) {
959 if (path.isEmpty) { 963 if (path.isEmpty) {
960 throw "Can't load the contents of $name: is a directory."; 964 throw "Can't load the contents of $name: is a directory.";
961 } 965 }
962 966
963 for (var descriptor in contents) { 967 for (var descriptor in contents) {
964 if (descriptor.name == path[0]) { 968 if (descriptor.name == path[0]) {
965 return descriptor.load(path.getRange(1, path.length - 1)); 969 return descriptor.load(path.getRange(1, path.length - 1));
966 } 970 }
967 } 971 }
968 972
969 throw "Directory $name doesn't contain ${Strings.join(path, '/')}."; 973 throw "Directory $name doesn't contain ${Strings.join(path, '/')}.";
970 } 974 }
971 } 975 }
972 976
973 /// Wraps a [Future] that will complete to a [Descriptor] and makes it behave 977 /// Wraps a [Future] that will complete to a [Descriptor] and makes it behave
974 /// like a concrete [Descriptor]. This is necessary when the contents of the 978 /// like a concrete [Descriptor]. This is necessary when the contents of the
975 /// descriptor depends on information that's not available until part of the 979 /// descriptor depends on information that's not available until part of the
976 /// test run is completed. 980 /// test run is completed.
977 class FutureDescriptor extends Descriptor { 981 class FutureDescriptor extends Descriptor {
978 Future<Descriptor> _future; 982 Future<Descriptor> _future;
979 983
980 FutureDescriptor(this._future) : super('<unknown>'); 984 FutureDescriptor(this._future) : super('<unknown>');
981 985
982 Future create(dir) => _future.then((desc) => desc.create(dir)); 986 Future create(dir) => _future.then((desc) => desc.create(dir));
983 987
984 Future validate(dir) => _future.then((desc) => desc.validate(dir)); 988 Future validate(dir) => _future.then((desc) => desc.validate(dir));
985 989
986 Future delete(dir) => _future.then((desc) => desc.delete(dir)); 990 Future delete(dir) => _future.then((desc) => desc.delete(dir));
987 991
988 ByteStream load(List<String> path) { 992 InputStream load(List<String> path) {
989 var controller = new StreamController<List<int>>(); 993 var resultStream = new ListInputStream();
990 _future.then((desc) => store(desc.load(path), controller)); 994 _future.then((desc) => pipeInputToInput(desc.load(path), resultStream));
991 return new ByteStream(controller.stream); 995 return resultStream;
992 } 996 }
993 } 997 }
994 998
995 /// Describes a Git repository and its contents. 999 /// Describes a Git repository and its contents.
996 class GitRepoDescriptor extends DirectoryDescriptor { 1000 class GitRepoDescriptor extends DirectoryDescriptor {
997 GitRepoDescriptor(Pattern name, List<Descriptor> contents) 1001 GitRepoDescriptor(Pattern name, List<Descriptor> contents)
998 : super(name, contents); 1002 : super(name, contents);
999 1003
1000 /// Creates the Git repository and commits the contents. 1004 /// Creates the Git repository and commits the contents.
1001 Future<Directory> create(parentDir) { 1005 Future<Directory> create(parentDir) {
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
1074 1078
1075 /// Creates the files and directories within this tar file, then archives 1079 /// Creates the files and directories within this tar file, then archives
1076 /// them, compresses them, and saves the result to [parentDir]. 1080 /// them, compresses them, and saves the result to [parentDir].
1077 Future<File> create(parentDir) { 1081 Future<File> create(parentDir) {
1078 // TODO(rnystrom): Use withTempDir(). 1082 // TODO(rnystrom): Use withTempDir().
1079 var tempDir; 1083 var tempDir;
1080 return createTempDir().then((_tempDir) { 1084 return createTempDir().then((_tempDir) {
1081 tempDir = _tempDir; 1085 tempDir = _tempDir;
1082 return Future.wait(contents.mappedBy((child) => child.create(tempDir))); 1086 return Future.wait(contents.mappedBy((child) => child.create(tempDir)));
1083 }).then((createdContents) { 1087 }).then((createdContents) {
1084 return createTarGz(createdContents, baseDir: tempDir).toBytes(); 1088 return consumeInputStream(createTarGz(createdContents, baseDir: tempDir));
1085 }).then((bytes) { 1089 }).then((bytes) {
1086 return new File(join(parentDir, _stringName)).writeAsBytes(bytes); 1090 return new File(join(parentDir, _stringName)).writeAsBytes(bytes);
1087 }).then((file) { 1091 }).then((file) {
1088 return deleteDir(tempDir).then((_) => file); 1092 return deleteDir(tempDir).then((_) => file);
1089 }); 1093 });
1090 } 1094 }
1091 1095
1092 /// Validates that the `.tar.gz` file at [path] contains the expected 1096 /// Validates that the `.tar.gz` file at [path] contains the expected
1093 /// contents. 1097 /// contents.
1094 Future validate(String path) { 1098 Future validate(String path) {
1095 throw "TODO(nweiz): implement this"; 1099 throw "TODO(nweiz): implement this";
1096 } 1100 }
1097 1101
1098 Future delete(dir) { 1102 Future delete(dir) {
1099 throw new UnsupportedError(''); 1103 throw new UnsupportedError('');
1100 } 1104 }
1101 1105
1102 /// Loads the contents of this tar file. 1106 /// Loads the contents of this tar file.
1103 ByteStream load(List<String> path) { 1107 InputStream load(List<String> path) {
1104 if (!path.isEmpty) { 1108 if (!path.isEmpty) {
1105 var joinedPath = Strings.join(path, '/'); 1109 var joinedPath = Strings.join(path, '/');
1106 throw "Can't load $joinedPath from within $name: not a directory."; 1110 throw "Can't load $joinedPath from within $name: not a directory.";
1107 } 1111 }
1108 1112
1109 var controller = new StreamController<List<int>>(); 1113 var sinkStream = new ListInputStream();
1110 var tempDir; 1114 var tempDir;
1111 // TODO(rnystrom): Use withTempDir() here. 1115 // TODO(rnystrom): Use withTempDir() here.
1112 // TODO(nweiz): propagate any errors to the return value. See issue 3657. 1116 // TODO(nweiz): propagate any errors to the return value. See issue 3657.
1113 createTempDir().then((_tempDir) { 1117 createTempDir().then((_tempDir) {
1114 tempDir = _tempDir; 1118 tempDir = _tempDir;
1115 return create(tempDir); 1119 return create(tempDir);
1116 }).then((tar) { 1120 }).then((tar) {
1117 var sourceStream = tar.openInputStream(); 1121 var sourceStream = tar.openInputStream();
1118 return store(wrapInputStream(sourceStream), controller).then((_) { 1122 return pipeInputToInput(sourceStream, sinkStream).then((_) {
1119 tempDir.delete(recursive: true); 1123 tempDir.delete(recursive: true);
1120 }); 1124 });
1121 }); 1125 });
1122 return new ByteStream(controller.stream); 1126 return sinkStream;
1123 } 1127 }
1124 } 1128 }
1125 1129
1126 /// A descriptor that validates that no file exists with the given name. 1130 /// A descriptor that validates that no file exists with the given name.
1127 class NothingDescriptor extends Descriptor { 1131 class NothingDescriptor extends Descriptor {
1128 NothingDescriptor(String name) : super(name); 1132 NothingDescriptor(String name) : super(name);
1129 1133
1130 Future create(dir) => new Future.immediate(null); 1134 Future create(dir) => new Future.immediate(null);
1131 Future delete(dir) => new Future.immediate(null); 1135 Future delete(dir) => new Future.immediate(null);
1132 1136
1133 Future validate(String dir) { 1137 Future validate(String dir) {
1134 return exists(join(dir, name)).then((exists) { 1138 return exists(join(dir, name)).then((exists) {
1135 if (exists) { 1139 if (exists) {
1136 throw new ExpectException('File $name in $dir should not exist.'); 1140 throw new ExpectException('File $name in $dir should not exist.');
1137 } 1141 }
1138 }); 1142 });
1139 } 1143 }
1140 1144
1141 ByteStream load(List<String> path) { 1145 InputStream load(List<String> path) {
1142 if (path.isEmpty) { 1146 if (path.isEmpty) {
1143 throw "Can't load the contents of $name: it doesn't exist."; 1147 throw "Can't load the contents of $name: it doesn't exist.";
1144 } else { 1148 } else {
1145 throw "Can't load ${Strings.join(path, '/')} from within $name: $name " 1149 throw "Can't load ${Strings.join(path, '/')} from within $name: $name "
1146 "doesn't exist."; 1150 "doesn't exist.";
1147 } 1151 }
1148 } 1152 }
1149 } 1153 }
1150 1154
1151 /// A function that creates a [Validator] subclass. 1155 /// A function that creates a [Validator] subclass.
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
1201 /// Before running the test, either [shouldExit] or [kill] must be called on 1205 /// Before running the test, either [shouldExit] or [kill] must be called on
1202 /// this to ensure that the process terminates when expected. 1206 /// this to ensure that the process terminates when expected.
1203 /// 1207 ///
1204 /// If the test fails, this will automatically print out any remaining stdout 1208 /// If the test fails, this will automatically print out any remaining stdout
1205 /// and stderr from the process to aid debugging. 1209 /// and stderr from the process to aid debugging.
1206 class ScheduledProcess { 1210 class ScheduledProcess {
1207 /// The name of the process. Used for error reporting. 1211 /// The name of the process. Used for error reporting.
1208 final String name; 1212 final String name;
1209 1213
1210 /// The process future that's scheduled to run. 1214 /// The process future that's scheduled to run.
1211 Future<PubProcess> _processFuture; 1215 Future<Process> _processFuture;
1212 1216
1213 /// The process that's scheduled to run. It may be null. 1217 /// The process that's scheduled to run. It may be null.
1214 Process _process; 1218 Process _process;
1215 1219
1216 /// The exit code of the scheduled program. It may be null. 1220 /// The exit code of the scheduled program. It may be null.
1217 int _exitCode; 1221 int _exitCode;
1218 1222
1219 /// A future that will complete to a list of all the lines emitted on the 1223 /// A [StringInputStream] wrapping the stdout of the process that's scheduled
1220 /// process's standard output stream. This is independent of what data is read 1224 /// to run.
1221 /// from [_stdout]. 1225 final Future<StringInputStream> _stdoutFuture;
1222 Future<List<String>> _stdoutLines;
1223 1226
1224 /// A [Stream] of stdout lines emitted by the process that's scheduled to run. 1227 /// A [StringInputStream] wrapping the stderr of the process that's scheduled
1225 /// It may be null. 1228 /// to run.
1226 Stream<String> _stdout; 1229 final Future<StringInputStream> _stderrFuture;
1227
1228 /// A [Future] that will resolve to [_stdout] once it's available.
1229 Future get _stdoutFuture => _processFuture.then((_) => _stdout);
1230
1231 /// A [StreamSubscription] that controls [_stdout].
1232 StreamSubscription _stdoutSubscription;
1233
1234 /// A future that will complete to a list of all the lines emitted on the
1235 /// process's standard error stream. This is independent of what data is read
1236 /// from [_stderr].
1237 Future<List<String>> _stderrLines;
1238
1239 /// A [Stream] of stderr lines emitted by the process that's scheduled to run.
1240 /// It may be null.
1241 Stream<String> _stderr;
1242
1243 /// A [Future] that will resolve to [_stderr] once it's available.
1244 Future get _stderrFuture => _processFuture.then((_) => _stderr);
1245
1246 /// A [StreamSubscription] that controls [_stderr].
1247 StreamSubscription _stderrSubscription;
1248 1230
1249 /// The exit code of the process that's scheduled to run. This will naturally 1231 /// The exit code of the process that's scheduled to run. This will naturally
1250 /// only complete once the process has terminated. 1232 /// only complete once the process has terminated.
1251 Future<int> get _exitCodeFuture => _exitCodeCompleter.future; 1233 Future<int> get _exitCodeFuture => _exitCodeCompleter.future;
1252 1234
1253 /// The completer for [_exitCode]. 1235 /// The completer for [_exitCode].
1254 final Completer<int> _exitCodeCompleter = new Completer(); 1236 final Completer<int> _exitCodeCompleter = new Completer();
1255 1237
1256 /// Whether the user has scheduled the end of this process by calling either 1238 /// Whether the user has scheduled the end of this process by calling either
1257 /// [shouldExit] or [kill]. 1239 /// [shouldExit] or [kill].
1258 bool _endScheduled = false; 1240 bool _endScheduled = false;
1259 1241
1260 /// Whether the process is expected to terminate at this point. 1242 /// Whether the process is expected to terminate at this point.
1261 bool _endExpected = false; 1243 bool _endExpected = false;
1262 1244
1263 /// Wraps a [Process] [Future] in a scheduled process. 1245 /// Wraps a [Process] [Future] in a scheduled process.
1264 ScheduledProcess(this.name, Future<PubProcess> process) 1246 ScheduledProcess(this.name, Future<Process> process)
1265 : _processFuture = process { 1247 : _processFuture = process,
1266 var pairFuture = process.then((p) { 1248 _stdoutFuture = process.then((p) => new StringInputStream(p.stdout)),
1249 _stderrFuture = process.then((p) => new StringInputStream(p.stderr)) {
1250 process.then((p) {
1267 _process = p; 1251 _process = p;
1268
1269 var stdoutTee = tee(p.stdout.handleError((e) {
1270 registerException(e.error, e.stackTrace);
1271 }));
1272 var stdoutPair = streamWithSubscription(stdoutTee.last);
1273 _stdout = stdoutPair.first;
1274 _stdoutSubscription = stdoutPair.last;
1275
1276 var stderrTee = tee(p.stderr.handleError((e) {
1277 registerException(e.error, e.stackTrace);
1278 }));
1279 var stderrPair = streamWithSubscription(stderrTee.last);
1280 _stderr = stderrPair.first;
1281 _stderrSubscription = stderrPair.last;
1282
1283 return new Pair(stdoutTee.first, stderrTee.first);
1284 }); 1252 });
1285 1253
1286 _stdoutLines = pairFuture.then((pair) => pair.first.toList());
1287 _stderrLines = pairFuture.then((pair) => pair.last.toList());
1288
1289 _schedule((_) { 1254 _schedule((_) {
1290 if (!_endScheduled) { 1255 if (!_endScheduled) {
1291 throw new StateError("Scheduled process $name must have shouldExit() " 1256 throw new StateError("Scheduled process $name must have shouldExit() "
1292 "or kill() called before the test is run."); 1257 "or kill() called before the test is run.");
1293 } 1258 }
1294 1259
1295 return process.then((p) => p.exitCode).then((exitCode) { 1260 return process.then((p) {
1296 if (_endExpected) { 1261 p.onExit = (c) {
1297 _exitCode = exitCode;
1298 _exitCodeCompleter.complete(exitCode);
1299 return;
1300 }
1301
1302 // Sleep for half a second in case _endExpected is set in the next
1303 // scheduled event.
1304 sleep(500).then((_) {
1305 if (_endExpected) { 1262 if (_endExpected) {
1306 _exitCodeCompleter.complete(exitCode); 1263 _exitCode = c;
1264 _exitCodeCompleter.complete(c);
1307 return; 1265 return;
1308 } 1266 }
1309 1267
1310 return _printStreams().then((_) { 1268 // Sleep for half a second in case _endExpected is set in the next
1311 registerException(new ExpectException("Process $name ended " 1269 // scheduled event.
1312 "earlier than scheduled with exit code $exitCode")); 1270 sleep(500).then((_) {
1271 if (_endExpected) {
1272 _exitCodeCompleter.complete(c);
1273 return;
1274 }
1275
1276 _printStreams().then((_) {
1277 registerException(new ExpectException("Process $name ended "
1278 "earlier than scheduled with exit code $c"));
1279 });
1313 }); 1280 });
1314 }); 1281 };
1315 }); 1282 });
1316 }); 1283 });
1317 1284
1318 _scheduleOnException((_) { 1285 _scheduleOnException((_) {
1319 if (_process == null) return; 1286 if (_process == null) return;
1320 1287
1321 if (_exitCode == null) { 1288 if (_exitCode == null) {
1322 print("\nKilling process $name prematurely."); 1289 print("\nKilling process $name prematurely.");
1323 _endExpected = true; 1290 _endExpected = true;
1324 _process.kill(); 1291 _process.kill();
1325 } 1292 }
1326 1293
1327 return _printStreams(); 1294 return _printStreams();
1328 }); 1295 });
1329 1296
1330 _scheduleCleanup((_) { 1297 _scheduleCleanup((_) {
1331 if (_process == null) return; 1298 if (_process == null) return;
1332 // Ensure that the process is dead and we aren't waiting on any IO. 1299 // Ensure that the process is dead and we aren't waiting on any IO.
1333 _process.kill(); 1300 _process.kill();
1334 _stdoutSubscription.cancel(); 1301 _process.stdout.close();
1335 _stderrSubscription.cancel(); 1302 _process.stderr.close();
1336 }); 1303 });
1337 } 1304 }
1338 1305
1339 /// Reads the next line of stdout from the process. 1306 /// Reads the next line of stdout from the process.
1340 Future<String> nextLine() { 1307 Future<String> nextLine() {
1341 return _scheduleValue((_) { 1308 return _scheduleValue((_) {
1342 return timeout(_stdoutFuture.then((stream) => streamFirst(stream)), 1309 return timeout(_stdoutFuture.then((stream) => readLine(stream)),
1343 _SCHEDULE_TIMEOUT, 1310 _SCHEDULE_TIMEOUT,
1344 "waiting for the next stdout line from process $name"); 1311 "waiting for the next stdout line from process $name");
1345 }); 1312 });
1346 } 1313 }
1347 1314
1348 /// Reads the next line of stderr from the process. 1315 /// Reads the next line of stderr from the process.
1349 Future<String> nextErrLine() { 1316 Future<String> nextErrLine() {
1350 return _scheduleValue((_) { 1317 return _scheduleValue((_) {
1351 return timeout(_stderrFuture.then((stream) => streamFirst(stream)), 1318 return timeout(_stderrFuture.then((stream) => readLine(stream)),
1352 _SCHEDULE_TIMEOUT, 1319 _SCHEDULE_TIMEOUT,
1353 "waiting for the next stderr line from process $name"); 1320 "waiting for the next stderr line from process $name");
1354 }); 1321 });
1355 } 1322 }
1356 1323
1357 /// Reads the remaining stdout from the process. This should only be called 1324 /// Reads the remaining stdout from the process. This should only be called
1358 /// after kill() or shouldExit(). 1325 /// after kill() or shouldExit().
1359 Future<String> remainingStdout() { 1326 Future<String> remainingStdout() {
1360 if (!_endScheduled) { 1327 if (!_endScheduled) {
1361 throw new StateError("remainingStdout() should only be called after " 1328 throw new StateError("remainingStdout() should only be called after "
1362 "kill() or shouldExit()."); 1329 "kill() or shouldExit().");
1363 } 1330 }
1364 1331
1365 return _scheduleValue((_) { 1332 return _scheduleValue((_) {
1366 return timeout(_stdoutFuture.then((stream) => stream.toList()) 1333 return timeout(_stdoutFuture.then(consumeStringInputStream),
1367 .then((lines) => lines.join("\n")),
1368 _SCHEDULE_TIMEOUT, 1334 _SCHEDULE_TIMEOUT,
1369 "waiting for the last stdout line from process $name"); 1335 "waiting for the last stdout line from process $name");
1370 }); 1336 });
1371 } 1337 }
1372 1338
1373 /// Reads the remaining stderr from the process. This should only be called 1339 /// Reads the remaining stderr from the process. This should only be called
1374 /// after kill() or shouldExit(). 1340 /// after kill() or shouldExit().
1375 Future<String> remainingStderr() { 1341 Future<String> remainingStderr() {
1376 if (!_endScheduled) { 1342 if (!_endScheduled) {
1377 throw new StateError("remainingStderr() should only be called after " 1343 throw new StateError("remainingStderr() should only be called after "
1378 "kill() or shouldExit()."); 1344 "kill() or shouldExit().");
1379 } 1345 }
1380 1346
1381 return _scheduleValue((_) { 1347 return _scheduleValue((_) {
1382 return timeout(_stderrFuture.then((stream) => stream.toList()) 1348 return timeout(_stderrFuture.then(consumeStringInputStream),
1383 .then((lines) => lines.join("\n")),
1384 _SCHEDULE_TIMEOUT, 1349 _SCHEDULE_TIMEOUT,
1385 "waiting for the last stderr line from process $name"); 1350 "waiting for the last stderr line from process $name");
1386 }); 1351 });
1387 } 1352 }
1388 1353
1389 /// Writes [line] to the process as stdin. 1354 /// Writes [line] to the process as stdin.
1390 void writeLine(String line) { 1355 void writeLine(String line) {
1391 _schedule((_) => _processFuture.then( 1356 _schedule((_) => _processFuture.then(
1392 (p) => p.stdin.write('$line\n'.charCodes))); 1357 (p) => p.stdin.writeString('$line\n')));
1393 } 1358 }
1394 1359
1395 /// Kills the process, and waits until it's dead. 1360 /// Kills the process, and waits until it's dead.
1396 void kill() { 1361 void kill() {
1397 _endScheduled = true; 1362 _endScheduled = true;
1398 _schedule((_) { 1363 _schedule((_) {
1399 _endExpected = true; 1364 _endExpected = true;
1400 _process.kill(); 1365 _process.kill();
1401 timeout(_exitCodeFuture, _SCHEDULE_TIMEOUT, 1366 timeout(_exitCodeCompleter.future, _SCHEDULE_TIMEOUT,
1402 "waiting for process $name to die"); 1367 "waiting for process $name to die");
1403 }); 1368 });
1404 } 1369 }
1405 1370
1406 /// Waits for the process to exit, and verifies that the exit code matches 1371 /// Waits for the process to exit, and verifies that the exit code matches
1407 /// [expectedExitCode] (if given). 1372 /// [expectedExitCode] (if given).
1408 void shouldExit([int expectedExitCode]) { 1373 void shouldExit([int expectedExitCode]) {
1409 _endScheduled = true; 1374 _endScheduled = true;
1410 _schedule((_) { 1375 _schedule((_) {
1411 _endExpected = true; 1376 _endExpected = true;
1412 return timeout(_exitCodeFuture, _SCHEDULE_TIMEOUT, 1377 return timeout(_exitCodeCompleter.future, _SCHEDULE_TIMEOUT,
1413 "waiting for process $name to exit").then((exitCode) { 1378 "waiting for process $name to exit").then((exitCode) {
1414 if (expectedExitCode != null) { 1379 if (expectedExitCode != null) {
1415 expect(exitCode, equals(expectedExitCode)); 1380 expect(exitCode, equals(expectedExitCode));
1416 } 1381 }
1417 }); 1382 });
1418 }); 1383 });
1419 } 1384 }
1420 1385
1421 /// Prints the remaining data in the process's stdout and stderr streams. 1386 /// Prints the remaining data in the process's stdout and stderr streams.
1422 /// Prints nothing if the streams are empty. 1387 /// Prints nothing if the straems are empty.
1423 Future _printStreams() { 1388 Future _printStreams() {
1424 void printStream(String streamName, List<String> lines) { 1389 Future printStream(String streamName, StringInputStream stream) {
1425 if (lines.isEmpty) return; 1390 return consumeStringInputStream(stream).then((output) {
1391 if (output.isEmpty) return;
1426 1392
1427 print('\nProcess $name $streamName:'); 1393 print('\nProcess $name $streamName:');
1428 for (var line in lines) { 1394 for (var line in output.trim().split("\n")) {
1429 print('| $line'); 1395 print('| $line');
1430 } 1396 }
1397 return;
1398 });
1431 } 1399 }
1432 1400
1433 return _stdoutLines.then((stdoutLines) { 1401 return _stdoutFuture.then((stdout) {
1434 printStream('stdout', stdoutLines); 1402 return _stderrFuture.then((stderr) {
1435 return _stderrLines.then((stderrLines) { 1403 return printStream('stdout', stdout)
1436 printStream('stderr', stderrLines); 1404 .then((_) => printStream('stderr', stderr));
1437 }); 1405 });
1438 }); 1406 });
1439 } 1407 }
1440 } 1408 }
1441 1409
1442 /// A class representing an [HttpServer] that's scheduled to run in the course 1410 /// A class representing an [HttpServer] that's scheduled to run in the course
1443 /// of the test. This class allows the server's request handling to be 1411 /// of the test. This class allows the server's request handling to be
1444 /// scheduled synchronously. All operations on this class are scheduled. 1412 /// scheduled synchronously. All operations on this class are scheduled.
1445 class ScheduledServer { 1413 class ScheduledServer {
1446 /// The wrapped server. 1414 /// The wrapped server.
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
1583 /// calling [completion] is unnecessary. 1551 /// calling [completion] is unnecessary.
1584 void expectLater(Future actual, matcher, {String reason, 1552 void expectLater(Future actual, matcher, {String reason,
1585 FailureHandler failureHandler, bool verbose: false}) { 1553 FailureHandler failureHandler, bool verbose: false}) {
1586 _schedule((_) { 1554 _schedule((_) {
1587 return actual.then((value) { 1555 return actual.then((value) {
1588 expect(value, matcher, reason: reason, failureHandler: failureHandler, 1556 expect(value, matcher, reason: reason, failureHandler: failureHandler,
1589 verbose: false); 1557 verbose: false);
1590 }); 1558 });
1591 }); 1559 });
1592 } 1560 }
OLDNEW
« no previous file with comments | « utils/tests/pub/pub_uploader_test.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698