| 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 /// Test infrastructure for testing pub. | 5 /// Test infrastructure for testing pub. |
| 6 /// | 6 /// |
| 7 /// Unlike typical unit tests, most pub tests are integration tests that stage | 7 /// Unlike typical unit tests, most pub tests are integration tests that stage |
| 8 /// some stuff on the file system, run pub, and then validate the results. This | 8 /// some stuff on the file system, run pub, and then validate the results. This |
| 9 /// library provides an API to build tests like that. | 9 /// library provides an API to build tests like that. |
| 10 import 'dart:async'; | 10 import 'dart:async'; |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 212 schedule( | 212 schedule( |
| 213 () => createSymlink( | 213 () => createSymlink( |
| 214 p.join(sandboxDir, target), | 214 p.join(sandboxDir, target), |
| 215 p.join(sandboxDir, symlink)), | 215 p.join(sandboxDir, symlink)), |
| 216 'symlinking $target to $symlink'); | 216 'symlinking $target to $symlink'); |
| 217 } | 217 } |
| 218 | 218 |
| 219 /// Schedules a call to the Pub command-line utility. | 219 /// Schedules a call to the Pub command-line utility. |
| 220 /// | 220 /// |
| 221 /// Runs Pub with [args] and validates that its results match [output] (or | 221 /// Runs Pub with [args] and validates that its results match [output] (or |
| 222 /// [outputJson]), [error], and [exitCode]. | 222 /// [outputJson]), [error], [silent] (for logs that are silent by default), and |
| 223 /// [exitCode]. |
| 223 /// | 224 /// |
| 224 /// [output] and [error] can be [String]s, [RegExp]s, or [Matcher]s. | 225 /// [output], [error], and [silent] can be [String]s, [RegExp]s, or [Matcher]s. |
| 225 /// | 226 /// |
| 226 /// If [outputJson] is given, validates that pub outputs stringified JSON | 227 /// If [outputJson] is given, validates that pub outputs stringified JSON |
| 227 /// matching that object, which can be a literal JSON object or any other | 228 /// matching that object, which can be a literal JSON object or any other |
| 228 /// [Matcher]. | 229 /// [Matcher]. |
| 229 /// | 230 /// |
| 230 /// If [environment] is given, any keys in it will override the environment | 231 /// If [environment] is given, any keys in it will override the environment |
| 231 /// variables passed to the spawned process. | 232 /// variables passed to the spawned process. |
| 232 void schedulePub({List args, output, error, outputJson, | 233 void schedulePub({List args, output, error, outputJson, silent, |
| 233 int exitCode: exit_codes.SUCCESS, Map<String, String> environment}) { | 234 int exitCode: exit_codes.SUCCESS, Map<String, String> environment}) { |
| 234 // Cannot pass both output and outputJson. | 235 // Cannot pass both output and outputJson. |
| 235 assert(output == null || outputJson == null); | 236 assert(output == null || outputJson == null); |
| 236 | 237 |
| 237 var pub = startPub(args: args, environment: environment); | 238 var pub = startPub(args: args, environment: environment); |
| 238 pub.shouldExit(exitCode); | 239 pub.shouldExit(exitCode); |
| 239 | 240 |
| 240 var failures = []; | 241 expect(() async { |
| 241 var stderr; | 242 var actualOutput = (await pub.stdoutStream().toList()).join("\n"); |
| 243 var actualError = (await pub.stderrStream().toList()).join("\n"); |
| 244 var actualSilent = (await pub.silentStream().toList()).join("\n"); |
| 242 | 245 |
| 243 expect(Future.wait([ | 246 var failures = []; |
| 244 pub.stdoutStream().toList(), | |
| 245 pub.stderrStream().toList() | |
| 246 ]).then((results) { | |
| 247 var stdout = results[0].join("\n"); | |
| 248 stderr = results[1].join("\n"); | |
| 249 | |
| 250 if (outputJson == null) { | 247 if (outputJson == null) { |
| 251 _validateOutput(failures, 'stdout', output, stdout); | 248 _validateOutput(failures, 'stdout', output, actualOutput); |
| 252 return null; | 249 } else { |
| 250 _validateOutputJson( |
| 251 failures, 'stdout', await awaitObject(outputJson), actualOutput); |
| 253 } | 252 } |
| 254 | 253 |
| 255 // Allow the expected JSON to contain futures. | 254 _validateOutput(failures, 'stderr', error, actualError); |
| 256 return awaitObject(outputJson).then((resolved) { | 255 _validateOutput(failures, 'silent', silent, actualSilent); |
| 257 _validateOutputJson(failures, 'stdout', resolved, stdout); | |
| 258 }); | |
| 259 }).then((_) { | |
| 260 _validateOutput(failures, 'stderr', error, stderr); | |
| 261 | 256 |
| 262 if (!failures.isEmpty) throw new TestFailure(failures.join('\n')); | 257 if (!failures.isEmpty) throw new TestFailure(failures.join('\n')); |
| 263 }), completes); | 258 }(), completes); |
| 264 } | 259 } |
| 265 | 260 |
| 266 /// Like [startPub], but runs `pub lish` in particular with [server] used both | 261 /// Like [startPub], but runs `pub lish` in particular with [server] used both |
| 267 /// as the OAuth2 server (with "/token" as the token endpoint) and as the | 262 /// as the OAuth2 server (with "/token" as the token endpoint) and as the |
| 268 /// package server. | 263 /// package server. |
| 269 /// | 264 /// |
| 270 /// Any futures in [args] will be resolved before the process is started. | 265 /// Any futures in [args] will be resolved before the process is started. |
| 271 ScheduledProcess startPublish(ScheduledServer server, {List args}) { | 266 ScheduledProcess startPublish(ScheduledServer server, {List args}) { |
| 272 var tokenEndpoint = server.url.then((url) => | 267 var tokenEndpoint = server.url.then((url) => |
| 273 url.resolve('/token').toString()); | 268 url.resolve('/token').toString()); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 366 description: args.isEmpty ? 'pub' : 'pub ${args.first}'); | 361 description: args.isEmpty ? 'pub' : 'pub ${args.first}'); |
| 367 } | 362 } |
| 368 | 363 |
| 369 /// A subclass of [ScheduledProcess] that parses pub's verbose logging output | 364 /// A subclass of [ScheduledProcess] that parses pub's verbose logging output |
| 370 /// and makes [stdout] and [stderr] work as though pub weren't running in | 365 /// and makes [stdout] and [stderr] work as though pub weren't running in |
| 371 /// verbose mode. | 366 /// verbose mode. |
| 372 class PubProcess extends ScheduledProcess { | 367 class PubProcess extends ScheduledProcess { |
| 373 Stream<Pair<log.Level, String>> _log; | 368 Stream<Pair<log.Level, String>> _log; |
| 374 Stream<String> _stdout; | 369 Stream<String> _stdout; |
| 375 Stream<String> _stderr; | 370 Stream<String> _stderr; |
| 371 Stream<String> _silent; |
| 376 | 372 |
| 377 PubProcess.start(executable, arguments, | 373 PubProcess.start(executable, arguments, |
| 378 {workingDirectory, environment, String description, | 374 {workingDirectory, environment, String description, |
| 379 Encoding encoding: UTF8}) | 375 Encoding encoding: UTF8}) |
| 380 : super.start(executable, arguments, | 376 : super.start(executable, arguments, |
| 381 workingDirectory: workingDirectory, | 377 workingDirectory: workingDirectory, |
| 382 environment: environment, | 378 environment: environment, |
| 383 description: description, | 379 description: description, |
| 384 encoding: encoding); | 380 encoding: encoding); |
| 385 | 381 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 439 return []; | 435 return []; |
| 440 } | 436 } |
| 441 return [entry.last]; | 437 return [entry.last]; |
| 442 }); | 438 }); |
| 443 } | 439 } |
| 444 | 440 |
| 445 var pair = tee(_stderr); | 441 var pair = tee(_stderr); |
| 446 _stderr = pair.first; | 442 _stderr = pair.first; |
| 447 return pair.last; | 443 return pair.last; |
| 448 } | 444 } |
| 445 |
| 446 /// A stream of log messages that are silent by default. |
| 447 Stream<String> silentStream() { |
| 448 if (_silent == null) { |
| 449 _silent = _logStream().expand((entry) { |
| 450 if (entry.first == log.Level.MESSAGE) return []; |
| 451 if (entry.first == log.Level.ERROR) return []; |
| 452 if (entry.first == log.Level.WARNING) return []; |
| 453 return [entry.last]; |
| 454 }); |
| 455 } |
| 456 |
| 457 var pair = tee(_silent); |
| 458 _silent = pair.first; |
| 459 return pair.last; |
| 460 } |
| 449 } | 461 } |
| 450 | 462 |
| 451 /// Fails the current test if Git is not installed. | 463 /// Fails the current test if Git is not installed. |
| 452 /// | 464 /// |
| 453 /// We require machines running these tests to have git installed. This | 465 /// We require machines running these tests to have git installed. This |
| 454 /// validation gives an easier-to-understand error when that requirement isn't | 466 /// validation gives an easier-to-understand error when that requirement isn't |
| 455 /// met than just failing in the middle of a test when pub invokes git. | 467 /// met than just failing in the middle of a test when pub invokes git. |
| 456 /// | 468 /// |
| 457 /// This also increases the [Schedule] timeout to 30 seconds on Windows, | 469 /// This also increases the [Schedule] timeout to 30 seconds on Windows, |
| 458 /// where Git runs really slowly. | 470 /// where Git runs really slowly. |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 743 _lastMatcher.matches(item.last, matchState); | 755 _lastMatcher.matches(item.last, matchState); |
| 744 } | 756 } |
| 745 | 757 |
| 746 Description describe(Description description) { | 758 Description describe(Description description) { |
| 747 return description.addAll("(", ", ", ")", [_firstMatcher, _lastMatcher]); | 759 return description.addAll("(", ", ", ")", [_firstMatcher, _lastMatcher]); |
| 748 } | 760 } |
| 749 } | 761 } |
| 750 | 762 |
| 751 /// A [StreamMatcher] that matches multiple lines of output. | 763 /// A [StreamMatcher] that matches multiple lines of output. |
| 752 StreamMatcher emitsLines(String output) => inOrder(output.split("\n")); | 764 StreamMatcher emitsLines(String output) => inOrder(output.split("\n")); |
| OLD | NEW |