| 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; | 16 import "dart:convert" show LineSplitter, UTF8; |
| 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 'dependency_graph.dart' as dgraph; | 21 import 'dependency_graph.dart' as dgraph; |
| 22 import "browser_controller.dart"; | 22 import "browser_controller.dart"; |
| 23 import "status_file_parser.dart"; | 23 import "status_file_parser.dart"; |
| 24 import "test_progress.dart"; | 24 import "test_progress.dart"; |
| 25 import "test_suite.dart"; | 25 import "test_suite.dart"; |
| 26 import "utils.dart"; | 26 import "utils.dart"; |
| 27 import 'record_and_replay.dart'; | 27 import 'record_and_replay.dart'; |
| 28 | 28 |
| 29 const int CRASHING_BROWSER_EXITCODE = -10; | |
| 30 const int SLOW_TIMEOUT_MULTIPLIER = 4; | 29 const int SLOW_TIMEOUT_MULTIPLIER = 4; |
| 31 | 30 |
| 32 const MESSAGE_CANNOT_OPEN_DISPLAY = 'Gtk-WARNING **: cannot open display'; | 31 const MESSAGE_CANNOT_OPEN_DISPLAY = 'Gtk-WARNING **: cannot open display'; |
| 33 const MESSAGE_FAILED_TO_RUN_COMMAND = 'Failed to run command. return code=1'; | 32 const MESSAGE_FAILED_TO_RUN_COMMAND = 'Failed to run command. return code=1'; |
| 34 | 33 |
| 35 typedef void TestCaseEvent(TestCase testCase); | 34 typedef void TestCaseEvent(TestCase testCase); |
| 36 typedef void ExitCodeEvent(int exitCode); | 35 typedef void ExitCodeEvent(int exitCode); |
| 37 typedef void EnqueueMoreWork(ProcessQueue queue); | 36 typedef void EnqueueMoreWork(ProcessQueue queue); |
| 38 | 37 |
| 39 // Some IO tests use these variables and get confused if the host environment | 38 // Some IO tests use these variables and get confused if the host environment |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 302 bool _equal(Command other) { | 301 bool _equal(Command other) { |
| 303 return | 302 return |
| 304 other is BrowserTestCommand && | 303 other is BrowserTestCommand && |
| 305 super._equal(other) && | 304 super._equal(other) && |
| 306 browser == other.browser && | 305 browser == other.browser && |
| 307 url == other.url && | 306 url == other.url && |
| 308 checkedMode == other.checkedMode; | 307 checkedMode == other.checkedMode; |
| 309 } | 308 } |
| 310 } | 309 } |
| 311 | 310 |
| 312 class SeleniumTestCommand extends Command { | |
| 313 final String browser; | |
| 314 final String url; | |
| 315 | |
| 316 SeleniumTestCommand._(String _browser, | |
| 317 this.url, | |
| 318 String executable, | |
| 319 List<String> arguments, | |
| 320 String configurationDir) | |
| 321 : super._(_browser, executable, arguments, configurationDir), | |
| 322 browser = _browser; | |
| 323 | |
| 324 void _buildHashCode(HashCodeBuilder builder) { | |
| 325 super._buildHashCode(builder); | |
| 326 builder.add(browser); | |
| 327 builder.add(url); | |
| 328 } | |
| 329 | |
| 330 bool _equal(Command other) { | |
| 331 return | |
| 332 other is SeleniumTestCommand && | |
| 333 super._equal(other) && | |
| 334 browser == other.browser && | |
| 335 url == other.url; | |
| 336 } | |
| 337 } | |
| 338 | |
| 339 class AnalysisCommand extends Command { | 311 class AnalysisCommand extends Command { |
| 340 final String flavor; | 312 final String flavor; |
| 341 | 313 |
| 342 // If [fileFilter] is given, only errors/warnings reported by the analyzer | 314 // If [fileFilter] is given, only errors/warnings reported by the analyzer |
| 343 // for which [fileFilter] returns [:true:] are considered. | 315 // for which [fileFilter] returns [:true:] are considered. |
| 344 final Function fileFilter; | 316 final Function fileFilter; |
| 345 | 317 |
| 346 AnalysisCommand._(this.flavor, | 318 AnalysisCommand._(this.flavor, |
| 347 String displayName, | 319 String displayName, |
| 348 String executable, | 320 String executable, |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 408 String executable, | 380 String executable, |
| 409 List<String> arguments, | 381 List<String> arguments, |
| 410 String configurationDir, | 382 String configurationDir, |
| 411 {bool checkedMode: false}) { | 383 {bool checkedMode: false}) { |
| 412 var command = new BrowserTestCommand._( | 384 var command = new BrowserTestCommand._( |
| 413 browser, url, executable, arguments, configurationDir, | 385 browser, url, executable, arguments, configurationDir, |
| 414 checkedMode: checkedMode); | 386 checkedMode: checkedMode); |
| 415 return _getUniqueCommand(command); | 387 return _getUniqueCommand(command); |
| 416 } | 388 } |
| 417 | 389 |
| 418 SeleniumTestCommand getSeleniumTestCommand(String browser, | |
| 419 String url, | |
| 420 String executable, | |
| 421 List<String> arguments, | |
| 422 String configurationDir) { | |
| 423 var command = new SeleniumTestCommand._( | |
| 424 browser, url, executable, arguments, configurationDir); | |
| 425 return _getUniqueCommand(command); | |
| 426 } | |
| 427 | |
| 428 CompilationCommand getCompilationCommand(String displayName, | 390 CompilationCommand getCompilationCommand(String displayName, |
| 429 outputFile, | 391 outputFile, |
| 430 neverSkipCompilation, | 392 neverSkipCompilation, |
| 431 List<String> bootstrapDependencies, | 393 List<String> bootstrapDependencies, |
| 432 String executable, | 394 String executable, |
| 433 List<String> arguments, | 395 List<String> arguments, |
| 434 String configurationDir) { | 396 String configurationDir) { |
| 435 var command = | 397 var command = |
| 436 new CompilationCommand._(displayName, outputFile, neverSkipCompilation, | 398 new CompilationCommand._(displayName, outputFile, neverSkipCompilation, |
| 437 bootstrapDependencies, executable, arguments, | 399 bootstrapDependencies, executable, arguments, |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 556 final compiler = configuration['compiler']; | 518 final compiler = configuration['compiler']; |
| 557 final runtime = configuration['runtime']; | 519 final runtime = configuration['runtime']; |
| 558 final mode = configuration['mode']; | 520 final mode = configuration['mode']; |
| 559 final arch = configuration['arch']; | 521 final arch = configuration['arch']; |
| 560 final checked = configuration['checked'] ? '-checked' : ''; | 522 final checked = configuration['checked'] ? '-checked' : ''; |
| 561 return "$compiler-$runtime$checked ${mode}_$arch"; | 523 return "$compiler-$runtime$checked ${mode}_$arch"; |
| 562 } | 524 } |
| 563 | 525 |
| 564 List<String> get batchTestArguments => commands.last.arguments; | 526 List<String> get batchTestArguments => commands.last.arguments; |
| 565 | 527 |
| 566 bool get usesWebDriver => TestUtils.usesWebDriver(configuration['runtime']); | |
| 567 | |
| 568 bool get isFlaky { | 528 bool get isFlaky { |
| 569 if (expectedOutcomes.contains(Expectation.SKIP) || | 529 if (expectedOutcomes.contains(Expectation.SKIP) || |
| 570 expectedOutcomes.contains(Expectation.SKIP_BY_DESIGN)) { | 530 expectedOutcomes.contains(Expectation.SKIP_BY_DESIGN)) { |
| 571 return false; | 531 return false; |
| 572 } | 532 } |
| 573 | 533 |
| 574 return expectedOutcomes | 534 return expectedOutcomes |
| 575 .where((expectation) => !expectation.isMetaExpectation).length > 1; | 535 .where((expectation) => !expectation.isMetaExpectation).length > 1; |
| 576 } | 536 } |
| 577 | 537 |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 696 bool get hasCrashed { | 656 bool get hasCrashed { |
| 697 // The Java dartc runner and dart2js exits with code 253 in case | 657 // The Java dartc runner and dart2js exits with code 253 in case |
| 698 // of unhandled exceptions. | 658 // of unhandled exceptions. |
| 699 if (exitCode == 253) return true; | 659 if (exitCode == 253) return true; |
| 700 if (io.Platform.operatingSystem == 'windows') { | 660 if (io.Platform.operatingSystem == 'windows') { |
| 701 // The VM uses std::abort to terminate on asserts. | 661 // The VM uses std::abort to terminate on asserts. |
| 702 // std::abort terminates with exit code 3 on Windows. | 662 // std::abort terminates with exit code 3 on Windows. |
| 703 if (exitCode == 3) { | 663 if (exitCode == 3) { |
| 704 return !timedOut; | 664 return !timedOut; |
| 705 } | 665 } |
| 706 // TODO(ricow): Remove this dirty hack ones we have a selenium | |
| 707 // replacement. | |
| 708 if (exitCode == CRASHING_BROWSER_EXITCODE) { | |
| 709 return !timedOut; | |
| 710 } | |
| 711 // If a program receives an uncaught system exception, the program | 666 // If a program receives an uncaught system exception, the program |
| 712 // terminates with the exception code as exit code. | 667 // terminates with the exception code as exit code. |
| 713 // The 0x3FFFFF00 mask here tries to determine if an exception indicates | 668 // The 0x3FFFFF00 mask here tries to determine if an exception indicates |
| 714 // a crash of the program. | 669 // a crash of the program. |
| 715 // System exception codes can be found in 'winnt.h', for example | 670 // System exception codes can be found in 'winnt.h', for example |
| 716 // "#define STATUS_ACCESS_VIOLATION ((DWORD) 0xC0000005)" | 671 // "#define STATUS_ACCESS_VIOLATION ((DWORD) 0xC0000005)" |
| 717 return (!timedOut && (exitCode < 0) && ((0x3FFFFF00 & exitCode) == 0)); | 672 return (!timedOut && (exitCode < 0) && ((0x3FFFFF00 & exitCode) == 0)); |
| 718 } | 673 } |
| 719 return !timedOut && ((exitCode < 0)); | 674 return !timedOut && ((exitCode < 0)); |
| 720 } | 675 } |
| (...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1160 Duration time, | 1115 Duration time, |
| 1161 bool compilationSkipped) { | 1116 bool compilationSkipped) { |
| 1162 if (command is ContentShellCommand) { | 1117 if (command is ContentShellCommand) { |
| 1163 return new BrowserCommandOutputImpl( | 1118 return new BrowserCommandOutputImpl( |
| 1164 command, exitCode, timedOut, stdout, stderr, | 1119 command, exitCode, timedOut, stdout, stderr, |
| 1165 time, compilationSkipped); | 1120 time, compilationSkipped); |
| 1166 } else if (command is BrowserTestCommand) { | 1121 } else if (command is BrowserTestCommand) { |
| 1167 return new HTMLBrowserCommandOutputImpl( | 1122 return new HTMLBrowserCommandOutputImpl( |
| 1168 command, exitCode, timedOut, stdout, stderr, | 1123 command, exitCode, timedOut, stdout, stderr, |
| 1169 time, compilationSkipped); | 1124 time, compilationSkipped); |
| 1170 } else if (command is SeleniumTestCommand) { | |
| 1171 return new BrowserCommandOutputImpl( | |
| 1172 command, exitCode, timedOut, stdout, stderr, | |
| 1173 time, compilationSkipped); | |
| 1174 } else if (command is AnalysisCommand) { | 1125 } else if (command is AnalysisCommand) { |
| 1175 return new AnalysisCommandOutputImpl( | 1126 return new AnalysisCommandOutputImpl( |
| 1176 command, exitCode, timedOut, stdout, stderr, | 1127 command, exitCode, timedOut, stdout, stderr, |
| 1177 time, compilationSkipped); | 1128 time, compilationSkipped); |
| 1178 } else if (command is VmCommand) { | 1129 } else if (command is VmCommand) { |
| 1179 return new VmCommandOutputImpl( | 1130 return new VmCommandOutputImpl( |
| 1180 command, exitCode, timedOut, stdout, stderr, time); | 1131 command, exitCode, timedOut, stdout, stderr, time); |
| 1181 } else if (command is CompilationCommand) { | 1132 } else if (command is CompilationCommand) { |
| 1182 return new CompilationCommandOutputImpl( | 1133 return new CompilationCommandOutputImpl( |
| 1183 command, exitCode, timedOut, stdout, stderr, time); | 1134 command, exitCode, timedOut, stdout, stderr, time); |
| 1184 } else if (command is JSCommandlineCommand) { | 1135 } else if (command is JSCommandlineCommand) { |
| 1185 return new JsCommandlineOutputImpl( | 1136 return new JsCommandlineOutputImpl( |
| 1186 command, exitCode, timedOut, stdout, stderr, time); | 1137 command, exitCode, timedOut, stdout, stderr, time); |
| 1187 } | 1138 } |
| 1188 | 1139 |
| 1189 return new CommandOutputImpl( | 1140 return new CommandOutputImpl( |
| 1190 command, exitCode, timedOut, stdout, stderr, | 1141 command, exitCode, timedOut, stdout, stderr, |
| 1191 time, compilationSkipped); | 1142 time, compilationSkipped); |
| 1192 } | 1143 } |
| 1193 | 1144 |
| 1194 | 1145 |
| 1195 /** Modifies the --timeout=XX parameter passed to run_selenium.py */ | |
| 1196 List<String> _modifySeleniumTimeout(List<String> arguments, int timeout) { | |
| 1197 return arguments.map((argument) { | |
| 1198 if (argument.startsWith('--timeout=')) { | |
| 1199 return "--timeout=$timeout"; | |
| 1200 } else { | |
| 1201 return argument; | |
| 1202 } | |
| 1203 }).toList(); | |
| 1204 } | |
| 1205 | |
| 1206 | |
| 1207 /** | 1146 /** |
| 1208 * A RunningProcess actually runs a test, getting the command lines from | 1147 * A RunningProcess actually runs a test, getting the command lines from |
| 1209 * its [TestCase], starting the test process (and first, a compilation | 1148 * its [TestCase], starting the test process (and first, a compilation |
| 1210 * process if the TestCase is a [BrowserTestCase]), creating a timeout | 1149 * process if the TestCase is a [BrowserTestCase]), creating a timeout |
| 1211 * timer, and recording the results in a new [CommandOutput] object, which it | 1150 * timer, and recording the results in a new [CommandOutput] object, which it |
| 1212 * attaches to the TestCase. The lifetime of the RunningProcess is limited | 1151 * attaches to the TestCase. The lifetime of the RunningProcess is limited |
| 1213 * to the time it takes to start the process, run the process, and record | 1152 * to the time it takes to start the process, run the process, and record |
| 1214 * the result; there are no pointers to it, so it should be available to | 1153 * the result; there are no pointers to it, so it should be available to |
| 1215 * be garbage collected as soon as it is done. | 1154 * be garbage collected as soon as it is done. |
| 1216 */ | 1155 */ |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1234 return completer.future; | 1173 return completer.future; |
| 1235 } | 1174 } |
| 1236 | 1175 |
| 1237 void _runCommand() { | 1176 void _runCommand() { |
| 1238 command.outputIsUpToDate.then((bool isUpToDate) { | 1177 command.outputIsUpToDate.then((bool isUpToDate) { |
| 1239 if (isUpToDate) { | 1178 if (isUpToDate) { |
| 1240 compilationSkipped = true; | 1179 compilationSkipped = true; |
| 1241 _commandComplete(0); | 1180 _commandComplete(0); |
| 1242 } else { | 1181 } else { |
| 1243 var processEnvironment = _createProcessEnvironment(); | 1182 var processEnvironment = _createProcessEnvironment(); |
| 1244 var commandArguments = _modifySeleniumTimeout(command.arguments, | |
| 1245 timeout); | |
| 1246 Future processFuture = | 1183 Future processFuture = |
| 1247 io.Process.start(command.executable, | 1184 io.Process.start(command.executable, |
| 1248 commandArguments, | 1185 command.arguments, |
| 1249 environment: processEnvironment); | 1186 environment: processEnvironment); |
| 1250 processFuture.then((io.Process process) { | 1187 processFuture.then((io.Process process) { |
| 1251 // Close stdin so that tests that try to block on input will fail. | 1188 // Close stdin so that tests that try to block on input will fail. |
| 1252 process.stdin.close(); | 1189 process.stdin.close(); |
| 1253 void timeoutHandler() { | 1190 void timeoutHandler() { |
| 1254 timedOut = true; | 1191 timedOut = true; |
| 1255 if (process != null) { | 1192 if (process != null) { |
| 1256 process.kill(); | 1193 process.kill(); |
| 1257 } | 1194 } |
| 1258 } | 1195 } |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1311 } | 1248 } |
| 1312 | 1249 |
| 1313 return environment; | 1250 return environment; |
| 1314 } | 1251 } |
| 1315 } | 1252 } |
| 1316 | 1253 |
| 1317 class BatchRunnerProcess { | 1254 class BatchRunnerProcess { |
| 1318 static bool isWindows = io.Platform.operatingSystem == 'windows'; | 1255 static bool isWindows = io.Platform.operatingSystem == 'windows'; |
| 1319 | 1256 |
| 1320 final batchRunnerTypes = { | 1257 final batchRunnerTypes = { |
| 1321 'selenium' : { | |
| 1322 'run_executable' : 'python', | |
| 1323 'run_arguments' : ['tools/testing/run_selenium.py', '--batch'], | |
| 1324 'terminate_command' : ['--terminate'], | |
| 1325 }, | |
| 1326 'dartanalyzer' : { | 1258 'dartanalyzer' : { |
| 1327 'run_executable' : | 1259 'run_executable' : |
| 1328 isWindows ? | 1260 isWindows ? |
| 1329 'sdk\\bin\\dartanalyzer_developer.bat' | 1261 'sdk\\bin\\dartanalyzer_developer.bat' |
| 1330 : 'sdk/bin/dartanalyzer_developer', | 1262 : 'sdk/bin/dartanalyzer_developer', |
| 1331 'run_arguments' : ['--batch'], | 1263 'run_arguments' : ['--batch'], |
| 1332 'terminate_command' : null, | |
| 1333 }, | 1264 }, |
| 1334 'dart2analyzer' : { | 1265 'dart2analyzer' : { |
| 1335 // This is a unix shell script, no windows equivalent available | 1266 // This is a unix shell script, no windows equivalent available |
| 1336 'run_executable' : 'editor/tools/analyzer', | 1267 'run_executable' : 'editor/tools/analyzer', |
| 1337 'run_arguments' : ['--batch'], | 1268 'run_arguments' : ['--batch'], |
| 1338 'terminate_command' : null, | |
| 1339 }, | 1269 }, |
| 1340 }; | 1270 }; |
| 1341 | 1271 |
| 1342 Completer<CommandOutput> _completer; | 1272 Completer<CommandOutput> _completer; |
| 1343 Command _command; | 1273 Command _command; |
| 1344 List<String> _arguments; | 1274 List<String> _arguments; |
| 1345 String _runnerType; | 1275 String _runnerType; |
| 1346 | 1276 |
| 1347 io.Process _process; | 1277 io.Process _process; |
| 1348 Map _processEnvironmentOverrides; | 1278 Map _processEnvironmentOverrides; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1396 } | 1326 } |
| 1397 | 1327 |
| 1398 Future terminate() { | 1328 Future terminate() { |
| 1399 if (_process == null) return new Future.value(true); | 1329 if (_process == null) return new Future.value(true); |
| 1400 Completer terminateCompleter = new Completer(); | 1330 Completer terminateCompleter = new Completer(); |
| 1401 Timer killTimer; | 1331 Timer killTimer; |
| 1402 _processExitHandler = (_) { | 1332 _processExitHandler = (_) { |
| 1403 if (killTimer != null) killTimer.cancel(); | 1333 if (killTimer != null) killTimer.cancel(); |
| 1404 terminateCompleter.complete(true); | 1334 terminateCompleter.complete(true); |
| 1405 }; | 1335 }; |
| 1406 var shutdownCommand = batchRunnerTypes[_runnerType]['terminate_command']; | 1336 _process.kill(); |
| 1407 if (shutdownCommand != null && !shutdownCommand.isEmpty) { | |
| 1408 // Use a graceful shutdown so our Selenium script can close | |
| 1409 // the open browser processes. On Windows, signals do not exist | |
| 1410 // and a kill is a hard kill. | |
| 1411 _process.stdin.writeln(shutdownCommand.join(' ')); | |
| 1412 | |
| 1413 // In case the run_selenium process didn't close, kill it after 30s | |
| 1414 killTimer = new Timer(new Duration(seconds: 30), _process.kill); | |
| 1415 } else { | |
| 1416 _process.kill(); | |
| 1417 } | |
| 1418 | 1337 |
| 1419 return terminateCompleter.future; | 1338 return terminateCompleter.future; |
| 1420 } | 1339 } |
| 1421 | 1340 |
| 1422 void doStartTest(Command command, int timeout) { | 1341 void doStartTest(Command command, int timeout) { |
| 1423 _startTime = new DateTime.now(); | 1342 _startTime = new DateTime.now(); |
| 1424 _testStdout = []; | 1343 _testStdout = []; |
| 1425 _testStderr = []; | 1344 _testStderr = []; |
| 1426 _status = null; | 1345 _status = null; |
| 1427 _stdoutCompleter = new Completer(); | 1346 _stdoutCompleter = new Completer(); |
| 1428 _stderrCompleter = new Completer(); | 1347 _stderrCompleter = new Completer(); |
| 1429 _timer = new Timer(new Duration(seconds: timeout), | 1348 _timer = new Timer(new Duration(seconds: timeout), |
| 1430 _timeoutHandler); | 1349 _timeoutHandler); |
| 1431 | 1350 |
| 1432 var line = _createArgumentsLine(_arguments, timeout); | 1351 var line = _createArgumentsLine(_arguments, timeout); |
| 1433 _process.stdin.write(line); | 1352 _process.stdin.write(line); |
| 1434 _stdoutSubscription.resume(); | 1353 _stdoutSubscription.resume(); |
| 1435 _stderrSubscription.resume(); | 1354 _stderrSubscription.resume(); |
| 1436 Future.wait([_stdoutCompleter.future, | 1355 Future.wait([_stdoutCompleter.future, |
| 1437 _stderrCompleter.future]).then((_) => _reportResult()); | 1356 _stderrCompleter.future]).then((_) => _reportResult()); |
| 1438 } | 1357 } |
| 1439 | 1358 |
| 1440 String _createArgumentsLine(List<String> arguments, int timeout) { | 1359 String _createArgumentsLine(List<String> arguments, int timeout) { |
| 1441 arguments = _modifySeleniumTimeout(arguments, timeout); | |
| 1442 return arguments.join(' ') + '\n'; | 1360 return arguments.join(' ') + '\n'; |
| 1443 } | 1361 } |
| 1444 | 1362 |
| 1445 void _reportResult() { | 1363 void _reportResult() { |
| 1446 if (!_currentlyRunning) return; | 1364 if (!_currentlyRunning) return; |
| 1447 // _status == '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}' | 1365 // _status == '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}' |
| 1448 | 1366 |
| 1449 var outcome = _status.split(" ")[2]; | 1367 var outcome = _status.split(" ")[2]; |
| 1450 var exitCode = 0; | 1368 var exitCode = 0; |
| 1451 if (outcome == "CRASH") exitCode = CRASHING_BROWSER_EXITCODE; | |
| 1452 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1; | 1369 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1; |
| 1453 var output = createCommandOutput(_command, | 1370 var output = createCommandOutput(_command, |
| 1454 exitCode, | 1371 exitCode, |
| 1455 (outcome == "TIMEOUT"), | 1372 (outcome == "TIMEOUT"), |
| 1456 _testStdout, | 1373 _testStdout, |
| 1457 _testStderr, | 1374 _testStderr, |
| 1458 new DateTime.now().difference(_startTime), | 1375 new DateTime.now().difference(_startTime), |
| 1459 false); | 1376 false); |
| 1460 assert(_completer != null); | 1377 assert(_completer != null); |
| 1461 _completer.complete(output); | 1378 _completer.complete(output); |
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1760 | 1677 |
| 1761 Stream<CommandOutput> get completedCommands => _commandOutputStream.stream; | 1678 Stream<CommandOutput> get completedCommands => _commandOutputStream.stream; |
| 1762 | 1679 |
| 1763 Future get done => _completer.future; | 1680 Future get done => _completer.future; |
| 1764 | 1681 |
| 1765 void _tryRunNextCommand() { | 1682 void _tryRunNextCommand() { |
| 1766 _checkDone(); | 1683 _checkDone(); |
| 1767 | 1684 |
| 1768 if (_numProcesses < _maxProcesses && !_runQueue.isEmpty) { | 1685 if (_numProcesses < _maxProcesses && !_runQueue.isEmpty) { |
| 1769 Command command = _runQueue.removeFirst(); | 1686 Command command = _runQueue.removeFirst(); |
| 1770 var isBrowserCommand = | 1687 var isBrowserCommand = command is BrowserTestCommand; |
| 1771 command is SeleniumTestCommand || | |
| 1772 command is BrowserTestCommand; | |
| 1773 | 1688 |
| 1774 if (isBrowserCommand && _numBrowserProcesses == _maxBrowserProcesses) { | 1689 if (isBrowserCommand && _numBrowserProcesses == _maxBrowserProcesses) { |
| 1775 // If there is no free browser runner, put it back into the queue. | 1690 // If there is no free browser runner, put it back into the queue. |
| 1776 _runQueue.add(command); | 1691 _runQueue.add(command); |
| 1777 // Don't lose a process. | 1692 // Don't lose a process. |
| 1778 new Timer(new Duration(milliseconds: 100), _tryRunNextCommand); | 1693 new Timer(new Duration(milliseconds: 100), _tryRunNextCommand); |
| 1779 return; | 1694 return; |
| 1780 } | 1695 } |
| 1781 | 1696 |
| 1782 _numProcesses++; | 1697 _numProcesses++; |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1848 // TODO(kustermann): The [timeout] parameter should be a property of Command | 1763 // TODO(kustermann): The [timeout] parameter should be a property of Command |
| 1849 Future<CommandOutput> runCommand( | 1764 Future<CommandOutput> runCommand( |
| 1850 dgraph.Node node, Command command, int timeout); | 1765 dgraph.Node node, Command command, int timeout); |
| 1851 } | 1766 } |
| 1852 | 1767 |
| 1853 class CommandExecutorImpl implements CommandExecutor { | 1768 class CommandExecutorImpl implements CommandExecutor { |
| 1854 final Map globalConfiguration; | 1769 final Map globalConfiguration; |
| 1855 final int maxProcesses; | 1770 final int maxProcesses; |
| 1856 final int maxBrowserProcesses; | 1771 final int maxBrowserProcesses; |
| 1857 | 1772 |
| 1858 // For dartc/selenium batch processing we keep a list of batch processes. | 1773 // For dartanalyzer batch processing we keep a list of batch processes. |
| 1859 final _batchProcesses = new Map<String, List<BatchRunnerProcess>>(); | 1774 final _batchProcesses = new Map<String, List<BatchRunnerProcess>>(); |
| 1860 // We keep a BrowserTestRunner for every "browserName-checked" configuration. | 1775 // We keep a BrowserTestRunner for every "browserName-checked" configuration. |
| 1861 final _browserTestRunners = new Map<String, BrowserTestRunner>(); | 1776 final _browserTestRunners = new Map<String, BrowserTestRunner>(); |
| 1862 | 1777 |
| 1863 bool _finishing = false; | 1778 bool _finishing = false; |
| 1864 | 1779 |
| 1865 CommandExecutorImpl( | 1780 CommandExecutorImpl( |
| 1866 this.globalConfiguration, this.maxProcesses, this.maxBrowserProcesses); | 1781 this.globalConfiguration, this.maxProcesses, this.maxBrowserProcesses); |
| 1867 | 1782 |
| 1868 Future cleanup() { | 1783 Future cleanup() { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1901 }); | 1816 }); |
| 1902 } | 1817 } |
| 1903 return runCommand(command.maxNumRetries); | 1818 return runCommand(command.maxNumRetries); |
| 1904 } | 1819 } |
| 1905 | 1820 |
| 1906 Future<CommandOutput> _runCommand(Command command, int timeout) { | 1821 Future<CommandOutput> _runCommand(Command command, int timeout) { |
| 1907 var batchMode = !globalConfiguration['noBatch']; | 1822 var batchMode = !globalConfiguration['noBatch']; |
| 1908 | 1823 |
| 1909 if (command is BrowserTestCommand) { | 1824 if (command is BrowserTestCommand) { |
| 1910 return _startBrowserControllerTest(command, timeout); | 1825 return _startBrowserControllerTest(command, timeout); |
| 1911 } else if (command is SeleniumTestCommand && batchMode) { | |
| 1912 var arguments = ['--force-refresh', '--browser=${command.browser}', | |
| 1913 '--timeout=${timeout}', '--out', '${command.url}']; | |
| 1914 return _getBatchRunner(command.browser) | |
| 1915 .runCommand('selenium', command, timeout, arguments); | |
| 1916 } else if (command is AnalysisCommand && batchMode) { | 1826 } else if (command is AnalysisCommand && batchMode) { |
| 1917 return _getBatchRunner(command.flavor) | 1827 return _getBatchRunner(command.flavor) |
| 1918 .runCommand(command.flavor, command, timeout, command.arguments); | 1828 .runCommand(command.flavor, command, timeout, command.arguments); |
| 1919 } else { | 1829 } else { |
| 1920 return new RunningProcess(command, timeout).run(); | 1830 return new RunningProcess(command, timeout).run(); |
| 1921 } | 1831 } |
| 1922 } | 1832 } |
| 1923 | 1833 |
| 1924 BatchRunnerProcess _getBatchRunner(String identifier) { | 1834 BatchRunnerProcess _getBatchRunner(String identifier) { |
| 1925 // Start batch processes if needed | 1835 // Start batch processes if needed |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2071 // "xvfb-run" issue 7564, try re-running the test. | 1981 // "xvfb-run" issue 7564, try re-running the test. |
| 2072 bool containsFailureMsg(String line) { | 1982 bool containsFailureMsg(String line) { |
| 2073 return line.contains(MESSAGE_CANNOT_OPEN_DISPLAY) || | 1983 return line.contains(MESSAGE_CANNOT_OPEN_DISPLAY) || |
| 2074 line.contains(MESSAGE_FAILED_TO_RUN_COMMAND); | 1984 line.contains(MESSAGE_FAILED_TO_RUN_COMMAND); |
| 2075 } | 1985 } |
| 2076 if (stdout.any(containsFailureMsg) || stderr.any(containsFailureMsg)) { | 1986 if (stdout.any(containsFailureMsg) || stderr.any(containsFailureMsg)) { |
| 2077 return true; | 1987 return true; |
| 2078 } | 1988 } |
| 2079 } | 1989 } |
| 2080 | 1990 |
| 2081 // Selenium tests can be flaky. Try re-running. | |
| 2082 if (command is SeleniumTestCommand) { | |
| 2083 return true; | |
| 2084 } | |
| 2085 | |
| 2086 // We currently rerun dartium tests, see issue 14074 | 1991 // We currently rerun dartium tests, see issue 14074 |
| 2087 if (command is BrowserTestCommand && command.displayName == 'dartium') { | 1992 if (command is BrowserTestCommand && command.displayName == 'dartium') { |
| 2088 return true; | 1993 return true; |
| 2089 } | 1994 } |
| 2090 } | 1995 } |
| 2091 return false; | 1996 return false; |
| 2092 } | 1997 } |
| 2093 | 1998 |
| 2094 /* | 1999 /* |
| 2095 * [TestCaseCompleter] will listen for | 2000 * [TestCaseCompleter] will listen for |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2309 } | 2214 } |
| 2310 } | 2215 } |
| 2311 | 2216 |
| 2312 void eventAllTestsDone() { | 2217 void eventAllTestsDone() { |
| 2313 for (var listener in _eventListener) { | 2218 for (var listener in _eventListener) { |
| 2314 listener.allDone(); | 2219 listener.allDone(); |
| 2315 } | 2220 } |
| 2316 _allDone(); | 2221 _allDone(); |
| 2317 } | 2222 } |
| 2318 } | 2223 } |
| OLD | NEW |