Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(62)

Side by Side Diff: tools/testing/dart/test_runner.dart

Issue 14757019: Add browser controller and allow it to be used under a flag. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 // We need to use the 'io' prefix here, otherwise io.exitCode will shadow 16 // We need to use the 'io' prefix here, otherwise io.exitCode will shadow
17 // CommandOutput.exitCode in subclasses of CommandOutput. 17 // CommandOutput.exitCode in subclasses of CommandOutput.
18 import "dart:io" as io; 18 import "dart:io" as io;
19 import "dart:isolate"; 19 import "dart:isolate";
20 import "dart:uri"; 20 import "dart:uri";
21 import "browser_controler.dart";
kustermann 2013/05/13 16:00:00 browser_controler -> browser_controller + file ren
ricow1 2013/05/14 07:20:58 Done.
21 import "http_server.dart" as http_server; 22 import "http_server.dart" as http_server;
22 import "status_file_parser.dart"; 23 import "status_file_parser.dart";
23 import "test_progress.dart"; 24 import "test_progress.dart";
24 import "test_suite.dart"; 25 import "test_suite.dart";
25 import "utils.dart"; 26 import "utils.dart";
26 27
27 const int NO_TIMEOUT = 0; 28 const int NO_TIMEOUT = 0;
28 const int SLOW_TIMEOUT_MULTIPLIER = 4; 29 const int SLOW_TIMEOUT_MULTIPLIER = 4;
29 30
30 const int CRASHING_BROWSER_EXITCODE = -10; 31 const int CRASHING_BROWSER_EXITCODE = -10;
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after
341 final arch = configuration['arch']; 342 final arch = configuration['arch'];
342 final checked = configuration['checked'] ? '-checked' : ''; 343 final checked = configuration['checked'] ? '-checked' : '';
343 return "$compiler-$runtime$checked ${mode}_$arch"; 344 return "$compiler-$runtime$checked ${mode}_$arch";
344 } 345 }
345 346
346 List<String> get batchRunnerArguments => ['-batch']; 347 List<String> get batchRunnerArguments => ['-batch'];
347 List<String> get batchTestArguments => commands.last.arguments; 348 List<String> get batchTestArguments => commands.last.arguments;
348 349
349 bool get usesWebDriver => TestUtils.usesWebDriver(configuration['runtime']); 350 bool get usesWebDriver => TestUtils.usesWebDriver(configuration['runtime']);
350 351
352 bool get usesBrowserControler => configuration['use_browser_controller'];
kustermann 2013/05/13 16:00:00 Controler -> Controller
ricow1 2013/05/14 07:20:58 Done.
353
351 void completed() { completedHandler(this); } 354 void completed() { completedHandler(this); }
352 355
353 bool get isFlaky { 356 bool get isFlaky {
354 if (expectedOutcomes.contains(SKIP)) { 357 if (expectedOutcomes.contains(SKIP)) {
355 return false; 358 return false;
356 } 359 }
357 360
358 var flags = new Set.from(expectedOutcomes); 361 var flags = new Set.from(expectedOutcomes);
359 flags..remove(TIMEOUT) 362 flags..remove(TIMEOUT)
360 ..remove(SLOW); 363 ..remove(SLOW);
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
519 } 522 }
520 factory CommandOutputImpl.fromCase(TestCase testCase, 523 factory CommandOutputImpl.fromCase(TestCase testCase,
521 Command command, 524 Command command,
522 int exitCode, 525 int exitCode,
523 bool incomplete, 526 bool incomplete,
524 bool timedOut, 527 bool timedOut,
525 List<int> stdout, 528 List<int> stdout,
526 List<int> stderr, 529 List<int> stderr,
527 Duration time, 530 Duration time,
528 bool compilationSkipped) { 531 bool compilationSkipped) {
529 if (testCase is BrowserTestCase) { 532 if (testCase.usesBrowserControler) {
533 return new HTMLBrowserCommandOutputImpl(testCase,
534 command,
535 exitCode,
536 incomplete,
537 timedOut,
538 stdout,
539 stderr,
540 time,
541 compilationSkipped);
542 } else if (testCase is BrowserTestCase) {
530 return new BrowserCommandOutputImpl(testCase, 543 return new BrowserCommandOutputImpl(testCase,
531 command, 544 command,
532 exitCode, 545 exitCode,
533 incomplete, 546 incomplete,
534 timedOut, 547 timedOut,
535 stdout, 548 stdout,
536 stderr, 549 stderr,
537 time, 550 time,
538 compilationSkipped); 551 compilationSkipped);
539 } else if (testCase.configuration['analyzer']) { 552 } else if (testCase.configuration['analyzer']) {
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
739 return (exitCode != 0 && !hasCrashed); 752 return (exitCode != 0 && !hasCrashed);
740 } 753 }
741 } 754 }
742 break; 755 break;
743 } 756 }
744 } 757 }
745 return true; 758 return true;
746 } 759 }
747 } 760 }
748 761
762 class HTMLBrowserCommandOutputImpl extends BrowserCommandOutputImpl {
763 HTMLBrowserCommandOutputImpl(
764 testCase,
765 command,
766 exitCode,
767 incomplete,
768 timedOut,
769 stdout,
770 stderr,
771 time,
772 compilationSkipped) :
773 super(testCase,
774 command,
775 exitCode,
776 incomplete,
777 timedOut,
778 stdout,
779 stderr,
780 time,
781 compilationSkipped);
782
783 bool get _browserTestFailure {
784 // We should not need to convert back and forward.
785 var output = decodeUtf8(super.stdout);
786 if (output.contains("FAIL")) return true;
787 return !output.contains("PASS");
788 }
789 }
790
791
749 // The static analyzer does not actually execute code, so 792 // The static analyzer does not actually execute code, so
750 // the criteria for success now depend on the text sent 793 // the criteria for success now depend on the text sent
751 // to stderr. 794 // to stderr.
752 class AnalysisCommandOutputImpl extends CommandOutputImpl { 795 class AnalysisCommandOutputImpl extends CommandOutputImpl {
753 // An error line has 8 fields that look like: 796 // An error line has 8 fields that look like:
754 // ERROR|COMPILER|MISSING_SOURCE|file:/tmp/t.dart|15|1|24|Missing source. 797 // ERROR|COMPILER|MISSING_SOURCE|file:/tmp/t.dart|15|1|24|Missing source.
755 final int ERROR_LEVEL = 0; 798 final int ERROR_LEVEL = 0;
756 final int ERROR_TYPE = 1; 799 final int ERROR_TYPE = 1;
757 final int FORMATTED_ERROR = 7; 800 final int FORMATTED_ERROR = 7;
758 801
(...skipping 529 matching lines...) Expand 10 before | Expand all | Expand 10 after
1288 List<EventListener> _eventListener; 1331 List<EventListener> _eventListener;
1289 1332
1290 // For dartc/selenium batch processing we keep a list of batch processes. 1333 // For dartc/selenium batch processing we keep a list of batch processes.
1291 Map<String, List<BatchRunnerProcess>> _batchProcesses; 1334 Map<String, List<BatchRunnerProcess>> _batchProcesses;
1292 1335
1293 // Cache information about test cases per test suite. For multiple 1336 // Cache information about test cases per test suite. For multiple
1294 // configurations there is no need to repeatedly search the file 1337 // configurations there is no need to repeatedly search the file
1295 // system, generate tests, and search test files for options. 1338 // system, generate tests, and search test files for options.
1296 Map<String, List<TestInformation>> _testCache; 1339 Map<String, List<TestInformation>> _testCache;
1297 1340
1341 Map<String, BrowserTestRunner> _browserTestRunners;
1342
1298 /** 1343 /**
1299 * String indicating the browser used to run the tests. Empty if no browser 1344 * String indicating the browser used to run the tests. Empty if no browser
1300 * used. 1345 * used.
1301 */ 1346 */
1302 String browserUsed = ''; 1347 String browserUsed = '';
1303 1348
1304 /** 1349 /**
1305 * Process running the selenium server .jar (only used for Safari and Opera 1350 * Process running the selenium server .jar (only used for Safari and Opera
1306 * tests.) 1351 * tests.)
1307 */ 1352 */
(...skipping 10 matching lines...) Expand all
1318 DateTime startTime, 1363 DateTime startTime,
1319 testSuites, 1364 testSuites,
1320 this._eventListener, 1365 this._eventListener,
1321 this._allDone, 1366 this._allDone,
1322 [bool verbose = false, 1367 [bool verbose = false,
1323 bool listTests = false]) 1368 bool listTests = false])
1324 : _verbose = verbose, 1369 : _verbose = verbose,
1325 _listTests = listTests, 1370 _listTests = listTests,
1326 _tests = new Queue<TestCase>(), 1371 _tests = new Queue<TestCase>(),
1327 _batchProcesses = new Map<String, List<BatchRunnerProcess>>(), 1372 _batchProcesses = new Map<String, List<BatchRunnerProcess>>(),
1328 _testCache = new Map<String, List<TestInformation>>() { 1373 _testCache = new Map<String, List<TestInformation>>(),
1374 _browserTestRunners = new Map<String, BrowserTestRunner>(){
kustermann 2013/05/13 16:00:00 space before {
ricow1 2013/05/14 07:20:58 Done.
1329 _runTests(testSuites); 1375 _runTests(testSuites);
1330 } 1376 }
1331 1377
1332 /** 1378 /**
1333 * Perform any cleanup needed once all tests in a TestSuite have completed 1379 * Perform any cleanup needed once all tests in a TestSuite have completed
1334 * and notify our progress indicator that we are done. 1380 * and notify our progress indicator that we are done.
1335 */ 1381 */
1336 void _cleanupAndMarkDone() { 1382 void _cleanupAndMarkDone() {
1337 _allDone(); 1383 _allDone();
1338 if (browserUsed != '' && _seleniumServer != null) { 1384 if (browserUsed != '' && _seleniumServer != null) {
1339 _seleniumServer.kill(); 1385 _seleniumServer.kill();
1340 } 1386 }
1341 eventAllTestsDone(); 1387 eventAllTestsDone();
1342 } 1388 }
1343 1389
1344 void _checkDone() { 1390 void _checkDone() {
1345 if (_allTestsWereEnqueued && _tests.isEmpty && _numProcesses == 0) { 1391 if (_allTestsWereEnqueued && _tests.isEmpty && _numProcesses == 0) {
1346 _terminateBatchRunners().then((_) => _cleanupAndMarkDone()); 1392 _terminateBatchRunners().then((_) {
1393 _terminateBrowserRunners().then((_) => _cleanupAndMarkDone());
1394 });
1347 } 1395 }
1348 } 1396 }
1349 1397
1350 void _runTests(List<TestSuite> testSuites) { 1398 void _runTests(List<TestSuite> testSuites) {
1351 // FIXME: For some reason we cannot call this method on all test suites 1399 // FIXME: For some reason we cannot call this method on all test suites
1352 // in parallel. 1400 // in parallel.
1353 // If we do, not all tests get enqueued (if --arch=all was specified, 1401 // If we do, not all tests get enqueued (if --arch=all was specified,
1354 // we don't get twice the number of tests [tested on -rvm -cnone]) 1402 // we don't get twice the number of tests [tested on -rvm -cnone])
1355 // Issue: 7927 1403 // Issue: 7927
1356 Iterator<TestSuite> iterator = testSuites.iterator; 1404 Iterator<TestSuite> iterator = testSuites.iterator;
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
1499 var futures = new List(); 1547 var futures = new List();
1500 for (var runners in _batchProcesses.values) { 1548 for (var runners in _batchProcesses.values) {
1501 for (var runner in runners) { 1549 for (var runner in runners) {
1502 futures.add(runner.terminate()); 1550 futures.add(runner.terminate());
1503 } 1551 }
1504 } 1552 }
1505 // Change to Future.wait when updating binaries. 1553 // Change to Future.wait when updating binaries.
1506 return Future.wait(futures); 1554 return Future.wait(futures);
1507 } 1555 }
1508 1556
1557 Future _terminateBrowserRunners() {
1558 var futures = [];
1559 for (BrowserTestRunner runner in _browserTestRunners.values) {
1560 futures.add(runner.terminate());
1561 }
1562 return Future.wait(futures);
1563 }
1564
1509 BatchRunnerProcess _getBatchRunner(TestCase test) { 1565 BatchRunnerProcess _getBatchRunner(TestCase test) {
1510 // Start batch processes if needed 1566 // Start batch processes if needed
1511 var compiler = test.configuration['compiler']; 1567 var compiler = test.configuration['compiler'];
1512 var runners = _batchProcesses[compiler]; 1568 var runners = _batchProcesses[compiler];
1513 if (runners == null) { 1569 if (runners == null) {
1514 runners = new List<BatchRunnerProcess>(_maxProcesses); 1570 runners = new List<BatchRunnerProcess>(_maxProcesses);
1515 for (int i = 0; i < _maxProcesses; i++) { 1571 for (int i = 0; i < _maxProcesses; i++) {
1516 runners[i] = new BatchRunnerProcess(test); 1572 runners[i] = new BatchRunnerProcess(test);
1517 } 1573 }
1518 _batchProcesses[compiler] = runners; 1574 _batchProcesses[compiler] = runners;
1519 } 1575 }
1520 1576
1521 for (var runner in runners) { 1577 for (var runner in runners) {
1522 if (!runner.active) return runner; 1578 if (!runner.active) return runner;
1523 } 1579 }
1524 throw new Exception('Unable to find inactive batch runner.'); 1580 throw new Exception('Unable to find inactive batch runner.');
1525 } 1581 }
1526 1582
1583 Future<BrowserTestRunner> getBrowserTestRunner(TestCase test) {
kustermann 2013/05/13 16:00:00 You could make it private as well.
ricow1 2013/05/14 07:20:58 Done.
1584 var runtime = test.configuration['runtime'];
1585 if (_browserTestRunners[runtime] == null) {
1586 var testRunner = new BrowserTestRunner(runtime, 4);
kustermann 2013/05/13 16:00:00 Make a constant.
ricow1 2013/05/14 07:20:58 Done.
1587 _browserTestRunners[runtime] = testRunner;
1588 return testRunner.start().then((started) {
1589 if (started) {
1590 return testRunner;
1591 }
1592 return null;
kustermann 2013/05/13 16:00:00 If we're unable to start the browser then we'll ge
ricow1 2013/05/14 07:20:58 Done.
ricow1 2013/05/14 07:20:58 Done
1593 });
1594 }
1595 return new Future.immediate(_browserTestRunners[runtime]);
1596 }
1597
1598 void startBrowserControllerTest(var test) {
kustermann 2013/05/13 16:00:00 private?
ricow1 2013/05/14 07:20:58 Done.
1599 // Get the url.
1600 // TODO(ricow): This is not needed when we have eliminated selenium.
1601 var nextCommandIndex = test.commandOutputs.keys.length;
1602 var url = test.commands[nextCommandIndex].toString().split("--out=")[1];
1603 // Remove trailing "
1604 url = url.split('"')[0];
1605 var callback = (var output) {
1606 new CommandOutput.fromCase(test,
1607 test.commands[nextCommandIndex],
1608 0,
1609 false,
1610 output == "TIMEOUT",
1611 output.codeUnits,
kustermann 2013/05/13 16:00:00 Please use encodeUtf8String or so. This is suppose
ricow1 2013/05/14 07:20:58 Done.
1612 [],
1613 const Duration(seconds: 1),
1614 false);
1615 test.completedHandler(test);
1616 };
1617 BrowserTest browserTest = new BrowserTest(url,
1618 callback,
1619 test.timeout);
kustermann 2013/05/13 16:00:00 Does this fit on one line?
ricow1 2013/05/14 07:20:58 Yes
1620 getBrowserTestRunner(test).then((testRunner) {
1621 testRunner.queueTest(browserTest);
1622 });
1623 }
1624
1527 void _tryRunTest() { 1625 void _tryRunTest() {
1528 _checkDone(); 1626 _checkDone();
1627 // We oversubscribe the cpus with the started browsers when we use our
kustermann 2013/05/13 16:00:00 This comment seems to be wrong.
1628 // internal browser driver. We use a simpler queue based setup.
1629 // TODO(ricow): remove most of the hacked selenium code below when
1630 // we have eliminated the need.
1631
1529 if (_numProcesses < _maxProcesses && !_tests.isEmpty) { 1632 if (_numProcesses < _maxProcesses && !_tests.isEmpty) {
1530 TestCase test = _tests.removeFirst(); 1633 TestCase test = _tests.removeFirst();
1531 if (_listTests) { 1634 if (_listTests) {
1532 var fields = [test.displayName, 1635 var fields = [test.displayName,
1533 test.expectedOutcomes.join(','), 1636 test.expectedOutcomes.join(','),
1534 test.isNegative.toString()]; 1637 test.isNegative.toString()];
1535 fields.addAll(test.commands.last.arguments); 1638 fields.addAll(test.commands.last.arguments);
1536 print(fields.join('\t')); 1639 print(fields.join('\t'));
1537 return; 1640 return;
1538 } 1641 }
1539 if (test.usesWebDriver && _needsSelenium && !_isSeleniumAvailable || (test 1642 if (test.usesWebDriver && _needsSelenium && !_isSeleniumAvailable ||
1540 is BrowserTestCase && test.waitingForOtherTest)) { 1643 (test is BrowserTestCase && test.waitingForOtherTest)) {
1541 // The test is not yet ready to run. Put the test back in 1644 // The test is not yet ready to run. Put the test back in
1542 // the queue. Avoid spin-polling by using a timeout. 1645 // the queue. Avoid spin-polling by using a timeout.
1543 _tests.add(test); 1646 _tests.add(test);
1544 new Timer(new Duration(milliseconds: 100), 1647 new Timer(new Duration(milliseconds: 100),
1545 _tryRunTest); // Don't lose a process. 1648 _tryRunTest); // Don't lose a process.
1546 return; 1649 return;
1547 } 1650 }
1548 // Before running any commands, we print out all commands if '--verbose' 1651 // Before running any commands, we print out all commands if '--verbose'
1549 // was specified. 1652 // was specified.
1550 if (_verbose && test.commandOutputs.length == 0) { 1653 if (_verbose && test.commandOutputs.length == 0) {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1591 _numProcesses--; 1694 _numProcesses--;
1592 if (isBrowserCommand) { 1695 if (isBrowserCommand) {
1593 _numBrowserProcesses--; 1696 _numBrowserProcesses--;
1594 } 1697 }
1595 eventFinishedTestCase(test_arg); 1698 eventFinishedTestCase(test_arg);
1596 if (test_arg is BrowserTestCase) test_arg.notifyObservers(); 1699 if (test_arg is BrowserTestCase) test_arg.notifyObservers();
1597 oldCallback(test_arg); 1700 oldCallback(test_arg);
1598 _tryRunTest(); 1701 _tryRunTest();
1599 }; 1702 };
1600 test.completedHandler = testCompleted; 1703 test.completedHandler = testCompleted;
1601 _getBatchRunner(test).startTest(test); 1704
1705 if (test.usesBrowserControler) {
kustermann 2013/05/13 16:00:00 I'm not sure if we should make this an attribute o
ricow1 2013/05/14 07:20:58 It is part of the configuration, see how we return
1706 startBrowserControllerTest(test);
1707 } else {
1708 _getBatchRunner(test).startTest(test);
1709 }
1602 } else { 1710 } else {
1603 // Once we've actually failed a test, technically, we wouldn't need to 1711 // Once we've actually failed a test, technically, we wouldn't need to
1604 // bother retrying any subsequent tests since the bot is already red. 1712 // bother retrying any subsequent tests since the bot is already red.
1605 // However, we continue to retry tests until we have actually failed 1713 // However, we continue to retry tests until we have actually failed
1606 // four tests (arbitrarily chosen) for more debugable output, so that 1714 // four tests (arbitrarily chosen) for more debugable output, so that
1607 // the developer doesn't waste his or her time trying to fix a bunch of 1715 // the developer doesn't waste his or her time trying to fix a bunch of
1608 // tests that appear to be broken but were actually just flakes that 1716 // tests that appear to be broken but were actually just flakes that
1609 // didn't get retried because there had already been one failure. 1717 // didn't get retried because there had already been one failure.
1610 bool allowRetry = _MAX_FAILED_NO_RETRY > _numFailedTests; 1718 bool allowRetry = _MAX_FAILED_NO_RETRY > _numFailedTests;
1611 runNextCommandWithRetries(test, allowRetry).then((TestCase testCase) { 1719 runNextCommandWithRetries(test, allowRetry).then((TestCase testCase) {
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
1737 } 1845 }
1738 } 1846 }
1739 1847
1740 void eventAllTestsDone() { 1848 void eventAllTestsDone() {
1741 for (var listener in _eventListener) { 1849 for (var listener in _eventListener) {
1742 listener.allDone(); 1850 listener.allDone();
1743 } 1851 }
1744 } 1852 }
1745 } 1853 }
1746 1854
OLDNEW
« tools/testing/dart/browser_controler.dart ('K') | « tools/testing/dart/test_options.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698