| 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; |
| 11 | 11 |
| 12 import 'dart:async'; | 12 import 'dart:async'; |
| 13 import 'dart:convert'; | 13 import 'dart:convert'; |
| 14 import 'dart:io'; | 14 import 'dart:io'; |
| 15 import 'dart:math'; | 15 import 'dart:math'; |
| 16 | 16 |
| 17 import 'package:crypto/crypto.dart'; | |
| 18 import 'package:http/testing.dart'; | 17 import 'package:http/testing.dart'; |
| 19 import 'package:path/path.dart' as p; | 18 import 'package:path/path.dart' as p; |
| 20 import 'package:pub/src/entrypoint.dart'; | 19 import 'package:pub/src/entrypoint.dart'; |
| 20 import 'package:pub/src/exceptions.dart'; |
| 21 import 'package:pub/src/exit_codes.dart' as exit_codes; | 21 import 'package:pub/src/exit_codes.dart' as exit_codes; |
| 22 // TODO(rnystrom): Using "gitlib" as the prefix here is ugly, but "git" collides | 22 // TODO(rnystrom): Using "gitlib" as the prefix here is ugly, but "git" collides |
| 23 // with the git descriptor method. Maybe we should try to clean up the top level | 23 // with the git descriptor method. Maybe we should try to clean up the top level |
| 24 // scope a bit? | 24 // scope a bit? |
| 25 import 'package:pub/src/git.dart' as gitlib; | 25 import 'package:pub/src/git.dart' as gitlib; |
| 26 import 'package:pub/src/http.dart'; | 26 import 'package:pub/src/http.dart'; |
| 27 import 'package:pub/src/io.dart'; | 27 import 'package:pub/src/io.dart'; |
| 28 import 'package:pub/src/lock_file.dart'; | 28 import 'package:pub/src/lock_file.dart'; |
| 29 import 'package:pub/src/log.dart' as log; | 29 import 'package:pub/src/log.dart' as log; |
| 30 import 'package:pub/src/package.dart'; | 30 import 'package:pub/src/package.dart'; |
| 31 import 'package:pub/src/pubspec.dart'; | |
| 32 import 'package:pub/src/sdk.dart' as sdk; | |
| 33 import 'package:pub/src/source/hosted.dart'; | |
| 34 import 'package:pub/src/source/path.dart'; | |
| 35 import 'package:pub/src/source_registry.dart'; | 31 import 'package:pub/src/source_registry.dart'; |
| 36 import 'package:pub/src/system_cache.dart'; | 32 import 'package:pub/src/system_cache.dart'; |
| 37 import 'package:pub/src/utils.dart'; | 33 import 'package:pub/src/utils.dart'; |
| 38 import 'package:pub/src/validator.dart'; | 34 import 'package:pub/src/validator.dart'; |
| 39 import 'package:pub_semver/pub_semver.dart'; | 35 import 'package:pub_semver/pub_semver.dart'; |
| 40 import 'package:scheduled_test/scheduled_process.dart'; | 36 import 'package:scheduled_test/scheduled_process.dart'; |
| 41 import 'package:scheduled_test/scheduled_server.dart'; | 37 import 'package:scheduled_test/scheduled_server.dart'; |
| 42 import 'package:scheduled_test/scheduled_stream.dart'; | 38 import 'package:scheduled_test/scheduled_stream.dart'; |
| 43 import 'package:scheduled_test/scheduled_test.dart' hide fail; | 39 import 'package:scheduled_test/scheduled_test.dart' hide fail; |
| 44 import 'package:shelf/shelf.dart' as shelf; | 40 import 'package:shelf/shelf.dart' as shelf; |
| 45 import 'package:shelf/shelf_io.dart' as shelf_io; | 41 import 'package:shelf/shelf_io.dart' as shelf_io; |
| 46 import 'package:yaml/yaml.dart'; | |
| 47 | 42 |
| 48 import 'descriptor.dart' as d; | 43 import 'descriptor.dart' as d; |
| 49 import 'serve_packages.dart'; | |
| 50 | 44 |
| 51 export 'serve_packages.dart'; | 45 export 'serve_packages.dart'; |
| 52 | 46 |
| 53 /// The current [HttpServer] created using [serve]. | 47 /// The current [HttpServer] created using [serve]. |
| 54 var _server; | 48 var _server; |
| 55 | 49 |
| 56 /// The list of paths that have been requested from the server since the last | 50 /// The list of paths that have been requested from the server since the last |
| 57 /// call to [getRequestedPaths]. | 51 /// call to [getRequestedPaths]. |
| 58 final _requestedPaths = <String>[]; | 52 final _requestedPaths = <String>[]; |
| 59 | 53 |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 274 // infrastructure runs pub in verbose mode, which enables this. | 268 // infrastructure runs pub in verbose mode, which enables this. |
| 275 pub.stdout.expect(consumeWhile(startsWith("Loading"))); | 269 pub.stdout.expect(consumeWhile(startsWith("Loading"))); |
| 276 | 270 |
| 277 return pub; | 271 return pub; |
| 278 } | 272 } |
| 279 | 273 |
| 280 /// Defines an integration test. | 274 /// Defines an integration test. |
| 281 /// | 275 /// |
| 282 /// The [body] should schedule a series of operations which will be run | 276 /// The [body] should schedule a series of operations which will be run |
| 283 /// asynchronously. | 277 /// asynchronously. |
| 284 void integration(String description, void body()) => | 278 void integration(String description, void body()) { |
| 285 _integration(description, body, test); | 279 test(description, () { |
| 286 | |
| 287 /// Like [integration], but causes only this test to run. | |
| 288 void solo_integration(String description, void body()) => | |
| 289 _integration(description, body, solo_test); | |
| 290 | |
| 291 void _integration(String description, void body(), [Function testFn]) { | |
| 292 testFn(description, () { | |
| 293 _sandboxDir = createSystemTempDir(); | 280 _sandboxDir = createSystemTempDir(); |
| 294 d.defaultRoot = sandboxDir; | 281 d.defaultRoot = sandboxDir; |
| 295 currentSchedule.onComplete.schedule(() { | 282 currentSchedule.onComplete.schedule(() { |
| 296 try { | 283 try { |
| 297 deleteEntry(_sandboxDir); | 284 deleteEntry(_sandboxDir); |
| 298 } on ApplicationException catch (_) { | 285 } on ApplicationException catch (_) { |
| 299 // Silently swallow exceptions on Windows. If the test failed, there may | 286 // Silently swallow exceptions on Windows. If the test failed, there may |
| 300 // still be lingering processes that have files in the sandbox open, | 287 // still be lingering processes that have files in the sandbox open, |
| 301 // which will cause this to fail on Windows. | 288 // which will cause this to fail on Windows. |
| 302 if (!Platform.isWindows) rethrow; | 289 if (!Platform.isWindows) rethrow; |
| (...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 552 return [entry.last]; | 539 return [entry.last]; |
| 553 }); | 540 }); |
| 554 } | 541 } |
| 555 | 542 |
| 556 var pair = tee(_stderr); | 543 var pair = tee(_stderr); |
| 557 _stderr = pair.first; | 544 _stderr = pair.first; |
| 558 return pair.last; | 545 return pair.last; |
| 559 } | 546 } |
| 560 } | 547 } |
| 561 | 548 |
| 562 /// The path to the `packages` directory from which pub loads its dependencies. | |
| 563 String get _packageRoot => p.absolute(Platform.packageRoot); | |
| 564 | |
| 565 /// Fails the current test if Git is not installed. | 549 /// Fails the current test if Git is not installed. |
| 566 /// | 550 /// |
| 567 /// We require machines running these tests to have git installed. This | 551 /// We require machines running these tests to have git installed. This |
| 568 /// validation gives an easier-to-understand error when that requirement isn't | 552 /// validation gives an easier-to-understand error when that requirement isn't |
| 569 /// met than just failing in the middle of a test when pub invokes git. | 553 /// met than just failing in the middle of a test when pub invokes git. |
| 570 /// | 554 /// |
| 571 /// This also increases the [Schedule] timeout to 30 seconds on Windows, | 555 /// This also increases the [Schedule] timeout to 30 seconds on Windows, |
| 572 /// where Git runs really slowly. | 556 /// where Git runs really slowly. |
| 573 void ensureGit() { | 557 void ensureGit() { |
| 574 if (!gitlib.isInstalled) { | 558 if (!gitlib.isInstalled) { |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 809 } | 793 } |
| 810 } | 794 } |
| 811 | 795 |
| 812 /// Validates that [actualText] is a string of JSON that matches [expected], | 796 /// Validates that [actualText] is a string of JSON that matches [expected], |
| 813 /// which may be a literal JSON object, or any other [Matcher]. | 797 /// which may be a literal JSON object, or any other [Matcher]. |
| 814 void _validateOutputJson(List<String> failures, String pipe, | 798 void _validateOutputJson(List<String> failures, String pipe, |
| 815 expected, String actualText) { | 799 expected, String actualText) { |
| 816 var actual; | 800 var actual; |
| 817 try { | 801 try { |
| 818 actual = JSON.decode(actualText); | 802 actual = JSON.decode(actualText); |
| 819 } on FormatException catch(error) { | 803 } on FormatException { |
| 820 failures.add('Expected $pipe JSON:'); | 804 failures.add('Expected $pipe JSON:'); |
| 821 failures.add(expected); | 805 failures.add(expected); |
| 822 failures.add('Got invalid JSON:'); | 806 failures.add('Got invalid JSON:'); |
| 823 failures.add(actualText); | 807 failures.add(actualText); |
| 824 } | 808 } |
| 825 | 809 |
| 826 // Match against the expectation. | 810 // Match against the expectation. |
| 827 expect(actual, expected); | 811 expect(actual, expected); |
| 828 } | 812 } |
| 829 | 813 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 865 _lastMatcher.matches(item.last, matchState); | 849 _lastMatcher.matches(item.last, matchState); |
| 866 } | 850 } |
| 867 | 851 |
| 868 Description describe(Description description) { | 852 Description describe(Description description) { |
| 869 return description.addAll("(", ", ", ")", [_firstMatcher, _lastMatcher]); | 853 return description.addAll("(", ", ", ")", [_firstMatcher, _lastMatcher]); |
| 870 } | 854 } |
| 871 } | 855 } |
| 872 | 856 |
| 873 /// A [StreamMatcher] that matches multiple lines of output. | 857 /// A [StreamMatcher] that matches multiple lines of output. |
| 874 StreamMatcher emitsLines(String output) => inOrder(output.split("\n")); | 858 StreamMatcher emitsLines(String output) => inOrder(output.split("\n")); |
| OLD | NEW |