| 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 library test_pub; | 10 library test_pub; |
| (...skipping 514 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 525 // Find a Dart executable we can use to spawn. Use the same one that was | 525 // Find a Dart executable we can use to spawn. Use the same one that was |
| 526 // used to run this script itself. | 526 // used to run this script itself. |
| 527 var dartBin = Platform.executable; | 527 var dartBin = Platform.executable; |
| 528 | 528 |
| 529 // If the executable looks like a path, get its full path. That way we | 529 // If the executable looks like a path, get its full path. That way we |
| 530 // can still find it when we spawn it with a different working directory. | 530 // can still find it when we spawn it with a different working directory. |
| 531 if (dartBin.contains(Platform.pathSeparator)) { | 531 if (dartBin.contains(Platform.pathSeparator)) { |
| 532 dartBin = p.absolute(dartBin); | 532 dartBin = p.absolute(dartBin); |
| 533 } | 533 } |
| 534 | 534 |
| 535 // Always run pub from a snapshot. Using the snapshot makes running the tests | 535 // If there's a snapshot available, use it. The user is responsible for |
| 536 // much faster, especially when multiple tests are run at once. | 536 // ensuring this is up-to-date.. |
| 537 var pubPath = p.absolute(p.join(pubRoot, '.pub/pub.test.snapshot')); | 537 // |
| 538 // TODO(nweiz): When the test runner supports plugins, create one to |
| 539 // auto-generate the snapshot before each run. |
| 540 var pubPath = p.absolute(p.join(pubRoot, 'bin/pub.dart')); |
| 541 if (fileExists('$pubPath.snapshot')) pubPath += '.snapshot'; |
| 542 |
| 538 var dartArgs = [pubPath, '--verbose']; | 543 var dartArgs = [pubPath, '--verbose']; |
| 539 dartArgs.addAll(args); | 544 dartArgs.addAll(args); |
| 540 | 545 |
| 541 if (tokenEndpoint == null) tokenEndpoint = new Future.value(); | 546 if (tokenEndpoint == null) tokenEndpoint = new Future.value(); |
| 542 var environmentFuture = tokenEndpoint | 547 var environmentFuture = tokenEndpoint |
| 543 .then((tokenEndpoint) => getPubTestEnvironment(tokenEndpoint)) | 548 .then((tokenEndpoint) => getPubTestEnvironment(tokenEndpoint)) |
| 544 .then((pubEnvironment) { | 549 .then((pubEnvironment) { |
| 545 if (environment != null) pubEnvironment.addAll(environment); | 550 if (environment != null) pubEnvironment.addAll(environment); |
| 546 return pubEnvironment; | 551 return pubEnvironment; |
| 547 }); | 552 }); |
| 548 | 553 |
| 549 _ensureSnapshot(); | |
| 550 | |
| 551 return new PubProcess.start(dartBin, dartArgs, environment: environmentFuture, | 554 return new PubProcess.start(dartBin, dartArgs, environment: environmentFuture, |
| 552 workingDirectory: _pathInSandbox(appPath), | 555 workingDirectory: _pathInSandbox(appPath), |
| 553 description: args.isEmpty ? 'pub' : 'pub ${args.first}'); | 556 description: args.isEmpty ? 'pub' : 'pub ${args.first}'); |
| 554 } | 557 } |
| 555 | 558 |
| 556 /// Ensure that a snapshot of the current pub source exists at | |
| 557 /// ".pub/pub.snapshot". | |
| 558 void _ensureSnapshot() { | |
| 559 ensureDir(p.join(pubRoot, '.pub')); | |
| 560 | |
| 561 var version = sdk.version.toString(); | |
| 562 var pubHash = _hashChanges(); | |
| 563 var dartHash = runningFromDartRepo ? _hashExecutable() : null; | |
| 564 | |
| 565 var snapshotPath = p.join(pubRoot, '.pub', 'pub.test.snapshot'); | |
| 566 var pubHashPath = p.join(pubRoot, '.pub', 'pub.hash'); | |
| 567 var dartHashPath = p.join(pubRoot, '.pub', 'dart.hash'); | |
| 568 var versionPath = p.join(pubRoot, '.pub', 'pub.version'); | |
| 569 if (fileExists(pubHashPath) && fileExists(versionPath) && | |
| 570 (!runningFromDartRepo || fileExists(dartHashPath))) { | |
| 571 var oldPubHash = readTextFile(pubHashPath); | |
| 572 var oldDartHash = runningFromDartRepo ? readTextFile(dartHashPath) : null; | |
| 573 var oldVersion = readTextFile(versionPath); | |
| 574 | |
| 575 if (oldPubHash == pubHash && oldDartHash == dartHash && | |
| 576 oldVersion == version && fileExists(snapshotPath)) { | |
| 577 return; | |
| 578 } | |
| 579 } | |
| 580 | |
| 581 var args = ['--snapshot=$snapshotPath']; | |
| 582 if (Platform.packageRoot.isNotEmpty) { | |
| 583 args.add('--package-root=${Platform.packageRoot}'); | |
| 584 } | |
| 585 args.add(p.join(pubRoot, 'bin', 'pub.dart')); | |
| 586 | |
| 587 var dartSnapshot = runProcessSync(Platform.executable, args); | |
| 588 if (dartSnapshot.exitCode != 0) throw "Failed to run dart --snapshot."; | |
| 589 | |
| 590 writeTextFile(pubHashPath, pubHash); | |
| 591 if (runningFromDartRepo) writeTextFile(dartHashPath, dartHash); | |
| 592 writeTextFile(versionPath, version); | |
| 593 } | |
| 594 | |
| 595 /// Returns a hash that encapsulates the current state of the repo. | |
| 596 String _hashChanges() { | |
| 597 var hash = new SHA1(); | |
| 598 | |
| 599 // Include the current Git commit. | |
| 600 hash.add(UTF8.encode( | |
| 601 gitlib.runSync(['rev-parse', 'HEAD'], workingDir: pubRoot).first)); | |
| 602 | |
| 603 // Include the changes in lib and bin relative to the current Git commit. | |
| 604 var tracked = gitlib.runSync(['diff-index', '--patch', 'HEAD', 'lib', 'bin'], | |
| 605 workingDir: pubRoot); | |
| 606 for (var line in tracked) { | |
| 607 hash.add(UTF8.encode("$line\n")); | |
| 608 } | |
| 609 | |
| 610 // Include the full contents of non-ignored files in lib and bin that aren't | |
| 611 // tracked by Git. | |
| 612 var untracked = gitlib.runSync( | |
| 613 ['ls-files', '--others', '--exclude-standard', 'lib', 'bin'], | |
| 614 workingDir: pubRoot); | |
| 615 for (var path in untracked) { | |
| 616 hash.add(readBinaryFile(path)); | |
| 617 } | |
| 618 | |
| 619 return CryptoUtils.bytesToHex(hash.close()); | |
| 620 } | |
| 621 | |
| 622 /// Return a SHA1 hash of the Dart executable used to run this script. | |
| 623 /// | |
| 624 /// This is used when running within the Dart repo to ensure that the snapshot | |
| 625 /// is invalidated when the executable changes. | |
| 626 String _hashExecutable() { | |
| 627 var hash = new SHA1(); | |
| 628 hash.add(new File(Platform.executable).readAsBytesSync()); | |
| 629 return CryptoUtils.bytesToHex(hash.close()); | |
| 630 } | |
| 631 | |
| 632 /// A subclass of [ScheduledProcess] that parses pub's verbose logging output | 559 /// A subclass of [ScheduledProcess] that parses pub's verbose logging output |
| 633 /// and makes [stdout] and [stderr] work as though pub weren't running in | 560 /// and makes [stdout] and [stderr] work as though pub weren't running in |
| 634 /// verbose mode. | 561 /// verbose mode. |
| 635 class PubProcess extends ScheduledProcess { | 562 class PubProcess extends ScheduledProcess { |
| 636 Stream<Pair<log.Level, String>> _log; | 563 Stream<Pair<log.Level, String>> _log; |
| 637 Stream<String> _stdout; | 564 Stream<String> _stdout; |
| 638 Stream<String> _stderr; | 565 Stream<String> _stderr; |
| 639 | 566 |
| 640 PubProcess.start(executable, arguments, | 567 PubProcess.start(executable, arguments, |
| 641 {workingDirectory, environment, String description, | 568 {workingDirectory, environment, String description, |
| (...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1065 _lastMatcher.matches(item.last, matchState); | 992 _lastMatcher.matches(item.last, matchState); |
| 1066 } | 993 } |
| 1067 | 994 |
| 1068 Description describe(Description description) { | 995 Description describe(Description description) { |
| 1069 return description.addAll("(", ", ", ")", [_firstMatcher, _lastMatcher]); | 996 return description.addAll("(", ", ", ")", [_firstMatcher, _lastMatcher]); |
| 1070 } | 997 } |
| 1071 } | 998 } |
| 1072 | 999 |
| 1073 /// A [StreamMatcher] that matches multiple lines of output. | 1000 /// A [StreamMatcher] that matches multiple lines of output. |
| 1074 StreamMatcher emitsLines(String output) => inOrder(output.split("\n")); | 1001 StreamMatcher emitsLines(String output) => inOrder(output.split("\n")); |
| OLD | NEW |