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

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_controller.dart";
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;
31 32
33 const int NUMBER_OF_BROWSERCONTROLLER_BROWSERS = 4;
34
32 typedef void TestCaseEvent(TestCase testCase); 35 typedef void TestCaseEvent(TestCase testCase);
33 typedef void ExitCodeEvent(int exitCode); 36 typedef void ExitCodeEvent(int exitCode);
34 typedef void EnqueueMoreWork(ProcessQueue queue); 37 typedef void EnqueueMoreWork(ProcessQueue queue);
35 38
36 // Some IO tests use these variables and get confused if the host environment 39 // Some IO tests use these variables and get confused if the host environment
37 // variables are inherited so they are excluded. 40 // variables are inherited so they are excluded.
38 const List<String> EXCLUDED_ENVIRONMENT_VARIABLES = 41 const List<String> EXCLUDED_ENVIRONMENT_VARIABLES =
39 const ['http_proxy', 'https_proxy', 'no_proxy', 42 const ['http_proxy', 'https_proxy', 'no_proxy',
40 'HTTP_PROXY', 'HTTPS_PROXY', 'NO_PROXY']; 43 'HTTP_PROXY', 'HTTPS_PROXY', 'NO_PROXY'];
41 44
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after
341 final arch = configuration['arch']; 344 final arch = configuration['arch'];
342 final checked = configuration['checked'] ? '-checked' : ''; 345 final checked = configuration['checked'] ? '-checked' : '';
343 return "$compiler-$runtime$checked ${mode}_$arch"; 346 return "$compiler-$runtime$checked ${mode}_$arch";
344 } 347 }
345 348
346 List<String> get batchRunnerArguments => ['-batch']; 349 List<String> get batchRunnerArguments => ['-batch'];
347 List<String> get batchTestArguments => commands.last.arguments; 350 List<String> get batchTestArguments => commands.last.arguments;
348 351
349 bool get usesWebDriver => TestUtils.usesWebDriver(configuration['runtime']); 352 bool get usesWebDriver => TestUtils.usesWebDriver(configuration['runtime']);
350 353
354 bool get usesBrowserController => configuration['use_browser_controller'];
355
351 void completed() { completedHandler(this); } 356 void completed() { completedHandler(this); }
352 357
353 bool get isFlaky { 358 bool get isFlaky {
354 if (expectedOutcomes.contains(SKIP)) { 359 if (expectedOutcomes.contains(SKIP)) {
355 return false; 360 return false;
356 } 361 }
357 362
358 var flags = new Set.from(expectedOutcomes); 363 var flags = new Set.from(expectedOutcomes);
359 flags..remove(TIMEOUT) 364 flags..remove(TIMEOUT)
360 ..remove(SLOW); 365 ..remove(SLOW);
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
519 } 524 }
520 factory CommandOutputImpl.fromCase(TestCase testCase, 525 factory CommandOutputImpl.fromCase(TestCase testCase,
521 Command command, 526 Command command,
522 int exitCode, 527 int exitCode,
523 bool incomplete, 528 bool incomplete,
524 bool timedOut, 529 bool timedOut,
525 List<int> stdout, 530 List<int> stdout,
526 List<int> stderr, 531 List<int> stderr,
527 Duration time, 532 Duration time,
528 bool compilationSkipped) { 533 bool compilationSkipped) {
529 if (testCase is BrowserTestCase) { 534 if (testCase.usesBrowserController) {
535 return new HTMLBrowserCommandOutputImpl(testCase,
536 command,
537 exitCode,
538 incomplete,
539 timedOut,
540 stdout,
541 stderr,
542 time,
543 compilationSkipped);
544 } else if (testCase is BrowserTestCase) {
530 return new BrowserCommandOutputImpl(testCase, 545 return new BrowserCommandOutputImpl(testCase,
531 command, 546 command,
532 exitCode, 547 exitCode,
533 incomplete, 548 incomplete,
534 timedOut, 549 timedOut,
535 stdout, 550 stdout,
536 stderr, 551 stderr,
537 time, 552 time,
538 compilationSkipped); 553 compilationSkipped);
539 } else if (testCase.configuration['analyzer']) { 554 } else if (testCase.configuration['analyzer']) {
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
739 return (exitCode != 0 && !hasCrashed); 754 return (exitCode != 0 && !hasCrashed);
740 } 755 }
741 } 756 }
742 break; 757 break;
743 } 758 }
744 } 759 }
745 return true; 760 return true;
746 } 761 }
747 } 762 }
748 763
764 class HTMLBrowserCommandOutputImpl extends BrowserCommandOutputImpl {
765 HTMLBrowserCommandOutputImpl(
766 testCase,
767 command,
768 exitCode,
769 incomplete,
770 timedOut,
771 stdout,
772 stderr,
773 time,
774 compilationSkipped) :
775 super(testCase,
776 command,
777 exitCode,
778 incomplete,
779 timedOut,
780 stdout,
781 stderr,
782 time,
783 compilationSkipped);
784
785 bool get _browserTestFailure {
786 // We should not need to convert back and forward.
787 var output = decodeUtf8(super.stdout);
788 if (output.contains("FAIL")) return true;
789 return !output.contains("PASS");
790 }
791 }
792
793
749 // The static analyzer does not actually execute code, so 794 // The static analyzer does not actually execute code, so
750 // the criteria for success now depend on the text sent 795 // the criteria for success now depend on the text sent
751 // to stderr. 796 // to stderr.
752 class AnalysisCommandOutputImpl extends CommandOutputImpl { 797 class AnalysisCommandOutputImpl extends CommandOutputImpl {
753 // An error line has 8 fields that look like: 798 // An error line has 8 fields that look like:
754 // ERROR|COMPILER|MISSING_SOURCE|file:/tmp/t.dart|15|1|24|Missing source. 799 // ERROR|COMPILER|MISSING_SOURCE|file:/tmp/t.dart|15|1|24|Missing source.
755 final int ERROR_LEVEL = 0; 800 final int ERROR_LEVEL = 0;
756 final int ERROR_TYPE = 1; 801 final int ERROR_TYPE = 1;
757 final int FORMATTED_ERROR = 7; 802 final int FORMATTED_ERROR = 7;
758 803
(...skipping 529 matching lines...) Expand 10 before | Expand all | Expand 10 after
1288 List<EventListener> _eventListener; 1333 List<EventListener> _eventListener;
1289 1334
1290 // For dartc/selenium batch processing we keep a list of batch processes. 1335 // For dartc/selenium batch processing we keep a list of batch processes.
1291 Map<String, List<BatchRunnerProcess>> _batchProcesses; 1336 Map<String, List<BatchRunnerProcess>> _batchProcesses;
1292 1337
1293 // Cache information about test cases per test suite. For multiple 1338 // Cache information about test cases per test suite. For multiple
1294 // configurations there is no need to repeatedly search the file 1339 // configurations there is no need to repeatedly search the file
1295 // system, generate tests, and search test files for options. 1340 // system, generate tests, and search test files for options.
1296 Map<String, List<TestInformation>> _testCache; 1341 Map<String, List<TestInformation>> _testCache;
1297 1342
1343 Map<String, BrowserTestRunner> _browserTestRunners;
1344
1298 /** 1345 /**
1299 * String indicating the browser used to run the tests. Empty if no browser 1346 * String indicating the browser used to run the tests. Empty if no browser
1300 * used. 1347 * used.
1301 */ 1348 */
1302 String browserUsed = ''; 1349 String browserUsed = '';
1303 1350
1304 /** 1351 /**
1305 * Process running the selenium server .jar (only used for Safari and Opera 1352 * Process running the selenium server .jar (only used for Safari and Opera
1306 * tests.) 1353 * tests.)
1307 */ 1354 */
(...skipping 10 matching lines...) Expand all
1318 DateTime startTime, 1365 DateTime startTime,
1319 testSuites, 1366 testSuites,
1320 this._eventListener, 1367 this._eventListener,
1321 this._allDone, 1368 this._allDone,
1322 [bool verbose = false, 1369 [bool verbose = false,
1323 bool listTests = false]) 1370 bool listTests = false])
1324 : _verbose = verbose, 1371 : _verbose = verbose,
1325 _listTests = listTests, 1372 _listTests = listTests,
1326 _tests = new Queue<TestCase>(), 1373 _tests = new Queue<TestCase>(),
1327 _batchProcesses = new Map<String, List<BatchRunnerProcess>>(), 1374 _batchProcesses = new Map<String, List<BatchRunnerProcess>>(),
1328 _testCache = new Map<String, List<TestInformation>>() { 1375 _testCache = new Map<String, List<TestInformation>>(),
1376 _browserTestRunners = new Map<String, BrowserTestRunner>() {
1329 _runTests(testSuites); 1377 _runTests(testSuites);
1330 } 1378 }
1331 1379
1332 /** 1380 /**
1333 * Perform any cleanup needed once all tests in a TestSuite have completed 1381 * Perform any cleanup needed once all tests in a TestSuite have completed
1334 * and notify our progress indicator that we are done. 1382 * and notify our progress indicator that we are done.
1335 */ 1383 */
1336 void _cleanupAndMarkDone() { 1384 void _cleanupAndMarkDone() {
1337 _allDone(); 1385 _allDone();
1338 if (browserUsed != '' && _seleniumServer != null) { 1386 if (browserUsed != '' && _seleniumServer != null) {
1339 _seleniumServer.kill(); 1387 _seleniumServer.kill();
1340 } 1388 }
1341 eventAllTestsDone(); 1389 eventAllTestsDone();
1342 } 1390 }
1343 1391
1344 void _checkDone() { 1392 void _checkDone() {
1345 if (_allTestsWereEnqueued && _tests.isEmpty && _numProcesses == 0) { 1393 if (_allTestsWereEnqueued && _tests.isEmpty && _numProcesses == 0) {
1346 _terminateBatchRunners().then((_) => _cleanupAndMarkDone()); 1394 _terminateBatchRunners().then((_) {
1395 _terminateBrowserRunners().then((_) => _cleanupAndMarkDone());
1396 });
1347 } 1397 }
1348 } 1398 }
1349 1399
1350 void _runTests(List<TestSuite> testSuites) { 1400 void _runTests(List<TestSuite> testSuites) {
1351 // FIXME: For some reason we cannot call this method on all test suites 1401 // FIXME: For some reason we cannot call this method on all test suites
1352 // in parallel. 1402 // in parallel.
1353 // If we do, not all tests get enqueued (if --arch=all was specified, 1403 // 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]) 1404 // we don't get twice the number of tests [tested on -rvm -cnone])
1355 // Issue: 7927 1405 // Issue: 7927
1356 Iterator<TestSuite> iterator = testSuites.iterator; 1406 Iterator<TestSuite> iterator = testSuites.iterator;
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
1499 var futures = new List(); 1549 var futures = new List();
1500 for (var runners in _batchProcesses.values) { 1550 for (var runners in _batchProcesses.values) {
1501 for (var runner in runners) { 1551 for (var runner in runners) {
1502 futures.add(runner.terminate()); 1552 futures.add(runner.terminate());
1503 } 1553 }
1504 } 1554 }
1505 // Change to Future.wait when updating binaries. 1555 // Change to Future.wait when updating binaries.
1506 return Future.wait(futures); 1556 return Future.wait(futures);
1507 } 1557 }
1508 1558
1559 Future _terminateBrowserRunners() {
1560 var futures = [];
1561 for (BrowserTestRunner runner in _browserTestRunners.values) {
1562 futures.add(runner.terminate());
1563 }
1564 return Future.wait(futures);
1565 }
1566
1509 BatchRunnerProcess _getBatchRunner(TestCase test) { 1567 BatchRunnerProcess _getBatchRunner(TestCase test) {
1510 // Start batch processes if needed 1568 // Start batch processes if needed
1511 var compiler = test.configuration['compiler']; 1569 var compiler = test.configuration['compiler'];
1512 var runners = _batchProcesses[compiler]; 1570 var runners = _batchProcesses[compiler];
1513 if (runners == null) { 1571 if (runners == null) {
1514 runners = new List<BatchRunnerProcess>(_maxProcesses); 1572 runners = new List<BatchRunnerProcess>(_maxProcesses);
1515 for (int i = 0; i < _maxProcesses; i++) { 1573 for (int i = 0; i < _maxProcesses; i++) {
1516 runners[i] = new BatchRunnerProcess(test); 1574 runners[i] = new BatchRunnerProcess(test);
1517 } 1575 }
1518 _batchProcesses[compiler] = runners; 1576 _batchProcesses[compiler] = runners;
1519 } 1577 }
1520 1578
1521 for (var runner in runners) { 1579 for (var runner in runners) {
1522 if (!runner.active) return runner; 1580 if (!runner.active) return runner;
1523 } 1581 }
1524 throw new Exception('Unable to find inactive batch runner.'); 1582 throw new Exception('Unable to find inactive batch runner.');
1525 } 1583 }
1526 1584
1585 Future<BrowserTestRunner> _getBrowserTestRunner(TestCase test) {
1586 var runtime = test.configuration['runtime'];
1587 if (_browserTestRunners[runtime] == null) {
1588 var testRunner =
1589 new BrowserTestRunner(runtime, NUMBER_OF_BROWSERCONTROLLER_BROWSERS);
1590 _browserTestRunners[runtime] = testRunner;
1591 return testRunner.start().then((started) {
1592 if (started) {
1593 return testRunner;
1594 }
1595 print("Issue starting browser test runner");
1596 exit(1);
1597 });
1598 }
1599 return new Future.immediate(_browserTestRunners[runtime]);
1600 }
1601
1602 void _startBrowserControllerTest(var test) {
1603 // Get the url.
1604 // TODO(ricow): This is not needed when we have eliminated selenium.
1605 var nextCommandIndex = test.commandOutputs.keys.length;
1606 var url = test.commands[nextCommandIndex].toString().split("--out=")[1];
1607 // Remove trailing "
1608 url = url.split('"')[0];
1609 var callback = (var output) {
1610 new CommandOutput.fromCase(test,
1611 test.commands[nextCommandIndex],
1612 0,
1613 false,
1614 output == "TIMEOUT",
1615 encodeUtf8(output),
1616 [],
1617 const Duration(seconds: 1),
1618 false);
1619 test.completedHandler(test);
1620 };
1621 BrowserTest browserTest = new BrowserTest(url, callback, test.timeout);
1622 _getBrowserTestRunner(test).then((testRunner) {
1623 testRunner.queueTest(browserTest);
1624 });
1625 }
1626
1527 void _tryRunTest() { 1627 void _tryRunTest() {
1528 _checkDone(); 1628 _checkDone();
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.usesBrowserController) {
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_controller.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