| 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. |
| (...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 void _buildHashCode(HashCodeBuilder builder) { | 357 void _buildHashCode(HashCodeBuilder builder) { |
| 358 super._buildHashCode(builder); | 358 super._buildHashCode(builder); |
| 359 builder.addJson(flavor); | 359 builder.addJson(flavor); |
| 360 } | 360 } |
| 361 | 361 |
| 362 bool _equal(AnalysisCommand other) => | 362 bool _equal(AnalysisCommand other) => |
| 363 super._equal(other) && flavor == other.flavor; | 363 super._equal(other) && flavor == other.flavor; |
| 364 } | 364 } |
| 365 | 365 |
| 366 class VmCommand extends ProcessCommand { | 366 class VmCommand extends ProcessCommand { |
| 367 final bool needsDFERunner; | |
| 368 VmCommand._(String executable, List<String> arguments, | 367 VmCommand._(String executable, List<String> arguments, |
| 369 Map<String, String> environmentOverrides, | 368 Map<String, String> environmentOverrides) |
| 370 bool this.needsDFERunner) | |
| 371 : super._("vm", executable, arguments, environmentOverrides); | 369 : super._("vm", executable, arguments, environmentOverrides); |
| 372 | |
| 373 void _buildHashCode(HashCodeBuilder builder) { | |
| 374 super._buildHashCode(builder); | |
| 375 builder.add(needsDFERunner); | |
| 376 } | |
| 377 | |
| 378 bool _equal(VmCommand other) => | |
| 379 super._equal(other) && needsDFERunner == other.needsDFERunner; | |
| 380 } | 370 } |
| 381 | 371 |
| 382 class VmBatchCommand extends ProcessCommand implements VmCommand { | 372 class VmBatchCommand extends ProcessCommand implements VmCommand { |
| 383 final String dartFile; | 373 final String dartFile; |
| 384 final bool checked; | 374 final bool checked; |
| 385 final needsDFERunner = false; | |
| 386 | 375 |
| 387 VmBatchCommand._(String executable, String dartFile, List<String> arguments, | 376 VmBatchCommand._(String executable, String dartFile, List<String> arguments, |
| 388 Map<String, String> environmentOverrides, {this.checked: true}) | 377 Map<String, String> environmentOverrides, {this.checked: true}) |
| 389 : this.dartFile = dartFile, | 378 : this.dartFile = dartFile, |
| 390 super._('vm-batch', executable, arguments, environmentOverrides); | 379 super._('vm-batch', executable, arguments, environmentOverrides); |
| 391 | 380 |
| 392 @override | 381 @override |
| 393 List<String> get batchArguments => checked | 382 List<String> get batchArguments => checked |
| 394 ? ['--checked', dartFile] | 383 ? ['--checked', dartFile] |
| 395 : [dartFile]; | 384 : [dartFile]; |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 644 | 633 |
| 645 AnalysisCommand getAnalysisCommand( | 634 AnalysisCommand getAnalysisCommand( |
| 646 String displayName, executable, arguments, environmentOverrides, | 635 String displayName, executable, arguments, environmentOverrides, |
| 647 {String flavor: 'dart2analyzer'}) { | 636 {String flavor: 'dart2analyzer'}) { |
| 648 var command = new AnalysisCommand._( | 637 var command = new AnalysisCommand._( |
| 649 flavor, displayName, executable, arguments, environmentOverrides); | 638 flavor, displayName, executable, arguments, environmentOverrides); |
| 650 return _getUniqueCommand(command); | 639 return _getUniqueCommand(command); |
| 651 } | 640 } |
| 652 | 641 |
| 653 VmCommand getVmCommand(String executable, List<String> arguments, | 642 VmCommand getVmCommand(String executable, List<String> arguments, |
| 654 Map<String, String> environmentOverrides, {bool needsDFERunner: false}) { | 643 Map<String, String> environmentOverrides) { |
| 655 var command = new VmCommand._(executable, arguments, environmentOverrides, n
eedsDFERunner); | 644 var command = new VmCommand._(executable, arguments, environmentOverrides); |
| 656 return _getUniqueCommand(command); | 645 return _getUniqueCommand(command); |
| 657 } | 646 } |
| 658 | 647 |
| 659 VmBatchCommand getVmBatchCommand(String executable, String tester, | 648 VmBatchCommand getVmBatchCommand(String executable, String tester, |
| 660 List<String> arguments, Map<String, String> environmentOverrides, | 649 List<String> arguments, Map<String, String> environmentOverrides, |
| 661 {bool checked: true}) { | 650 {bool checked: true}) { |
| 662 var command = | 651 var command = |
| 663 new VmBatchCommand._(executable, tester, arguments, environmentOverrides
, | 652 new VmBatchCommand._(executable, tester, arguments, environmentOverrides
, |
| 664 checked: checked); | 653 checked: checked); |
| 665 return _getUniqueCommand(command); | 654 return _getUniqueCommand(command); |
| (...skipping 1228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1894 bool timedOut = false; | 1883 bool timedOut = false; |
| 1895 DateTime startTime; | 1884 DateTime startTime; |
| 1896 Timer timeoutTimer; | 1885 Timer timeoutTimer; |
| 1897 int pid; | 1886 int pid; |
| 1898 OutputLog stdout = new OutputLog(); | 1887 OutputLog stdout = new OutputLog(); |
| 1899 OutputLog stderr = new OutputLog(); | 1888 OutputLog stderr = new OutputLog(); |
| 1900 List<String> diagnostics = <String>[]; | 1889 List<String> diagnostics = <String>[]; |
| 1901 bool compilationSkipped = false; | 1890 bool compilationSkipped = false; |
| 1902 Completer<CommandOutput> completer; | 1891 Completer<CommandOutput> completer; |
| 1903 Map configuration; | 1892 Map configuration; |
| 1904 List<String> preArguments; | |
| 1905 | 1893 |
| 1906 RunningProcess(this.command, | 1894 RunningProcess(this.command, |
| 1907 this.timeout, | 1895 this.timeout, |
| 1908 {this.configuration, | 1896 {this.configuration}); |
| 1909 this.preArguments}); | |
| 1910 | 1897 |
| 1911 Future<CommandOutput> run() { | 1898 Future<CommandOutput> run() { |
| 1912 completer = new Completer<CommandOutput>(); | 1899 completer = new Completer<CommandOutput>(); |
| 1913 startTime = new DateTime.now(); | 1900 startTime = new DateTime.now(); |
| 1914 _runCommand(); | 1901 _runCommand(); |
| 1915 return completer.future; | 1902 return completer.future; |
| 1916 } | 1903 } |
| 1917 | 1904 |
| 1918 void _runCommand() { | 1905 void _runCommand() { |
| 1919 command.outputIsUpToDate.then((bool isUpToDate) { | 1906 command.outputIsUpToDate.then((bool isUpToDate) { |
| 1920 if (isUpToDate) { | 1907 if (isUpToDate) { |
| 1921 compilationSkipped = true; | 1908 compilationSkipped = true; |
| 1922 _commandComplete(0); | 1909 _commandComplete(0); |
| 1923 } else { | 1910 } else { |
| 1924 var processEnvironment = _createProcessEnvironment(); | 1911 var processEnvironment = _createProcessEnvironment(); |
| 1925 var args = command.arguments; | 1912 var args = command.arguments; |
| 1926 if (preArguments != null) { | |
| 1927 args = []..addAll(preArguments)..addAll(args); | |
| 1928 } | |
| 1929 Future processFuture = io.Process.start( | 1913 Future processFuture = io.Process.start( |
| 1930 command.executable, args, | 1914 command.executable, args, |
| 1931 environment: processEnvironment, | 1915 environment: processEnvironment, |
| 1932 workingDirectory: command.workingDirectory); | 1916 workingDirectory: command.workingDirectory); |
| 1933 processFuture.then((io.Process process) { | 1917 processFuture.then((io.Process process) { |
| 1934 StreamSubscription stdoutSubscription = | 1918 StreamSubscription stdoutSubscription = |
| 1935 _drainStream(process.stdout, stdout); | 1919 _drainStream(process.stdout, stdout); |
| 1936 StreamSubscription stderrSubscription = | 1920 StreamSubscription stderrSubscription = |
| 1937 _drainStream(process.stderr, stderr); | 1921 _drainStream(process.stderr, stderr); |
| 1938 | 1922 |
| (...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2326 bool _dictEquals(Map a, Map b) { | 2310 bool _dictEquals(Map a, Map b) { |
| 2327 if (a == null) return b == null; | 2311 if (a == null) return b == null; |
| 2328 if (b == null) return false; | 2312 if (b == null) return false; |
| 2329 for (var key in a.keys) { | 2313 for (var key in a.keys) { |
| 2330 if (a[key] != b[key]) return false; | 2314 if (a[key] != b[key]) return false; |
| 2331 } | 2315 } |
| 2332 return true; | 2316 return true; |
| 2333 } | 2317 } |
| 2334 } | 2318 } |
| 2335 | 2319 |
| 2336 class BatchDFEProcess { | |
| 2337 io.Process _process; | |
| 2338 int _port = -1; | |
| 2339 Function _processExitHandler; | |
| 2340 | |
| 2341 Completer terminating = null; | |
| 2342 | |
| 2343 bool locked = false; | |
| 2344 | |
| 2345 Future<int> acquire() async { | |
| 2346 try { | |
| 2347 assert(!locked); | |
| 2348 locked = true; | |
| 2349 if (_process == null) { | |
| 2350 await _startProcess(); | |
| 2351 } | |
| 2352 return _port; | |
| 2353 } catch(e) { | |
| 2354 locked = false; | |
| 2355 rethrow; | |
| 2356 } | |
| 2357 } | |
| 2358 | |
| 2359 void release() { | |
| 2360 locked = false; | |
| 2361 } | |
| 2362 | |
| 2363 Future terminate() { | |
| 2364 locked = true; | |
| 2365 if (_process == null) { | |
| 2366 return new Future.value(true); | |
| 2367 } | |
| 2368 if (terminating == null) { | |
| 2369 terminating = new Completer(); | |
| 2370 _process.kill(); | |
| 2371 } | |
| 2372 return terminating.future; | |
| 2373 } | |
| 2374 | |
| 2375 _onExit(exitCode) { | |
| 2376 if (terminating != null) { | |
| 2377 terminating.complete(); | |
| 2378 return; | |
| 2379 } | |
| 2380 | |
| 2381 _process = null; | |
| 2382 locked = false; | |
| 2383 _port = -1; | |
| 2384 } | |
| 2385 | |
| 2386 static Future<String> _firstLine(stream) { | |
| 2387 var completer = new Completer<String>(); | |
| 2388 stream.transform(UTF8.decoder) | |
| 2389 .transform(new LineSplitter()) | |
| 2390 .listen((line) { | |
| 2391 if (!completer.isCompleted) { | |
| 2392 completer.complete(line); | |
| 2393 } | |
| 2394 // We need to drain a pipe continuously. | |
| 2395 }, onDone: () { | |
| 2396 if (!completer.isCompleted) { | |
| 2397 completer.completeError( | |
| 2398 "DFE kernel compiler server did not sucessfully start up"); | |
| 2399 } | |
| 2400 }); | |
| 2401 return completer.future; | |
| 2402 } | |
| 2403 | |
| 2404 Future _startProcess() async { | |
| 2405 final executable = io.Platform.executable; | |
| 2406 final arguments = ['utils/kernel-service/kernel-service.dart', '--batch']; | |
| 2407 | |
| 2408 try { | |
| 2409 _port = -1; | |
| 2410 _process = await io.Process.start(executable, arguments); | |
| 2411 _process.exitCode.then(_onExit); | |
| 2412 _process.stderr.transform(UTF8.decoder).listen(DebugLogger.error); | |
| 2413 | |
| 2414 final readyMsg = await _firstLine(_process.stdout); | |
| 2415 final data = readyMsg.split(' '); | |
| 2416 assert(data[0] == 'READY'); | |
| 2417 | |
| 2418 _port = int.parse(data[1]); | |
| 2419 } catch (e) { | |
| 2420 print("Process error:"); | |
| 2421 print(" Command: $executable ${arguments.join(' ')}"); | |
| 2422 print(" Error: $e"); | |
| 2423 // If there is an error starting a batch process, chances are that | |
| 2424 // it will always fail. So rather than re-trying a 1000+ times, we | |
| 2425 // exit. | |
| 2426 io.exit(1); | |
| 2427 return true; | |
| 2428 } | |
| 2429 } | |
| 2430 } | |
| 2431 | |
| 2432 /** | 2320 /** |
| 2433 * [TestCaseEnqueuer] takes a list of TestSuites, generates TestCases and | 2321 * [TestCaseEnqueuer] takes a list of TestSuites, generates TestCases and |
| 2434 * builds a dependency graph of all commands in every TestSuite. | 2322 * builds a dependency graph of all commands in every TestSuite. |
| 2435 * | 2323 * |
| 2436 * It will maintain three helper data structures | 2324 * It will maintain three helper data structures |
| 2437 * - command2node: A mapping from a [Command] to a node in the dependency graph | 2325 * - command2node: A mapping from a [Command] to a node in the dependency graph |
| 2438 * - command2testCases: A mapping from [Command] to all TestCases that it is | 2326 * - command2testCases: A mapping from [Command] to all TestCases that it is |
| 2439 * part of. | 2327 * part of. |
| 2440 * - remainingTestCases: A set of TestCases that were enqueued but are not | 2328 * - remainingTestCases: A set of TestCases that were enqueued but are not |
| 2441 * finished | 2329 * finished |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2730 final int maxProcesses; | 2618 final int maxProcesses; |
| 2731 final int maxBrowserProcesses; | 2619 final int maxBrowserProcesses; |
| 2732 AdbDevicePool adbDevicePool; | 2620 AdbDevicePool adbDevicePool; |
| 2733 | 2621 |
| 2734 // For dart2js and analyzer batch processing, | 2622 // For dart2js and analyzer batch processing, |
| 2735 // we keep a list of batch processes. | 2623 // we keep a list of batch processes. |
| 2736 final _batchProcesses = new Map<String, List<BatchRunnerProcess>>(); | 2624 final _batchProcesses = new Map<String, List<BatchRunnerProcess>>(); |
| 2737 // We keep a BrowserTestRunner for every configuration. | 2625 // We keep a BrowserTestRunner for every configuration. |
| 2738 final _browserTestRunners = new Map<Map, BrowserTestRunner>(); | 2626 final _browserTestRunners = new Map<Map, BrowserTestRunner>(); |
| 2739 | 2627 |
| 2740 List<BatchDFEProcess> _dfeProcesses = null; | |
| 2741 | |
| 2742 bool _finishing = false; | 2628 bool _finishing = false; |
| 2743 | 2629 |
| 2744 CommandExecutorImpl( | 2630 CommandExecutorImpl( |
| 2745 this.globalConfiguration, this.maxProcesses, this.maxBrowserProcesses, | 2631 this.globalConfiguration, this.maxProcesses, this.maxBrowserProcesses, |
| 2746 {this.adbDevicePool}); | 2632 {this.adbDevicePool}); |
| 2747 | 2633 |
| 2748 Future cleanup() { | 2634 Future cleanup() { |
| 2749 assert(!_finishing); | 2635 assert(!_finishing); |
| 2750 _finishing = true; | 2636 _finishing = true; |
| 2751 | 2637 |
| 2752 Future _terminateBatchRunners() { | 2638 Future _terminateBatchRunners() { |
| 2753 var futures = []; | 2639 var futures = []; |
| 2754 for (var runners in _batchProcesses.values) { | 2640 for (var runners in _batchProcesses.values) { |
| 2755 futures.addAll(runners.map((runner) => runner.terminate())); | 2641 futures.addAll(runners.map((runner) => runner.terminate())); |
| 2756 } | 2642 } |
| 2757 return Future.wait(futures); | 2643 return Future.wait(futures); |
| 2758 } | 2644 } |
| 2759 | 2645 |
| 2760 Future _terminateBrowserRunners() { | 2646 Future _terminateBrowserRunners() { |
| 2761 var futures = | 2647 var futures = |
| 2762 _browserTestRunners.values.map((runner) => runner.terminate()); | 2648 _browserTestRunners.values.map((runner) => runner.terminate()); |
| 2763 return Future.wait(futures); | 2649 return Future.wait(futures); |
| 2764 } | 2650 } |
| 2765 | 2651 |
| 2766 Future _terminateDFEWorkers() => | |
| 2767 Future.wait((_dfeProcesses ?? <BatchDFEProcess>[]).map((p) => p.terminate(
))); | |
| 2768 | |
| 2769 return Future.wait([ | 2652 return Future.wait([ |
| 2770 _terminateBatchRunners(), | 2653 _terminateBatchRunners(), |
| 2771 _terminateBrowserRunners(), | 2654 _terminateBrowserRunners(), |
| 2772 _terminateDFEWorkers() | |
| 2773 ]); | 2655 ]); |
| 2774 } | 2656 } |
| 2775 | 2657 |
| 2776 Future<CommandOutput> runCommand(node, Command command, int timeout) { | 2658 Future<CommandOutput> runCommand(node, Command command, int timeout) { |
| 2777 assert(!_finishing); | 2659 assert(!_finishing); |
| 2778 | 2660 |
| 2779 Future<CommandOutput> runCommand(int retriesLeft) { | 2661 Future<CommandOutput> runCommand(int retriesLeft) { |
| 2780 return _runCommand(command, timeout).then((CommandOutput output) { | 2662 return _runCommand(command, timeout).then((CommandOutput output) { |
| 2781 if (retriesLeft > 0 && shouldRetryCommand(output)) { | 2663 if (retriesLeft > 0 && shouldRetryCommand(output)) { |
| 2782 DebugLogger.warning("Rerunning Command: ($retriesLeft " | 2664 DebugLogger.warning("Rerunning Command: ($retriesLeft " |
| (...skipping 28 matching lines...) Expand all Loading... |
| 2811 } else if (command is ScriptCommand) { | 2693 } else if (command is ScriptCommand) { |
| 2812 return command.run(); | 2694 return command.run(); |
| 2813 } else if (command is AdbPrecompilationCommand) { | 2695 } else if (command is AdbPrecompilationCommand) { |
| 2814 assert(adbDevicePool != null); | 2696 assert(adbDevicePool != null); |
| 2815 return adbDevicePool.acquireDevice().then((AdbDevice device) { | 2697 return adbDevicePool.acquireDevice().then((AdbDevice device) { |
| 2816 return _runAdbPrecompilationCommand(device, command, timeout) | 2698 return _runAdbPrecompilationCommand(device, command, timeout) |
| 2817 .whenComplete(() { | 2699 .whenComplete(() { |
| 2818 adbDevicePool.releaseDevice(device); | 2700 adbDevicePool.releaseDevice(device); |
| 2819 }); | 2701 }); |
| 2820 }); | 2702 }); |
| 2821 } else if (command is VmCommand && command.needsDFERunner) { | |
| 2822 final runner = _getDFEProcess(); | |
| 2823 return runner.acquire().then((port) { | |
| 2824 return new RunningProcess(command, timeout, | |
| 2825 configuration: globalConfiguration, | |
| 2826 preArguments: ['-DDFE_WORKER_PORT=${port}']).run(); | |
| 2827 }).whenComplete(() => runner.release()); | |
| 2828 } else if (command is VmBatchCommand) { | 2703 } else if (command is VmBatchCommand) { |
| 2829 var name = command.displayName; | 2704 var name = command.displayName; |
| 2830 return _getBatchRunner(command.displayName + command.dartFile) | 2705 return _getBatchRunner(command.displayName + command.dartFile) |
| 2831 .runCommand(name, command, timeout, command.arguments); | 2706 .runCommand(name, command, timeout, command.arguments); |
| 2832 } else { | 2707 } else { |
| 2833 return new RunningProcess( | 2708 return new RunningProcess( |
| 2834 command, timeout, configuration: globalConfiguration).run(); | 2709 command, timeout, configuration: globalConfiguration).run(); |
| 2835 } | 2710 } |
| 2836 } | 2711 } |
| 2837 | 2712 |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2921 } | 2796 } |
| 2922 _batchProcesses[identifier] = runners; | 2797 _batchProcesses[identifier] = runners; |
| 2923 } | 2798 } |
| 2924 | 2799 |
| 2925 for (var runner in runners) { | 2800 for (var runner in runners) { |
| 2926 if (!runner._currentlyRunning) return runner; | 2801 if (!runner._currentlyRunning) return runner; |
| 2927 } | 2802 } |
| 2928 throw new Exception('Unable to find inactive batch runner.'); | 2803 throw new Exception('Unable to find inactive batch runner.'); |
| 2929 } | 2804 } |
| 2930 | 2805 |
| 2931 BatchDFEProcess _getDFEProcess() { | |
| 2932 _dfeProcesses ??= new List<BatchDFEProcess>.generate(maxProcesses, | |
| 2933 (_) => new BatchDFEProcess()); | |
| 2934 return _dfeProcesses.firstWhere((runner) => !runner.locked); | |
| 2935 } | |
| 2936 | |
| 2937 Future<CommandOutput> _startBrowserControllerTest( | 2806 Future<CommandOutput> _startBrowserControllerTest( |
| 2938 BrowserTestCommand browserCommand, int timeout) { | 2807 BrowserTestCommand browserCommand, int timeout) { |
| 2939 var completer = new Completer<CommandOutput>(); | 2808 var completer = new Completer<CommandOutput>(); |
| 2940 | 2809 |
| 2941 var callback = (BrowserTestOutput output) { | 2810 var callback = (BrowserTestOutput output) { |
| 2942 completer | 2811 completer |
| 2943 .complete(new BrowserControllerTestOutcome(browserCommand, output)); | 2812 .complete(new BrowserControllerTestOutcome(browserCommand, output)); |
| 2944 }; | 2813 }; |
| 2945 | 2814 |
| 2946 BrowserTest browserTest; | 2815 BrowserTest browserTest; |
| (...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3358 } | 3227 } |
| 3359 } | 3228 } |
| 3360 | 3229 |
| 3361 void eventAllTestsDone() { | 3230 void eventAllTestsDone() { |
| 3362 for (var listener in _eventListener) { | 3231 for (var listener in _eventListener) { |
| 3363 listener.allDone(); | 3232 listener.allDone(); |
| 3364 } | 3233 } |
| 3365 _allDone(); | 3234 _allDone(); |
| 3366 } | 3235 } |
| 3367 } | 3236 } |
| OLD | NEW |