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 /** | 5 /** |
6 * Classes and methods for executing tests. | 6 * Classes and methods for executing tests. |
7 * | 7 * |
8 * This module includes: | 8 * This module includes: |
9 * - Managing parallel execution of tests, including timeout checks. | 9 * - Managing parallel execution of tests, including timeout checks. |
10 * - Evaluating the output of each test as pass/fail/crash/timeout. | 10 * - Evaluating the output of each test as pass/fail/crash/timeout. |
11 */ | 11 */ |
12 library test_runner; | 12 library test_runner; |
13 | 13 |
14 import "dart:async"; | 14 import "dart:async"; |
15 import "dart:collection" show Queue; | 15 import "dart:collection" show Queue; |
16 import "dart:convert" show LineSplitter, UTF8, JSON; | 16 import "dart:convert" show LineSplitter, UTF8, JSON; |
17 // We need to use the 'io' prefix here, otherwise io.exitCode will shadow | 17 // We need to use the 'io' prefix here, otherwise io.exitCode will shadow |
18 // CommandOutput.exitCode in subclasses of CommandOutput. | 18 // CommandOutput.exitCode in subclasses of CommandOutput. |
19 import "dart:io" as io; | 19 import "dart:io" as io; |
20 import "dart:math" as math; | 20 import "dart:math" as math; |
21 import 'android.dart'; | |
21 import 'dependency_graph.dart' as dgraph; | 22 import 'dependency_graph.dart' as dgraph; |
22 import "browser_controller.dart"; | 23 import "browser_controller.dart"; |
23 import "path.dart"; | 24 import "path.dart"; |
24 import "status_file_parser.dart"; | 25 import "status_file_parser.dart"; |
25 import "test_progress.dart"; | 26 import "test_progress.dart"; |
26 import "test_suite.dart"; | 27 import "test_suite.dart"; |
27 import "utils.dart"; | 28 import "utils.dart"; |
28 import 'record_and_replay.dart'; | 29 import 'record_and_replay.dart'; |
29 | 30 |
30 const int CRASHING_BROWSER_EXITCODE = -10; | 31 const int CRASHING_BROWSER_EXITCODE = -10; |
(...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
337 bool _equal(AnalysisCommand other) => | 338 bool _equal(AnalysisCommand other) => |
338 super._equal(other) && flavor == other.flavor; | 339 super._equal(other) && flavor == other.flavor; |
339 } | 340 } |
340 | 341 |
341 class VmCommand extends ProcessCommand { | 342 class VmCommand extends ProcessCommand { |
342 VmCommand._(String executable, List<String> arguments, | 343 VmCommand._(String executable, List<String> arguments, |
343 Map<String, String> environmentOverrides) | 344 Map<String, String> environmentOverrides) |
344 : super._("vm", executable, arguments, environmentOverrides); | 345 : super._("vm", executable, arguments, environmentOverrides); |
345 } | 346 } |
346 | 347 |
348 class AdbPrecompilationCommand extends Command { | |
349 final String precompiledRunnerFilename; | |
350 final String precompiledTestDirectory; | |
351 final bool useBlobs; | |
352 | |
353 AdbPrecompilationCommand._(this.precompiledRunnerFilename, | |
354 this.precompiledTestDirectory, | |
355 this.useBlobs) | |
356 : super._("adb_precompilation"); | |
357 | |
358 void _buildHashCode(HashCodeBuilder builder) { | |
359 super._buildHashCode(builder); | |
360 builder.add(precompiledRunnerFilename); | |
361 builder.add(precompiledTestDirectory); | |
362 builder.add(useBlobs); | |
363 } | |
364 | |
365 bool _equal(AdbPrecompilationCommand other) => | |
366 super._equal(other) && | |
367 precompiledRunnerFilename == other.precompiledRunnerFilename && | |
368 useBlobs == other.useBlobs && | |
369 precompiledTestDirectory == other.precompiledTestDirectory; | |
370 | |
371 String toString() => 'Steps to push precompiled runner and precompiled code ' | |
372 'to an attached device. Uses (and requires) adb.'; | |
373 } | |
374 | |
347 class JSCommandlineCommand extends ProcessCommand { | 375 class JSCommandlineCommand extends ProcessCommand { |
348 JSCommandlineCommand._( | 376 JSCommandlineCommand._( |
349 String displayName, String executable, List<String> arguments, | 377 String displayName, String executable, List<String> arguments, |
350 [Map<String, String> environmentOverrides = null]) | 378 [Map<String, String> environmentOverrides = null]) |
351 : super._(displayName, executable, arguments, environmentOverrides); | 379 : super._(displayName, executable, arguments, environmentOverrides); |
352 } | 380 } |
353 | 381 |
354 class PubCommand extends ProcessCommand { | 382 class PubCommand extends ProcessCommand { |
355 final String command; | 383 final String command; |
356 | 384 |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
603 flavor, displayName, executable, arguments, environmentOverrides); | 631 flavor, displayName, executable, arguments, environmentOverrides); |
604 return _getUniqueCommand(command); | 632 return _getUniqueCommand(command); |
605 } | 633 } |
606 | 634 |
607 VmCommand getVmCommand(String executable, List<String> arguments, | 635 VmCommand getVmCommand(String executable, List<String> arguments, |
608 Map<String, String> environmentOverrides) { | 636 Map<String, String> environmentOverrides) { |
609 var command = new VmCommand._(executable, arguments, environmentOverrides); | 637 var command = new VmCommand._(executable, arguments, environmentOverrides); |
610 return _getUniqueCommand(command); | 638 return _getUniqueCommand(command); |
611 } | 639 } |
612 | 640 |
641 AdbPrecompilationCommand getAdbPrecompiledCommand(String precompiledRunner, | |
642 String testDirectory, | |
643 bool useBlobs) { | |
644 var command = new AdbPrecompilationCommand._( | |
645 precompiledRunner, testDirectory, useBlobs); | |
646 return _getUniqueCommand(command); | |
647 } | |
648 | |
613 Command getJSCommandlineCommand(String displayName, executable, arguments, | 649 Command getJSCommandlineCommand(String displayName, executable, arguments, |
614 [environment = null]) { | 650 [environment = null]) { |
615 var command = new JSCommandlineCommand._( | 651 var command = new JSCommandlineCommand._( |
616 displayName, executable, arguments, environment); | 652 displayName, executable, arguments, environment); |
617 return _getUniqueCommand(command); | 653 return _getUniqueCommand(command); |
618 } | 654 } |
619 | 655 |
620 Command getProcessCommand(String displayName, executable, arguments, | 656 Command getProcessCommand(String displayName, executable, arguments, |
621 [environment = null, workingDirectory = null]) { | 657 [environment = null, workingDirectory = null]) { |
622 var command = new ProcessCommand._( | 658 var command = new ProcessCommand._( |
(...skipping 995 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1618 command, exitCode, timedOut, stdout, stderr, time, compilationSkipped); | 1654 command, exitCode, timedOut, stdout, stderr, time, compilationSkipped); |
1619 } else if (command is BrowserTestCommand) { | 1655 } else if (command is BrowserTestCommand) { |
1620 return new HTMLBrowserCommandOutputImpl( | 1656 return new HTMLBrowserCommandOutputImpl( |
1621 command, exitCode, timedOut, stdout, stderr, time, compilationSkipped); | 1657 command, exitCode, timedOut, stdout, stderr, time, compilationSkipped); |
1622 } else if (command is AnalysisCommand) { | 1658 } else if (command is AnalysisCommand) { |
1623 return new AnalysisCommandOutputImpl( | 1659 return new AnalysisCommandOutputImpl( |
1624 command, exitCode, timedOut, stdout, stderr, time, compilationSkipped); | 1660 command, exitCode, timedOut, stdout, stderr, time, compilationSkipped); |
1625 } else if (command is VmCommand) { | 1661 } else if (command is VmCommand) { |
1626 return new VmCommandOutputImpl( | 1662 return new VmCommandOutputImpl( |
1627 command, exitCode, timedOut, stdout, stderr, time, pid); | 1663 command, exitCode, timedOut, stdout, stderr, time, pid); |
1664 } else if (command is AdbPrecompilationCommand) { | |
1665 return new VmCommandOutputImpl( | |
1666 command, exitCode, timedOut, stdout, stderr, time, pid); | |
1628 } else if (command is CompilationCommand) { | 1667 } else if (command is CompilationCommand) { |
1629 if (command.displayName == 'precompiler' || | 1668 if (command.displayName == 'precompiler' || |
1630 command.displayName == 'dart2snapshot') { | 1669 command.displayName == 'dart2snapshot') { |
1631 return new VmCommandOutputImpl( | 1670 return new VmCommandOutputImpl( |
1632 command, exitCode, timedOut, stdout, stderr, time, pid); | 1671 command, exitCode, timedOut, stdout, stderr, time, pid); |
1633 } | 1672 } |
1634 return new CompilationCommandOutputImpl( | 1673 return new CompilationCommandOutputImpl( |
1635 command, exitCode, timedOut, stdout, stderr, time, compilationSkipped); | 1674 command, exitCode, timedOut, stdout, stderr, time, compilationSkipped); |
1636 } else if (command is JSCommandlineCommand) { | 1675 } else if (command is JSCommandlineCommand) { |
1637 return new JsCommandlineOutputImpl( | 1676 return new JsCommandlineOutputImpl( |
(...skipping 751 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2389 Future cleanup(); | 2428 Future cleanup(); |
2390 // TODO(kustermann): The [timeout] parameter should be a property of Command | 2429 // TODO(kustermann): The [timeout] parameter should be a property of Command |
2391 Future<CommandOutput> runCommand( | 2430 Future<CommandOutput> runCommand( |
2392 dgraph.Node node, Command command, int timeout); | 2431 dgraph.Node node, Command command, int timeout); |
2393 } | 2432 } |
2394 | 2433 |
2395 class CommandExecutorImpl implements CommandExecutor { | 2434 class CommandExecutorImpl implements CommandExecutor { |
2396 final Map globalConfiguration; | 2435 final Map globalConfiguration; |
2397 final int maxProcesses; | 2436 final int maxProcesses; |
2398 final int maxBrowserProcesses; | 2437 final int maxBrowserProcesses; |
2438 AdbDevicePool adbDevicePool; | |
2399 | 2439 |
2400 // For dart2js and analyzer batch processing, | 2440 // For dart2js and analyzer batch processing, |
2401 // we keep a list of batch processes. | 2441 // we keep a list of batch processes. |
2402 final _batchProcesses = new Map<String, List<BatchRunnerProcess>>(); | 2442 final _batchProcesses = new Map<String, List<BatchRunnerProcess>>(); |
2403 // We keep a BrowserTestRunner for every configuration. | 2443 // We keep a BrowserTestRunner for every configuration. |
2404 final _browserTestRunners = new Map<Map, BrowserTestRunner>(); | 2444 final _browserTestRunners = new Map<Map, BrowserTestRunner>(); |
2405 | 2445 |
2406 bool _finishing = false; | 2446 bool _finishing = false; |
2407 | 2447 |
2408 CommandExecutorImpl( | 2448 CommandExecutorImpl( |
2409 this.globalConfiguration, this.maxProcesses, this.maxBrowserProcesses); | 2449 this.globalConfiguration, this.maxProcesses, this.maxBrowserProcesses, |
2450 {this.adbDevicePool}); | |
2410 | 2451 |
2411 Future cleanup() { | 2452 Future cleanup() { |
2412 assert(!_finishing); | 2453 assert(!_finishing); |
2413 _finishing = true; | 2454 _finishing = true; |
2414 | 2455 |
2415 Future _terminateBatchRunners() { | 2456 Future _terminateBatchRunners() { |
2416 var futures = []; | 2457 var futures = []; |
2417 for (var runners in _batchProcesses.values) { | 2458 for (var runners in _batchProcesses.values) { |
2418 futures.addAll(runners.map((runner) => runner.terminate())); | 2459 futures.addAll(runners.map((runner) => runner.terminate())); |
2419 } | 2460 } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2453 if (command is BrowserTestCommand) { | 2494 if (command is BrowserTestCommand) { |
2454 return _startBrowserControllerTest(command, timeout); | 2495 return _startBrowserControllerTest(command, timeout); |
2455 } else if (command is CompilationCommand && dart2jsBatchMode) { | 2496 } else if (command is CompilationCommand && dart2jsBatchMode) { |
2456 return _getBatchRunner("dart2js") | 2497 return _getBatchRunner("dart2js") |
2457 .runCommand("dart2js", command, timeout, command.arguments); | 2498 .runCommand("dart2js", command, timeout, command.arguments); |
2458 } else if (command is AnalysisCommand && batchMode) { | 2499 } else if (command is AnalysisCommand && batchMode) { |
2459 return _getBatchRunner(command.flavor) | 2500 return _getBatchRunner(command.flavor) |
2460 .runCommand(command.flavor, command, timeout, command.arguments); | 2501 .runCommand(command.flavor, command, timeout, command.arguments); |
2461 } else if (command is ScriptCommand) { | 2502 } else if (command is ScriptCommand) { |
2462 return command.run(); | 2503 return command.run(); |
2504 } else if (command is AdbPrecompilationCommand) { | |
2505 assert(adbDevicePool != null); | |
2506 return adbDevicePool.aquireDevice().then((AdbDevice device) { | |
Florian Schneider
2016/04/27 13:53:05
s/aquire/acquire/
kustermann
2016/05/02 10:40:23
Done.
| |
2507 return _runAdbPrecompilationCommand(device, command).whenComplete(() { | |
2508 adbDevicePool.releaseDevice(device); | |
2509 }); | |
2510 }); | |
2463 } else { | 2511 } else { |
2464 return new RunningProcess(command, timeout).run(); | 2512 return new RunningProcess(command, timeout).run(); |
2465 } | 2513 } |
2466 } | 2514 } |
2467 | 2515 |
2516 Future<CommandOutput> _runAdbPrecompilationCommand( | |
2517 AdbDevice device, AdbPrecompilationCommand command) async { | |
2518 var runner = command.precompiledRunnerFilename; | |
2519 var testdir = command.precompiledTestDirectory; | |
2520 var devicedir = '/data/local/tmp/precompilation-testing'; | |
2521 | |
2522 // We copy all the files which the vm precompiler puts into the test | |
2523 // directory. | |
2524 List<String> files = new io.Directory(testdir) | |
2525 .listSync() | |
2526 .where((fse) => fse is io.File) | |
2527 .map((file) => file.path) | |
2528 .map((path) => path.substring(path.lastIndexOf('/') + 1)) | |
2529 .toList(); | |
2530 | |
2531 // All closures are of type "Future<AdbCommandResult> run()" | |
2532 List<Function> steps = []; | |
2533 | |
2534 steps.add(() => device.runAdbShellCommand( | |
2535 ['rm', '-Rf', devicedir])); | |
2536 steps.add(() => device.runAdbShellCommand( | |
2537 ['mkdir', devicedir])); | |
2538 steps.add(() => device.runAdbCommand( | |
2539 ['push', runner, '$devicedir/runner'])); | |
Florian Schneider
2016/04/28 13:18:30
Maybe add a TODO that we should push the runner (d
kustermann
2016/05/02 10:40:23
Done.
| |
2540 steps.add(() => device.runAdbShellCommand( | |
2541 ['chmod', '777', '$devicedir/runner'])); | |
2542 | |
2543 for (var file in files) { | |
2544 steps.add(() => device.runAdbCommand( | |
2545 ['push', '$testdir/$file', '$devicedir/$file'])); | |
2546 } | |
2547 | |
2548 if (command.useBlobs) { | |
2549 steps.add(() => device.runAdbShellCommand( | |
2550 ['$devicedir/runner', '--run-precompiled-snapshot=$devicedir', | |
2551 '--use_blobs', 'ignored.dart'])); | |
2552 } else { | |
2553 steps.add(() => device.runAdbShellCommand( | |
2554 ['$devicedir/runner', '--run-precompiled-snapshot=$devicedir', | |
2555 'ignored.dart'])); | |
2556 } | |
2557 | |
2558 var stopwatch = new Stopwatch()..start(); | |
2559 var writer = new StringBuffer(); | |
2560 | |
2561 await device.waitForBootCompleted(); | |
2562 await device.waitForDevice(); | |
2563 | |
2564 AdbCommandResult result; | |
2565 for (var i = 0; i < steps.length; i++) { | |
2566 var fun = steps[i]; | |
2567 var commandStopwatch = new Stopwatch()..start(); | |
2568 result = await fun(); | |
2569 | |
2570 writer.writeln("Executing ${result.command}"); | |
2571 if (result.stdout.length > 0) { | |
2572 writer.writeln("Stdout:\n${result.stdout.trim()}"); | |
2573 } | |
2574 if (result.stderr.length > 0) { | |
2575 writer.writeln("Stderr:\n${result.stderr.trim()}"); | |
2576 } | |
2577 writer.writeln("ExitCode: ${result.exitCode}"); | |
2578 writer.writeln("Time: ${commandStopwatch.elapsed}"); | |
2579 writer.writeln(""); | |
2580 | |
2581 // If one command fails, we stop processing the others and return | |
2582 // immediately. | |
2583 if (result.exitCode != 0) break; | |
2584 } | |
2585 return createCommandOutput( | |
2586 command, result.exitCode, false, UTF8.encode('$writer'), | |
2587 [], stopwatch.elapsed, false); | |
2588 } | |
2589 | |
2468 BatchRunnerProcess _getBatchRunner(String identifier) { | 2590 BatchRunnerProcess _getBatchRunner(String identifier) { |
2469 // Start batch processes if needed | 2591 // Start batch processes if needed |
2470 var runners = _batchProcesses[identifier]; | 2592 var runners = _batchProcesses[identifier]; |
2471 if (runners == null) { | 2593 if (runners == null) { |
2472 runners = new List<BatchRunnerProcess>(maxProcesses); | 2594 runners = new List<BatchRunnerProcess>(maxProcesses); |
2473 for (int i = 0; i < maxProcesses; i++) { | 2595 for (int i = 0; i < maxProcesses; i++) { |
2474 runners[i] = new BatchRunnerProcess(); | 2596 runners[i] = new BatchRunnerProcess(); |
2475 } | 2597 } |
2476 _batchProcesses[identifier] = runners; | 2598 _batchProcesses[identifier] = runners; |
2477 } | 2599 } |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2709 Map _globalConfiguration; | 2831 Map _globalConfiguration; |
2710 | 2832 |
2711 Function _allDone; | 2833 Function _allDone; |
2712 final dgraph.Graph _graph = new dgraph.Graph(); | 2834 final dgraph.Graph _graph = new dgraph.Graph(); |
2713 List<EventListener> _eventListener; | 2835 List<EventListener> _eventListener; |
2714 | 2836 |
2715 ProcessQueue(this._globalConfiguration, maxProcesses, maxBrowserProcesses, | 2837 ProcessQueue(this._globalConfiguration, maxProcesses, maxBrowserProcesses, |
2716 DateTime startTime, testSuites, this._eventListener, this._allDone, | 2838 DateTime startTime, testSuites, this._eventListener, this._allDone, |
2717 [bool verbose = false, | 2839 [bool verbose = false, |
2718 String recordingOutputFile, | 2840 String recordingOutputFile, |
2719 String recordedInputFile]) { | 2841 String recordedInputFile, |
2842 AdbDevicePool adbDevicePool]) { | |
2720 void setupForListing(TestCaseEnqueuer testCaseEnqueuer) { | 2843 void setupForListing(TestCaseEnqueuer testCaseEnqueuer) { |
2721 _graph.events | 2844 _graph.events |
2722 .where((event) => event is dgraph.GraphSealedEvent) | 2845 .where((event) => event is dgraph.GraphSealedEvent) |
2723 .listen((dgraph.GraphSealedEvent event) { | 2846 .listen((dgraph.GraphSealedEvent event) { |
2724 var testCases = new List.from(testCaseEnqueuer.remainingTestCases); | 2847 var testCases = new List.from(testCaseEnqueuer.remainingTestCases); |
2725 testCases.sort((a, b) => a.displayName.compareTo(b.displayName)); | 2848 testCases.sort((a, b) => a.displayName.compareTo(b.displayName)); |
2726 | 2849 |
2727 print("\nGenerating all matching test cases ....\n"); | 2850 print("\nGenerating all matching test cases ....\n"); |
2728 | 2851 |
2729 for (TestCase testCase in testCases) { | 2852 for (TestCase testCase in testCases) { |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2810 var commandEnqueuer = new CommandEnqueuer(_graph); | 2933 var commandEnqueuer = new CommandEnqueuer(_graph); |
2811 | 2934 |
2812 // CommandExecutor will execute commands | 2935 // CommandExecutor will execute commands |
2813 var executor; | 2936 var executor; |
2814 if (recording) { | 2937 if (recording) { |
2815 executor = new RecordingCommandExecutor(new Path(recordingOutputFile)); | 2938 executor = new RecordingCommandExecutor(new Path(recordingOutputFile)); |
2816 } else if (replaying) { | 2939 } else if (replaying) { |
2817 executor = new ReplayingCommandExecutor(new Path(recordedInputFile)); | 2940 executor = new ReplayingCommandExecutor(new Path(recordedInputFile)); |
2818 } else { | 2941 } else { |
2819 executor = new CommandExecutorImpl( | 2942 executor = new CommandExecutorImpl( |
2820 _globalConfiguration, maxProcesses, maxBrowserProcesses); | 2943 _globalConfiguration, maxProcesses, |
2944 maxBrowserProcesses, adbDevicePool: adbDevicePool); | |
2821 } | 2945 } |
2822 | 2946 |
2823 // Run "runnable commands" using [executor] subject to | 2947 // Run "runnable commands" using [executor] subject to |
2824 // maxProcesses/maxBrowserProcesses constraint | 2948 // maxProcesses/maxBrowserProcesses constraint |
2825 commandQueue = new CommandQueue(_graph, testCaseEnqueuer, executor, | 2949 commandQueue = new CommandQueue(_graph, testCaseEnqueuer, executor, |
2826 maxProcesses, maxBrowserProcesses, verbose); | 2950 maxProcesses, maxBrowserProcesses, verbose); |
2827 | 2951 |
2828 // Finish test cases when all commands were run (or some failed) | 2952 // Finish test cases when all commands were run (or some failed) |
2829 var testCaseCompleter = | 2953 var testCaseCompleter = |
2830 new TestCaseCompleter(_graph, testCaseEnqueuer, commandQueue); | 2954 new TestCaseCompleter(_graph, testCaseEnqueuer, commandQueue); |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2886 } | 3010 } |
2887 } | 3011 } |
2888 | 3012 |
2889 void eventAllTestsDone() { | 3013 void eventAllTestsDone() { |
2890 for (var listener in _eventListener) { | 3014 for (var listener in _eventListener) { |
2891 listener.allDone(); | 3015 listener.allDone(); |
2892 } | 3016 } |
2893 _allDone(); | 3017 _allDone(); |
2894 } | 3018 } |
2895 } | 3019 } |
OLD | NEW |