OLD | NEW |
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 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 for (var spec in resolvedPubspecs) { | 163 for (var spec in resolvedPubspecs) { |
164 var name = spec['name']; | 164 var name = spec['name']; |
165 var version = spec['version']; | 165 var version = spec['version']; |
166 var versions = _servedPackages.putIfAbsent( | 166 var versions = _servedPackages.putIfAbsent( |
167 name, () => <String, String>{}); | 167 name, () => <String, String>{}); |
168 versions[version] = yaml(spec); | 168 versions[version] = yaml(spec); |
169 } | 169 } |
170 | 170 |
171 _servedPackageDir.contents.clear(); | 171 _servedPackageDir.contents.clear(); |
172 for (var name in _servedPackages.keys) { | 172 for (var name in _servedPackages.keys) { |
173 var versions = _servedPackages[name].keys.toList()); | 173 var versions = _servedPackages[name].keys.toList(); |
174 _servedPackageDir.contents.addAll([ | 174 _servedPackageDir.contents.addAll([ |
175 file('$name.json', | 175 file('$name.json', |
176 json.stringify({'versions': versions})), | 176 json.stringify({'versions': versions})), |
177 dir(name, [ | 177 dir(name, [ |
178 dir('versions', flatten(versions.mappedBy((version) { | 178 dir('versions', flatten(versions.mappedBy((version) { |
179 return [ | 179 return [ |
180 file('$version.yaml', _servedPackages[name][version]), | 180 file('$version.yaml', _servedPackages[name][version]), |
181 tar('$version.tar.gz', [ | 181 tar('$version.tar.gz', [ |
182 file('pubspec.yaml', _servedPackages[name][version]), | 182 file('pubspec.yaml', _servedPackages[name][version]), |
183 libDir(name, '$name $version') | 183 libDir(name, '$name $version') |
(...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
458 if (createdSandboxDir != null) return deleteDir(createdSandboxDir); | 458 if (createdSandboxDir != null) return deleteDir(createdSandboxDir); |
459 return new Future.immediate(null); | 459 return new Future.immediate(null); |
460 }); | 460 }); |
461 } | 461 } |
462 | 462 |
463 final future = _setUpSandbox().then((sandboxDir) { | 463 final future = _setUpSandbox().then((sandboxDir) { |
464 createdSandboxDir = sandboxDir; | 464 createdSandboxDir = sandboxDir; |
465 return _runScheduled(sandboxDir, _scheduled); | 465 return _runScheduled(sandboxDir, _scheduled); |
466 }); | 466 }); |
467 | 467 |
468 future.catchError((error) { | 468 future.catchError((e) { |
469 // If an error occurs during testing, delete the sandbox, throw the error so | 469 // If an error occurs during testing, delete the sandbox, throw the error so |
470 // that the test framework sees it, then finally call asyncDone so that the | 470 // that the test framework sees it, then finally call asyncDone so that the |
471 // test framework knows we're done doing asynchronous stuff. | 471 // test framework knows we're done doing asynchronous stuff. |
472 var subFuture = _runScheduled(createdSandboxDir, _scheduledOnException) | 472 var subFuture = _runScheduled(createdSandboxDir, _scheduledOnException) |
473 .then((_) => cleanup()); | 473 .then((_) => cleanup()); |
474 subFuture.catchError((e) { | 474 subFuture.catchError((e) { |
475 print("Exception while cleaning up: ${e.error}"); | 475 print("Exception while cleaning up: ${e.error}"); |
476 print(e.stackTrace); | 476 print(e.stackTrace); |
477 registerException(e.error, e.stackTrace); | 477 registerException(e.error, e.stackTrace); |
478 return true; | 478 return true; |
479 }); | 479 }); |
| 480 subFuture.then((_) => registerException(e.error, e.stackTrace)); |
| 481 return true; |
| 482 }); |
| 483 |
480 timeout(future, _TIMEOUT, 'waiting for a test to complete') | 484 timeout(future, _TIMEOUT, 'waiting for a test to complete') |
481 .then((_) => cleanup()) | 485 .then((_) => cleanup()) |
482 .then((_) => asyncDone()); | 486 .then((_) => asyncDone()); |
483 } | 487 } |
484 | 488 |
485 /// Get the path to the root "util/test/pub" directory containing the pub | 489 /// Get the path to the root "util/test/pub" directory containing the pub |
486 /// tests. | 490 /// tests. |
487 String get testDirectory { | 491 String get testDirectory { |
488 var dir = new Options().script; | 492 var dir = new Options().script; |
489 while (basename(dir) != 'pub') dir = dirname(dir); | 493 while (basename(dir) != 'pub') dir = dirname(dir); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
541 _doPub(startProcess, sandboxDir, args, tokenEndpoint)); | 545 _doPub(startProcess, sandboxDir, args, tokenEndpoint)); |
542 return new ScheduledProcess("pub", process); | 546 return new ScheduledProcess("pub", process); |
543 } | 547 } |
544 | 548 |
545 /// Like [startPub], but runs `pub lish` in particular with [server] used both | 549 /// Like [startPub], but runs `pub lish` in particular with [server] used both |
546 /// as the OAuth2 server (with "/token" as the token endpoint) and as the | 550 /// as the OAuth2 server (with "/token" as the token endpoint) and as the |
547 /// package server. | 551 /// package server. |
548 /// | 552 /// |
549 /// Any futures in [args] will be resolved before the process is started. | 553 /// Any futures in [args] will be resolved before the process is started. |
550 ScheduledProcess startPubLish(ScheduledServer server, {List args}) { | 554 ScheduledProcess startPubLish(ScheduledServer server, {List args}) { |
551 var tokenEndpoint = server.url.transform((url) => | 555 var tokenEndpoint = server.url.then((url) => |
552 url.resolve('/token').toString()); | 556 url.resolve('/token').toString()); |
553 if (args == null) args = []; | 557 if (args == null) args = []; |
554 args = flatten(['lish', '--server', tokenEndpoint, args]); | 558 args = flatten(['lish', '--server', tokenEndpoint, args]); |
555 return startPub(args: args, tokenEndpoint: tokenEndpoint); | 559 return startPub(args: args, tokenEndpoint: tokenEndpoint); |
556 } | 560 } |
557 | 561 |
558 /// Handles the beginning confirmation process for uploading a packages. | 562 /// Handles the beginning confirmation process for uploading a packages. |
559 /// Ensures that the right output is shown and then enters "y" to confirm the | 563 /// Ensures that the right output is shown and then enters "y" to confirm the |
560 /// upload. | 564 /// upload. |
561 void confirmPublish(ScheduledProcess pub) { | 565 void confirmPublish(ScheduledProcess pub) { |
(...skipping 13 matching lines...) Expand all Loading... |
575 /// Calls [fn] with appropriately modified arguments to run a pub process. [fn] | 579 /// Calls [fn] with appropriately modified arguments to run a pub process. [fn] |
576 /// should have the same signature as [startProcess], except that the returned | 580 /// should have the same signature as [startProcess], except that the returned |
577 /// [Future] may have a type other than [Process]. | 581 /// [Future] may have a type other than [Process]. |
578 Future _doPub(Function fn, sandboxDir, List args, Future<Uri> tokenEndpoint) { | 582 Future _doPub(Function fn, sandboxDir, List args, Future<Uri> tokenEndpoint) { |
579 String pathInSandbox(path) => join(getFullPath(sandboxDir), path); | 583 String pathInSandbox(path) => join(getFullPath(sandboxDir), path); |
580 | 584 |
581 return Futures.wait([ | 585 return Futures.wait([ |
582 ensureDir(pathInSandbox(appPath)), | 586 ensureDir(pathInSandbox(appPath)), |
583 _awaitObject(args), | 587 _awaitObject(args), |
584 tokenEndpoint == null ? new Future.immediate(null) : tokenEndpoint | 588 tokenEndpoint == null ? new Future.immediate(null) : tokenEndpoint |
585 ]).chain((results) { | 589 ]).then((results) { |
586 var args = results[1]; | 590 var args = results[1]; |
587 var tokenEndpoint = results[2]; | 591 var tokenEndpoint = results[2]; |
588 // Find a Dart executable we can use to spawn. Use the same one that was | 592 // Find a Dart executable we can use to spawn. Use the same one that was |
589 // used to run this script itself. | 593 // used to run this script itself. |
590 var dartBin = new Options().executable; | 594 var dartBin = new Options().executable; |
591 | 595 |
592 // If the executable looks like a path, get its full path. That way we | 596 // If the executable looks like a path, get its full path. That way we |
593 // can still find it when we spawn it with a different working directory. | 597 // can still find it when we spawn it with a different working directory. |
594 if (dartBin.contains(Platform.pathSeparator)) { | 598 if (dartBin.contains(Platform.pathSeparator)) { |
595 dartBin = new File(dartBin).fullPathSync(); | 599 dartBin = new File(dartBin).fullPathSync(); |
(...skipping 557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1153 /// Schedules a single [Validator] to run on the [appPath]. Returns a scheduled | 1157 /// Schedules a single [Validator] to run on the [appPath]. Returns a scheduled |
1154 /// Future that contains the erros and warnings produced by that validator. | 1158 /// Future that contains the erros and warnings produced by that validator. |
1155 Future<Pair<List<String>, List<String>>> schedulePackageValidation( | 1159 Future<Pair<List<String>, List<String>>> schedulePackageValidation( |
1156 ValidatorCreator fn) { | 1160 ValidatorCreator fn) { |
1157 return _scheduleValue((sandboxDir) { | 1161 return _scheduleValue((sandboxDir) { |
1158 var cache = new SystemCache.withSources( | 1162 var cache = new SystemCache.withSources( |
1159 join(sandboxDir, cachePath), | 1163 join(sandboxDir, cachePath), |
1160 join(sandboxDir, sdkPath)); | 1164 join(sandboxDir, sdkPath)); |
1161 | 1165 |
1162 return Entrypoint.load(join(sandboxDir, appPath), cache) | 1166 return Entrypoint.load(join(sandboxDir, appPath), cache) |
1163 .chain((entrypoint) { | 1167 .then((entrypoint) { |
1164 var validator = fn(entrypoint); | 1168 var validator = fn(entrypoint); |
1165 return validator.validate().then((_) { | 1169 return validator.validate().then((_) { |
1166 return new Pair(validator.errors, validator.warnings); | 1170 return new Pair(validator.errors, validator.warnings); |
1167 }); | 1171 }); |
1168 }); | 1172 }); |
1169 }); | 1173 }); |
1170 } | 1174 } |
1171 | 1175 |
1172 /// A matcher that matches a Pair. | 1176 /// A matcher that matches a Pair. |
1173 Matcher pairOf(Matcher firstMatcher, Matcher lastMatcher) => | 1177 Matcher pairOf(Matcher firstMatcher, Matcher lastMatcher) => |
(...skipping 26 matching lines...) Expand all Loading... |
1200 /// | 1204 /// |
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 that's scheduled to run. | 1214 /// The process future that's scheduled to run. |
1211 final Future<Process> _process; | 1215 Future<Process> _processFuture; |
| 1216 |
| 1217 /// The process that's scheduled to run. It may be null. |
| 1218 Process _process; |
| 1219 |
| 1220 /// The exit code of the scheduled program. It may be null. |
| 1221 int _exitCode; |
1212 | 1222 |
1213 /// A [StringInputStream] wrapping the stdout of the process that's scheduled | 1223 /// A [StringInputStream] wrapping the stdout of the process that's scheduled |
1214 /// to run. | 1224 /// to run. |
1215 final Future<StringInputStream> _stdout; | 1225 final Future<StringInputStream> _stdoutFuture; |
1216 | 1226 |
1217 /// A [StringInputStream] wrapping the stderr of the process that's scheduled | 1227 /// A [StringInputStream] wrapping the stderr of the process that's scheduled |
1218 /// to run. | 1228 /// to run. |
1219 final Future<StringInputStream> _stderr; | 1229 final Future<StringInputStream> _stderrFuture; |
1220 | 1230 |
1221 /// 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 |
1222 /// only complete once the process has terminated. | 1232 /// only complete once the process has terminated. |
1223 Future<int> get _exitCode => _exitCodeCompleter.future; | 1233 Future<int> get _exitCodeFuture => _exitCodeCompleter.future; |
1224 | 1234 |
1225 /// The completer for [_exitCode]. | 1235 /// The completer for [_exitCode]. |
1226 final Completer<int> _exitCodeCompleter = new Completer(); | 1236 final Completer<int> _exitCodeCompleter = new Completer(); |
1227 | 1237 |
1228 /// 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 |
1229 /// [shouldExit] or [kill]. | 1239 /// [shouldExit] or [kill]. |
1230 bool _endScheduled = false; | 1240 bool _endScheduled = false; |
1231 | 1241 |
1232 /// Whether the process is expected to terminate at this point. | 1242 /// Whether the process is expected to terminate at this point. |
1233 bool _endExpected = false; | 1243 bool _endExpected = false; |
1234 | 1244 |
1235 /// Wraps a [Process] [Future] in a scheduled process. | 1245 /// Wraps a [Process] [Future] in a scheduled process. |
1236 ScheduledProcess(this.name, Future<Process> process) | 1246 ScheduledProcess(this.name, Future<Process> process) |
1237 : _process = process, | 1247 : _processFuture = process, |
1238 _stdout = process.then((p) => new StringInputStream(p.stdout)), | 1248 _stdoutFuture = process.then((p) => new StringInputStream(p.stdout)), |
1239 _stderr = process.then((p) => new StringInputStream(p.stderr)) { | 1249 _stderrFuture = process.then((p) => new StringInputStream(p.stderr)) { |
| 1250 process.then((p) { |
| 1251 _process = p; |
| 1252 }); |
1240 | 1253 |
1241 _schedule((_) { | 1254 _schedule((_) { |
1242 if (!_endScheduled) { | 1255 if (!_endScheduled) { |
1243 throw new StateError("Scheduled process $name must have shouldExit() " | 1256 throw new StateError("Scheduled process $name must have shouldExit() " |
1244 "or kill() called before the test is run."); | 1257 "or kill() called before the test is run."); |
1245 } | 1258 } |
1246 | 1259 |
1247 return _process.then((p) { | 1260 return process.then((p) { |
1248 p.onExit = (c) { | 1261 p.onExit = (c) { |
1249 if (_endExpected) { | 1262 if (_endExpected) { |
| 1263 _exitCode = c; |
1250 _exitCodeCompleter.complete(c); | 1264 _exitCodeCompleter.complete(c); |
1251 return; | 1265 return; |
1252 } | 1266 } |
1253 | 1267 |
1254 // Sleep for half a second in case _endExpected is set in the next | 1268 // Sleep for half a second in case _endExpected is set in the next |
1255 // scheduled event. | 1269 // scheduled event. |
1256 sleep(500).then((_) { | 1270 sleep(500).then((_) { |
1257 if (_endExpected) { | 1271 if (_endExpected) { |
1258 _exitCodeCompleter.complete(c); | 1272 _exitCodeCompleter.complete(c); |
1259 return; | 1273 return; |
1260 } | 1274 } |
1261 | 1275 |
1262 _printStreams().then((_) { | 1276 _printStreams().then((_) { |
1263 registerException(new ExpectException("Process $name ended " | 1277 registerException(new ExpectException("Process $name ended " |
1264 "earlier than scheduled with exit code $c")); | 1278 "earlier than scheduled with exit code $c")); |
1265 }); | 1279 }); |
1266 }); | 1280 }); |
1267 }; | 1281 }; |
1268 }); | 1282 }); |
1269 }); | 1283 }); |
1270 | 1284 |
1271 _scheduleOnException((_) { | 1285 _scheduleOnException((_) { |
1272 if (!_process.hasValue) return; | 1286 if (_process == null) return; |
1273 | 1287 |
1274 if (!_exitCode.hasValue) { | 1288 if (_exitCode == null) { |
1275 print("\nKilling process $name prematurely."); | 1289 print("\nKilling process $name prematurely."); |
1276 _endExpected = true; | 1290 _endExpected = true; |
1277 _process.value.kill(); | 1291 _process.kill(); |
1278 } | 1292 } |
1279 | 1293 |
1280 return _printStreams(); | 1294 return _printStreams(); |
1281 }); | 1295 }); |
1282 | 1296 |
1283 _scheduleCleanup((_) { | 1297 _scheduleCleanup((_) { |
1284 if (!_process.hasValue) return; | 1298 if (_process == null) return; |
1285 // 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. |
1286 var process = _process.value; | 1300 _process.kill(); |
1287 process.kill(); | 1301 _process.stdout.close(); |
1288 process.stdout.close(); | 1302 _process.stderr.close(); |
1289 process.stderr.close(); | |
1290 }); | 1303 }); |
1291 } | 1304 } |
1292 | 1305 |
1293 /// Reads the next line of stdout from the process. | 1306 /// Reads the next line of stdout from the process. |
1294 Future<String> nextLine() { | 1307 Future<String> nextLine() { |
1295 return _scheduleValue((_) { | 1308 return _scheduleValue((_) { |
1296 return timeout(_stdout.chain((stream) => readLine(stream)), | 1309 return timeout(_stdoutFuture.then((stream) => readLine(stream)), |
1297 _SCHEDULE_TIMEOUT, | 1310 _SCHEDULE_TIMEOUT, |
1298 "waiting for the next stdout line from process $name"); | 1311 "waiting for the next stdout line from process $name"); |
1299 }); | 1312 }); |
1300 } | 1313 } |
1301 | 1314 |
1302 /// Reads the next line of stderr from the process. | 1315 /// Reads the next line of stderr from the process. |
1303 Future<String> nextErrLine() { | 1316 Future<String> nextErrLine() { |
1304 return _scheduleValue((_) { | 1317 return _scheduleValue((_) { |
1305 return timeout(_stderr.chain((stream) => readLine(stream)), | 1318 return timeout(_stderrFuture.then((stream) => readLine(stream)), |
1306 _SCHEDULE_TIMEOUT, | 1319 _SCHEDULE_TIMEOUT, |
1307 "waiting for the next stderr line from process $name"); | 1320 "waiting for the next stderr line from process $name"); |
1308 }); | 1321 }); |
1309 } | 1322 } |
1310 | 1323 |
1311 /// 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 |
1312 /// after kill() or shouldExit(). | 1325 /// after kill() or shouldExit(). |
1313 Future<String> remainingStdout() { | 1326 Future<String> remainingStdout() { |
1314 if (!_endScheduled) { | 1327 if (!_endScheduled) { |
1315 throw new StateError("remainingStdout() should only be called after " | 1328 throw new StateError("remainingStdout() should only be called after " |
1316 "kill() or shouldExit()."); | 1329 "kill() or shouldExit()."); |
1317 } | 1330 } |
1318 | 1331 |
1319 return _scheduleValue((_) { | 1332 return _scheduleValue((_) { |
1320 return timeout(_stdout.chain(consumeStringInputStream), _SCHEDULE_TIMEOUT, | 1333 return timeout(_stdoutFuture.then(consumeStringInputStream), |
| 1334 _SCHEDULE_TIMEOUT, |
1321 "waiting for the last stdout line from process $name"); | 1335 "waiting for the last stdout line from process $name"); |
1322 }); | 1336 }); |
1323 } | 1337 } |
1324 | 1338 |
1325 /// 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 |
1326 /// after kill() or shouldExit(). | 1340 /// after kill() or shouldExit(). |
1327 Future<String> remainingStderr() { | 1341 Future<String> remainingStderr() { |
1328 if (!_endScheduled) { | 1342 if (!_endScheduled) { |
1329 throw new StateError("remainingStderr() should only be called after " | 1343 throw new StateError("remainingStderr() should only be called after " |
1330 "kill() or shouldExit()."); | 1344 "kill() or shouldExit()."); |
1331 } | 1345 } |
1332 | 1346 |
1333 return _scheduleValue((_) { | 1347 return _scheduleValue((_) { |
1334 return timeout(_stderr.chain(consumeStringInputStream), _SCHEDULE_TIMEOUT, | 1348 return timeout(_stderrFuture.then(consumeStringInputStream), |
| 1349 _SCHEDULE_TIMEOUT, |
1335 "waiting for the last stderr line from process $name"); | 1350 "waiting for the last stderr line from process $name"); |
1336 }); | 1351 }); |
1337 } | 1352 } |
1338 | 1353 |
1339 /// Writes [line] to the process as stdin. | 1354 /// Writes [line] to the process as stdin. |
1340 void writeLine(String line) { | 1355 void writeLine(String line) { |
1341 _schedule((_) => _process.then((p) => p.stdin.writeString('$line\n'))); | 1356 _schedule((_) => _processFuture.then( |
| 1357 (p) => p.stdin.writeString('$line\n'))); |
1342 } | 1358 } |
1343 | 1359 |
1344 /// Kills the process, and waits until it's dead. | 1360 /// Kills the process, and waits until it's dead. |
1345 void kill() { | 1361 void kill() { |
1346 _endScheduled = true; | 1362 _endScheduled = true; |
1347 _schedule((_) { | 1363 _schedule((_) { |
1348 _endExpected = true; | 1364 _endExpected = true; |
1349 return _process.chain((p) { | 1365 _process.kill(); |
1350 p.kill(); | 1366 timeout(_exitCodeCompleter.future, _SCHEDULE_TIMEOUT, |
1351 return timeout(_exitCode, _SCHEDULE_TIMEOUT, | 1367 "waiting for process $name to die"); |
1352 "waiting for process $name to die"); | |
1353 }); | |
1354 }); | 1368 }); |
1355 } | 1369 } |
1356 | 1370 |
1357 /// 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 |
1358 /// [expectedExitCode] (if given). | 1372 /// [expectedExitCode] (if given). |
1359 void shouldExit([int expectedExitCode]) { | 1373 void shouldExit([int expectedExitCode]) { |
1360 _endScheduled = true; | 1374 _endScheduled = true; |
1361 _schedule((_) { | 1375 _schedule((_) { |
1362 _endExpected = true; | 1376 _endExpected = true; |
1363 return timeout(_exitCode, _SCHEDULE_TIMEOUT, | 1377 return timeout(_exitCodeCompleter.future, _SCHEDULE_TIMEOUT, |
1364 "waiting for process $name to exit").then((exitCode) { | 1378 "waiting for process $name to exit").then((exitCode) { |
1365 if (expectedExitCode != null) { | 1379 if (expectedExitCode != null) { |
1366 expect(exitCode, equals(expectedExitCode)); | 1380 expect(exitCode, equals(expectedExitCode)); |
1367 } | 1381 } |
1368 }); | 1382 }); |
1369 }); | 1383 }); |
1370 } | 1384 } |
1371 | 1385 |
1372 /// 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. |
1373 /// Prints nothing if the straems are empty. | 1387 /// Prints nothing if the straems are empty. |
1374 Future _printStreams() { | 1388 Future _printStreams() { |
1375 Future printStream(String streamName, StringInputStream stream) { | 1389 Future printStream(String streamName, StringInputStream stream) { |
1376 return consumeStringInputStream(stream).then((output) { | 1390 return consumeStringInputStream(stream).then((output) { |
1377 if (output.isEmpty) return; | 1391 if (output.isEmpty) return; |
1378 | 1392 |
1379 print('\nProcess $name $streamName:'); | 1393 print('\nProcess $name $streamName:'); |
1380 for (var line in output.trim().split("\n")) { | 1394 for (var line in output.trim().split("\n")) { |
1381 print('| $line'); | 1395 print('| $line'); |
1382 } | 1396 } |
1383 return; | 1397 return; |
1384 }); | 1398 }); |
1385 } | 1399 } |
1386 | 1400 |
1387 return printStream('stdout', _stdout.value) | 1401 return _stdoutFuture.then((stdout) { |
1388 .chain((_) => printStream('stderr', _stderr.value)); | 1402 return _stderrFuture.then((stderr) { |
| 1403 return printStream('stdout', stdout) |
| 1404 .then((_) => printStream('stderr', stderr)); |
| 1405 }); |
| 1406 }); |
1389 } | 1407 } |
1390 } | 1408 } |
1391 | 1409 |
1392 /// 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 |
1393 /// 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 |
1394 /// scheduled synchronously. All operations on this class are scheduled. | 1412 /// scheduled synchronously. All operations on this class are scheduled. |
1395 class ScheduledServer { | 1413 class ScheduledServer { |
1396 /// The wrapped server. | 1414 /// The wrapped server. |
1397 final Future<HttpServer> _server; | 1415 final Future<HttpServer> _server; |
1398 | 1416 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1449 } | 1467 } |
1450 | 1468 |
1451 /// Ignore all requests with the given [method] and [path]. If one is | 1469 /// Ignore all requests with the given [method] and [path]. If one is |
1452 /// received, don't respond to it. | 1470 /// received, don't respond to it. |
1453 void ignore(String method, String path) => | 1471 void ignore(String method, String path) => |
1454 _ignored.add(new Pair(method, path)); | 1472 _ignored.add(new Pair(method, path)); |
1455 | 1473 |
1456 /// Raises an error complaining of an unexpected request. | 1474 /// Raises an error complaining of an unexpected request. |
1457 void _awaitHandle(HttpRequest request, HttpResponse response) { | 1475 void _awaitHandle(HttpRequest request, HttpResponse response) { |
1458 if (_ignored.contains(new Pair(request.method, request.path))) return; | 1476 if (_ignored.contains(new Pair(request.method, request.path))) return; |
1459 var future = timeout(new Future.immediate(null).chain((_) { | 1477 var future = timeout(new Future.immediate(null).then((_) { |
1460 if (_handlers.isEmpty) { | 1478 if (_handlers.isEmpty) { |
1461 fail('Unexpected ${request.method} request to ${request.path}.'); | 1479 fail('Unexpected ${request.method} request to ${request.path}.'); |
1462 } | 1480 } |
1463 return _handlers.removeFirst(); | 1481 return _handlers.removeFirst(); |
1464 }).then((handler) { | 1482 }).then((handler) { |
1465 handler(request, response); | 1483 handler(request, response); |
1466 }), _SCHEDULE_TIMEOUT, "waiting for a handler for ${request.method} " | 1484 }), _SCHEDULE_TIMEOUT, "waiting for a handler for ${request.method} " |
1467 "${request.path}"); | 1485 "${request.path}"); |
1468 expect(future, completes); | 1486 expect(future, completes); |
1469 } | 1487 } |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1533 /// calling [completion] is unnecessary. | 1551 /// calling [completion] is unnecessary. |
1534 void expectLater(Future actual, matcher, {String reason, | 1552 void expectLater(Future actual, matcher, {String reason, |
1535 FailureHandler failureHandler, bool verbose: false}) { | 1553 FailureHandler failureHandler, bool verbose: false}) { |
1536 _schedule((_) { | 1554 _schedule((_) { |
1537 return actual.then((value) { | 1555 return actual.then((value) { |
1538 expect(value, matcher, reason: reason, failureHandler: failureHandler, | 1556 expect(value, matcher, reason: reason, failureHandler: failureHandler, |
1539 verbose: false); | 1557 verbose: false); |
1540 }); | 1558 }); |
1541 }); | 1559 }); |
1542 } | 1560 } |
OLD | NEW |