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 import 'dart:async'; | 12 import 'dart:async'; |
13 import 'dart:collection'; | 13 import 'dart:collection'; |
14 import 'dart:convert'; | 14 import 'dart:convert'; |
15 // We need to use the 'io' prefix here, otherwise io.exitCode will shadow | 15 // We need to use the 'io' prefix here, otherwise io.exitCode will shadow |
16 // CommandOutput.exitCode in subclasses of CommandOutput. | 16 // CommandOutput.exitCode in subclasses of CommandOutput. |
17 import 'dart:io' as io; | 17 import 'dart:io' as io; |
18 import 'dart:math' as math; | 18 import 'dart:math' as math; |
19 | 19 |
20 import 'android.dart'; | 20 import 'android.dart'; |
21 import 'browser_controller.dart'; | 21 import 'browser_controller.dart'; |
22 import 'configuration.dart'; | 22 import 'configuration.dart'; |
23 import 'dependency_graph.dart' as dgraph; | 23 import 'dependency_graph.dart' as dgraph; |
24 import 'expectation.dart'; | 24 import 'expectation.dart'; |
25 import 'path.dart'; | 25 import 'path.dart'; |
26 import 'record_and_replay.dart'; | |
27 import 'runtime_configuration.dart'; | 26 import 'runtime_configuration.dart'; |
28 import 'test_progress.dart'; | 27 import 'test_progress.dart'; |
29 import 'test_suite.dart'; | 28 import 'test_suite.dart'; |
30 import 'utils.dart'; | 29 import 'utils.dart'; |
31 | 30 |
32 const int CRASHING_BROWSER_EXITCODE = -10; | 31 const int CRASHING_BROWSER_EXITCODE = -10; |
33 const int SLOW_TIMEOUT_MULTIPLIER = 4; | 32 const int SLOW_TIMEOUT_MULTIPLIER = 4; |
34 const int NON_UTF_FAKE_EXITCODE = 0xFFFD; | 33 const int NON_UTF_FAKE_EXITCODE = 0xFFFD; |
35 | 34 |
36 const MESSAGE_CANNOT_OPEN_DISPLAY = 'Gtk-WARNING **: cannot open display'; | 35 const MESSAGE_CANNOT_OPEN_DISPLAY = 'Gtk-WARNING **: cannot open display'; |
(...skipping 2848 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2885 if (globalConfiguration.isVerbose) { | 2884 if (globalConfiguration.isVerbose) { |
2886 testRunner.logger = DebugLogger.info; | 2885 testRunner.logger = DebugLogger.info; |
2887 } | 2886 } |
2888 _browserTestRunners[configuration] = testRunner; | 2887 _browserTestRunners[configuration] = testRunner; |
2889 await testRunner.start(); | 2888 await testRunner.start(); |
2890 } | 2889 } |
2891 return _browserTestRunners[configuration]; | 2890 return _browserTestRunners[configuration]; |
2892 } | 2891 } |
2893 } | 2892 } |
2894 | 2893 |
2895 class RecordingCommandExecutor implements CommandExecutor { | |
2896 TestCaseRecorder _recorder; | |
2897 | |
2898 RecordingCommandExecutor(Path path) : _recorder = new TestCaseRecorder(path); | |
2899 | |
2900 Future<CommandOutput> runCommand(node, ProcessCommand command, int timeout) { | |
2901 assert(node.dependencies.length == 0); | |
2902 assert(_cleanEnvironmentOverrides(command.environmentOverrides)); | |
2903 _recorder.nextCommand(command, timeout); | |
2904 // Return dummy CommandOutput | |
2905 var output = | |
2906 createCommandOutput(command, 0, false, [], [], const Duration(), false); | |
2907 return new Future.value(output); | |
2908 } | |
2909 | |
2910 Future cleanup() { | |
2911 _recorder.finish(); | |
2912 return new Future.value(); | |
2913 } | |
2914 | |
2915 // Returns [:true:] if the environment contains only 'DART_CONFIGURATION' | |
2916 bool _cleanEnvironmentOverrides(Map environment) { | |
2917 if (environment == null) return true; | |
2918 return environment.length == 0 || | |
2919 (environment.length == 1 && | |
2920 environment.containsKey("DART_CONFIGURATION")); | |
2921 } | |
2922 } | |
2923 | |
2924 class ReplayingCommandExecutor implements CommandExecutor { | |
2925 TestCaseOutputArchive _archive = new TestCaseOutputArchive(); | |
2926 | |
2927 ReplayingCommandExecutor(Path path) { | |
2928 _archive.loadFromPath(path); | |
2929 } | |
2930 | |
2931 Future cleanup() => new Future.value(); | |
2932 | |
2933 Future<CommandOutput> runCommand(node, ProcessCommand command, int timeout) { | |
2934 assert(node.dependencies.length == 0); | |
2935 return new Future.value(_archive.outputOf(command)); | |
2936 } | |
2937 } | |
2938 | |
2939 bool shouldRetryCommand(CommandOutput output) { | 2894 bool shouldRetryCommand(CommandOutput output) { |
2940 if (!output.successful) { | 2895 if (!output.successful) { |
2941 List<String> stdout, stderr; | 2896 List<String> stdout, stderr; |
2942 | 2897 |
2943 decodeOutput() { | 2898 decodeOutput() { |
2944 if (stdout == null && stderr == null) { | 2899 if (stdout == null && stderr == null) { |
2945 stdout = decodeUtf8(output.stderr).split("\n"); | 2900 stdout = decodeUtf8(output.stderr).split("\n"); |
2946 stderr = decodeUtf8(output.stderr).split("\n"); | 2901 stderr = decodeUtf8(output.stderr).split("\n"); |
2947 } | 2902 } |
2948 } | 2903 } |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3109 | 3064 |
3110 ProcessQueue( | 3065 ProcessQueue( |
3111 this._globalConfiguration, | 3066 this._globalConfiguration, |
3112 int maxProcesses, | 3067 int maxProcesses, |
3113 int maxBrowserProcesses, | 3068 int maxBrowserProcesses, |
3114 DateTime startTime, | 3069 DateTime startTime, |
3115 List<TestSuite> testSuites, | 3070 List<TestSuite> testSuites, |
3116 this._eventListener, | 3071 this._eventListener, |
3117 this._allDone, | 3072 this._allDone, |
3118 [bool verbose = false, | 3073 [bool verbose = false, |
3119 String recordingOutputFile, | |
3120 String recordedInputFile, | |
3121 AdbDevicePool adbDevicePool]) { | 3074 AdbDevicePool adbDevicePool]) { |
3122 void setupForListing(TestCaseEnqueuer testCaseEnqueuer) { | 3075 void setupForListing(TestCaseEnqueuer testCaseEnqueuer) { |
3123 _graph.events | 3076 _graph.events |
3124 .where((event) => event is dgraph.GraphSealedEvent) | 3077 .where((event) => event is dgraph.GraphSealedEvent) |
3125 .listen((_) { | 3078 .listen((_) { |
3126 var testCases = testCaseEnqueuer.remainingTestCases.toList(); | 3079 var testCases = testCaseEnqueuer.remainingTestCases.toList(); |
3127 testCases.sort((a, b) => a.displayName.compareTo(b.displayName)); | 3080 testCases.sort((a, b) => a.displayName.compareTo(b.displayName)); |
3128 | 3081 |
3129 print("\nGenerating all matching test cases ....\n"); | 3082 print("\nGenerating all matching test cases ....\n"); |
3130 | 3083 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3191 print(""); | 3144 print(""); |
3192 } | 3145 } |
3193 } | 3146 } |
3194 | 3147 |
3195 if (commandQueue != null) { | 3148 if (commandQueue != null) { |
3196 commandQueue.dumpState(); | 3149 commandQueue.dumpState(); |
3197 } | 3150 } |
3198 }); | 3151 }); |
3199 } | 3152 } |
3200 | 3153 |
3201 bool recording = recordingOutputFile != null; | |
3202 bool replaying = recordedInputFile != null; | |
3203 | |
3204 // When the graph building is finished, notify event listeners. | 3154 // When the graph building is finished, notify event listeners. |
3205 _graph.events | 3155 _graph.events |
3206 .where((event) => event is dgraph.GraphSealedEvent) | 3156 .where((event) => event is dgraph.GraphSealedEvent) |
3207 .listen((event) { | 3157 .listen((event) { |
3208 eventAllTestsKnown(); | 3158 eventAllTestsKnown(); |
3209 }); | 3159 }); |
3210 | 3160 |
3211 // Queue commands as they become "runnable" | 3161 // Queue commands as they become "runnable" |
3212 new CommandEnqueuer(_graph); | 3162 new CommandEnqueuer(_graph); |
3213 | 3163 |
3214 // CommandExecutor will execute commands | 3164 // CommandExecutor will execute commands |
3215 CommandExecutor executor; | 3165 var executor = new CommandExecutorImpl( |
3216 if (recording) { | 3166 _globalConfiguration, maxProcesses, maxBrowserProcesses, |
3217 executor = new RecordingCommandExecutor(new Path(recordingOutputFile)); | 3167 adbDevicePool: adbDevicePool); |
3218 } else if (replaying) { | |
3219 executor = new ReplayingCommandExecutor(new Path(recordedInputFile)); | |
3220 } else { | |
3221 executor = new CommandExecutorImpl( | |
3222 _globalConfiguration, maxProcesses, maxBrowserProcesses, | |
3223 adbDevicePool: adbDevicePool); | |
3224 } | |
3225 | 3168 |
3226 // Run "runnable commands" using [executor] subject to | 3169 // Run "runnable commands" using [executor] subject to |
3227 // maxProcesses/maxBrowserProcesses constraint | 3170 // maxProcesses/maxBrowserProcesses constraint |
3228 commandQueue = new CommandQueue(_graph, testCaseEnqueuer, executor, | 3171 commandQueue = new CommandQueue(_graph, testCaseEnqueuer, executor, |
3229 maxProcesses, maxBrowserProcesses, verbose); | 3172 maxProcesses, maxBrowserProcesses, verbose); |
3230 | 3173 |
3231 // Finish test cases when all commands were run (or some failed) | 3174 // Finish test cases when all commands were run (or some failed) |
3232 var testCaseCompleter = | 3175 var testCaseCompleter = |
3233 new TestCaseCompleter(_graph, testCaseEnqueuer, commandQueue); | 3176 new TestCaseCompleter(_graph, testCaseEnqueuer, commandQueue); |
3234 testCaseCompleter.finishedTestCases.listen((TestCase finishedTestCase) { | 3177 testCaseCompleter.finishedTestCases.listen((TestCase finishedTestCase) { |
3235 resetDebugTimer(); | 3178 resetDebugTimer(); |
3236 | 3179 |
3237 // If we're recording, we don't report any TestCases to listeners. | 3180 eventFinishedTestCase(finishedTestCase); |
3238 if (!recording) { | |
3239 eventFinishedTestCase(finishedTestCase); | |
3240 } | |
3241 }, onDone: () { | 3181 }, onDone: () { |
3242 // Wait until the commandQueue/exectutor is done (it may need to stop | 3182 // Wait until the commandQueue/exectutor is done (it may need to stop |
3243 // batch runners, browser controllers, ....) | 3183 // batch runners, browser controllers, ....) |
3244 commandQueue.done.then((_) { | 3184 commandQueue.done.then((_) { |
3245 cancelDebugTimer(); | 3185 cancelDebugTimer(); |
3246 eventAllTestsDone(); | 3186 eventAllTestsDone(); |
3247 }); | 3187 }); |
3248 }); | 3188 }); |
3249 | 3189 |
3250 resetDebugTimer(); | 3190 resetDebugTimer(); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3289 } | 3229 } |
3290 } | 3230 } |
3291 | 3231 |
3292 void eventAllTestsDone() { | 3232 void eventAllTestsDone() { |
3293 for (var listener in _eventListener) { | 3233 for (var listener in _eventListener) { |
3294 listener.allDone(); | 3234 listener.allDone(); |
3295 } | 3235 } |
3296 _allDone(); | 3236 _allDone(); |
3297 } | 3237 } |
3298 } | 3238 } |
OLD | NEW |