| 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 1299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1310 * Because multiple configurations may be run on each test suite, the | 1310 * Because multiple configurations may be run on each test suite, the |
| 1311 * ProcessQueue contains a cache in which a test suite may record information | 1311 * ProcessQueue contains a cache in which a test suite may record information |
| 1312 * about its list of tests, and may retrieve that information when it is called | 1312 * about its list of tests, and may retrieve that information when it is called |
| 1313 * upon to enqueue its tests again. | 1313 * upon to enqueue its tests again. |
| 1314 */ | 1314 */ |
| 1315 class ProcessQueue { | 1315 class ProcessQueue { |
| 1316 int _numProcesses = 0; | 1316 int _numProcesses = 0; |
| 1317 int _maxProcesses; | 1317 int _maxProcesses; |
| 1318 int _numBrowserProcesses = 0; | 1318 int _numBrowserProcesses = 0; |
| 1319 int _maxBrowserProcesses; | 1319 int _maxBrowserProcesses; |
| 1320 int _numFailedTests = 0; |
| 1320 bool _allTestsWereEnqueued = false; | 1321 bool _allTestsWereEnqueued = false; |
| 1321 | 1322 |
| 1322 /** The number of tests we allow to actually fail before we stop retrying. */ | 1323 /** The number of tests we allow to actually fail before we stop retrying. */ |
| 1323 int _MAX_FAILED_NO_RETRY = 4; | 1324 int _MAX_FAILED_NO_RETRY = 4; |
| 1324 bool _verbose; | 1325 bool _verbose; |
| 1325 bool _listTests; | 1326 bool _listTests; |
| 1326 Function _allDone; | 1327 Function _allDone; |
| 1327 Queue<TestCase> _tests; | 1328 Queue<TestCase> _tests; |
| 1328 ProgressIndicator _progress; | 1329 List<EventListener> _eventListener; |
| 1329 | 1330 |
| 1330 // For dartc/selenium batch processing we keep a list of batch processes. | 1331 // For dartc/selenium batch processing we keep a list of batch processes. |
| 1331 Map<String, List<BatchRunnerProcess>> _batchProcesses; | 1332 Map<String, List<BatchRunnerProcess>> _batchProcesses; |
| 1332 | 1333 |
| 1333 // Cache information about test cases per test suite. For multiple | 1334 // Cache information about test cases per test suite. For multiple |
| 1334 // configurations there is no need to repeatedly search the file | 1335 // configurations there is no need to repeatedly search the file |
| 1335 // system, generate tests, and search test files for options. | 1336 // system, generate tests, and search test files for options. |
| 1336 Map<String, List<TestInformation>> _testCache; | 1337 Map<String, List<TestInformation>> _testCache; |
| 1337 | 1338 |
| 1338 /** | 1339 /** |
| 1339 * String indicating the browser used to run the tests. Empty if no browser | 1340 * String indicating the browser used to run the tests. Empty if no browser |
| 1340 * used. | 1341 * used. |
| 1341 */ | 1342 */ |
| 1342 String browserUsed = ''; | 1343 String browserUsed = ''; |
| 1343 | 1344 |
| 1344 /** | 1345 /** |
| 1345 * Process running the selenium server .jar (only used for Safari and Opera | 1346 * Process running the selenium server .jar (only used for Safari and Opera |
| 1346 * tests.) | 1347 * tests.) |
| 1347 */ | 1348 */ |
| 1348 io.Process _seleniumServer = null; | 1349 io.Process _seleniumServer = null; |
| 1349 | 1350 |
| 1350 /** True if we are in the process of starting the server. */ | 1351 /** True if we are in the process of starting the server. */ |
| 1351 bool _startingServer = false; | 1352 bool _startingServer = false; |
| 1352 | 1353 |
| 1353 /** True if we find that there is already a selenium jar running. */ | 1354 /** True if we find that there is already a selenium jar running. */ |
| 1354 bool _seleniumAlreadyRunning = false; | 1355 bool _seleniumAlreadyRunning = false; |
| 1355 | 1356 |
| 1356 ProcessQueue(this._maxProcesses, | 1357 ProcessQueue(this._maxProcesses, |
| 1357 this._maxBrowserProcesses, | 1358 this._maxBrowserProcesses, |
| 1358 String progress, | |
| 1359 Date startTime, | 1359 Date startTime, |
| 1360 bool printTiming, | |
| 1361 testSuites, | 1360 testSuites, |
| 1361 this._eventListener, |
| 1362 this._allDone, | 1362 this._allDone, |
| 1363 [bool verbose = false, | 1363 [bool verbose = false, |
| 1364 bool listTests = false]) | 1364 bool listTests = false]) |
| 1365 : _verbose = verbose, | 1365 : _verbose = verbose, |
| 1366 _listTests = listTests, | 1366 _listTests = listTests, |
| 1367 _tests = new Queue<TestCase>(), | 1367 _tests = new Queue<TestCase>(), |
| 1368 _progress = new ProgressIndicator.fromName(progress, | |
| 1369 startTime, | |
| 1370 printTiming), | |
| 1371 _batchProcesses = new Map<String, List<BatchRunnerProcess>>(), | 1368 _batchProcesses = new Map<String, List<BatchRunnerProcess>>(), |
| 1372 _testCache = new Map<String, List<TestInformation>>() { | 1369 _testCache = new Map<String, List<TestInformation>>() { |
| 1373 _runTests(testSuites); | 1370 _runTests(testSuites); |
| 1374 } | 1371 } |
| 1375 | 1372 |
| 1376 /** | 1373 /** |
| 1377 * Perform any cleanup needed once all tests in a TestSuite have completed | 1374 * Perform any cleanup needed once all tests in a TestSuite have completed |
| 1378 * and notify our progress indicator that we are done. | 1375 * and notify our progress indicator that we are done. |
| 1379 */ | 1376 */ |
| 1380 void _cleanupAndMarkDone() { | 1377 void _cleanupAndMarkDone() { |
| 1381 _allDone(); | 1378 _allDone(); |
| 1382 if (browserUsed != '' && _seleniumServer != null) { | 1379 if (browserUsed != '' && _seleniumServer != null) { |
| 1383 _seleniumServer.kill(); | 1380 _seleniumServer.kill(); |
| 1384 } | 1381 } |
| 1385 _progress.allDone(); | 1382 eventAllTestsDone(); |
| 1386 } | 1383 } |
| 1387 | 1384 |
| 1388 void _checkDone() { | 1385 void _checkDone() { |
| 1389 if (_allTestsWereEnqueued && _tests.isEmpty && _numProcesses == 0) { | 1386 if (_allTestsWereEnqueued && _tests.isEmpty && _numProcesses == 0) { |
| 1390 _terminateBatchRunners().then((_) => _cleanupAndMarkDone()); | 1387 _terminateBatchRunners().then((_) => _cleanupAndMarkDone()); |
| 1391 } | 1388 } |
| 1392 } | 1389 } |
| 1393 | 1390 |
| 1394 void _runTests(List<TestSuite> testSuites) { | 1391 void _runTests(List<TestSuite> testSuites) { |
| 1395 // FIXME: For some reason we cannot call this method on all test suites | 1392 // FIXME: For some reason we cannot call this method on all test suites |
| 1396 // in parallel. | 1393 // in parallel. |
| 1397 // If we do, not all tests get enqueued (if --arch=all was specified, | 1394 // If we do, not all tests get enqueued (if --arch=all was specified, |
| 1398 // we don't get twice the number of tests [tested on -rvm -cnone]) | 1395 // we don't get twice the number of tests [tested on -rvm -cnone]) |
| 1399 // Issue: 7927 | 1396 // Issue: 7927 |
| 1400 Iterator<TestSuite> iterator = testSuites.iterator; | 1397 Iterator<TestSuite> iterator = testSuites.iterator; |
| 1401 void enqueueNextSuite() { | 1398 void enqueueNextSuite() { |
| 1402 if (!iterator.moveNext()) { | 1399 if (!iterator.moveNext()) { |
| 1403 _allTestsWereEnqueued = true; | 1400 _allTestsWereEnqueued = true; |
| 1404 _progress.allTestsKnown(); | 1401 eventAllTestsKnown(); |
| 1405 _checkDone(); | 1402 _checkDone(); |
| 1406 } else { | 1403 } else { |
| 1407 iterator.current.forEachTest(_runTest, _testCache, enqueueNextSuite); | 1404 iterator.current.forEachTest(_runTest, _testCache, enqueueNextSuite); |
| 1408 } | 1405 } |
| 1409 } | 1406 } |
| 1410 enqueueNextSuite(); | 1407 enqueueNextSuite(); |
| 1411 } | 1408 } |
| 1412 | 1409 |
| 1413 /** | 1410 /** |
| 1414 * True if we are using a browser + platform combination that needs the | 1411 * True if we are using a browser + platform combination that needs the |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1471 return true; | 1468 return true; |
| 1472 }); | 1469 }); |
| 1473 } | 1470 } |
| 1474 } | 1471 } |
| 1475 | 1472 |
| 1476 void _runTest(TestCase test) { | 1473 void _runTest(TestCase test) { |
| 1477 if (test.usesWebDriver) { | 1474 if (test.usesWebDriver) { |
| 1478 browserUsed = test.configuration['browser']; | 1475 browserUsed = test.configuration['browser']; |
| 1479 if (_needsSelenium) _ensureSeleniumServerRunning(); | 1476 if (_needsSelenium) _ensureSeleniumServerRunning(); |
| 1480 } | 1477 } |
| 1481 _progress.testAdded(); | 1478 eventTestAdded(test); |
| 1482 _tests.add(test); | 1479 _tests.add(test); |
| 1483 _tryRunTest(); | 1480 _tryRunTest(); |
| 1484 } | 1481 } |
| 1485 | 1482 |
| 1486 /** | 1483 /** |
| 1487 * Monitor the output of the Selenium server, to know when we are ready to | 1484 * Monitor the output of the Selenium server, to know when we are ready to |
| 1488 * begin running tests. | 1485 * begin running tests. |
| 1489 * source: Output(Stream) from the Java server. | 1486 * source: Output(Stream) from the Java server. |
| 1490 */ | 1487 */ |
| 1491 VoidFunction makeSeleniumServerHandler(io.StringInputStream source) { | 1488 VoidFunction makeSeleniumServerHandler(io.StringInputStream source) { |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1619 var isLastCommand = | 1616 var isLastCommand = |
| 1620 ((test.commands.length-1) == test.commandOutputs.length); | 1617 ((test.commands.length-1) == test.commandOutputs.length); |
| 1621 var isBrowserCommand = isLastCommand && (test is BrowserTestCase); | 1618 var isBrowserCommand = isLastCommand && (test is BrowserTestCase); |
| 1622 if (isBrowserCommand && _numBrowserProcesses == _maxBrowserProcesses) { | 1619 if (isBrowserCommand && _numBrowserProcesses == _maxBrowserProcesses) { |
| 1623 // If there is no free browser runner, put it back into the queue. | 1620 // If there is no free browser runner, put it back into the queue. |
| 1624 _tests.add(test); | 1621 _tests.add(test); |
| 1625 new Timer(100, (_) => _tryRunTest()); // Don't lose a process. | 1622 new Timer(100, (_) => _tryRunTest()); // Don't lose a process. |
| 1626 return; | 1623 return; |
| 1627 } | 1624 } |
| 1628 | 1625 |
| 1629 _progress.start(test); | 1626 eventStartTestCase(test); |
| 1630 | 1627 |
| 1631 // Dartc and browser test commands can be run by a [BatchRunnerProcess] | 1628 // Dartc and browser test commands can be run by a [BatchRunnerProcess] |
| 1632 var nextCommandIndex = test.commandOutputs.keys.length; | 1629 var nextCommandIndex = test.commandOutputs.keys.length; |
| 1633 var numberOfCommands = test.commands.length; | 1630 var numberOfCommands = test.commands.length; |
| 1634 var useBatchRunnerForDartc = test.configuration['compiler'] == 'dartc' && | 1631 var useBatchRunnerForDartc = test.configuration['compiler'] == 'dartc' && |
| 1635 test.displayName != 'dartc/junit_tests'; | 1632 test.displayName != 'dartc/junit_tests'; |
| 1636 var isWebdriverCommand = nextCommandIndex == (numberOfCommands - 1) && | 1633 var isWebdriverCommand = nextCommandIndex == (numberOfCommands - 1) && |
| 1637 test.usesWebDriver && | 1634 test.usesWebDriver && |
| 1638 !test.configuration['noBatch']; | 1635 !test.configuration['noBatch']; |
| 1639 if (useBatchRunnerForDartc || isWebdriverCommand) { | 1636 if (useBatchRunnerForDartc || isWebdriverCommand) { |
| 1640 TestCaseEvent oldCallback = test.completedHandler; | 1637 TestCaseEvent oldCallback = test.completedHandler; |
| 1641 void testCompleted(TestCase test_arg) { | 1638 void testCompleted(TestCase test_arg) { |
| 1642 _numProcesses--; | 1639 _numProcesses--; |
| 1643 if (isBrowserCommand) { | 1640 if (isBrowserCommand) { |
| 1644 _numBrowserProcesses--; | 1641 _numBrowserProcesses--; |
| 1645 } | 1642 } |
| 1646 _progress.done(test_arg); | 1643 eventFinishedTestCase(test_arg); |
| 1647 if (test_arg is BrowserTestCase) test_arg.notifyObservers(); | 1644 if (test_arg is BrowserTestCase) test_arg.notifyObservers(); |
| 1648 oldCallback(test_arg); | 1645 oldCallback(test_arg); |
| 1649 _tryRunTest(); | 1646 _tryRunTest(); |
| 1650 }; | 1647 }; |
| 1651 test.completedHandler = testCompleted; | 1648 test.completedHandler = testCompleted; |
| 1652 _getBatchRunner(test).startTest(test); | 1649 _getBatchRunner(test).startTest(test); |
| 1653 } else { | 1650 } else { |
| 1654 // Once we've actually failed a test, technically, we wouldn't need to | 1651 // Once we've actually failed a test, technically, we wouldn't need to |
| 1655 // bother retrying any subsequent tests since the bot is already red. | 1652 // bother retrying any subsequent tests since the bot is already red. |
| 1656 // However, we continue to retry tests until we have actually failed | 1653 // However, we continue to retry tests until we have actually failed |
| 1657 // four tests (arbitrarily chosen) for more debugable output, so that | 1654 // four tests (arbitrarily chosen) for more debugable output, so that |
| 1658 // the developer doesn't waste his or her time trying to fix a bunch of | 1655 // the developer doesn't waste his or her time trying to fix a bunch of |
| 1659 // tests that appear to be broken but were actually just flakes that | 1656 // tests that appear to be broken but were actually just flakes that |
| 1660 // didn't get retried because there had already been one failure. | 1657 // didn't get retried because there had already been one failure. |
| 1661 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; | 1658 bool allowRetry = _MAX_FAILED_NO_RETRY > _numFailedTests; |
| 1662 runNextCommandWithRetries(test, allowRetry).then((TestCase testCase) { | 1659 runNextCommandWithRetries(test, allowRetry).then((TestCase testCase) { |
| 1663 _numProcesses--; | 1660 _numProcesses--; |
| 1664 if (isBrowserCommand) { | 1661 if (isBrowserCommand) { |
| 1665 _numBrowserProcesses--; | 1662 _numBrowserProcesses--; |
| 1666 } | 1663 } |
| 1667 if (isTestCaseFinished(testCase)) { | 1664 if (isTestCaseFinished(testCase)) { |
| 1668 testCase.completed(); | 1665 testCase.completed(); |
| 1669 _progress.done(testCase); | 1666 eventFinishedTestCase(testCase); |
| 1670 if (testCase is BrowserTestCase) testCase.notifyObservers(); | 1667 if (testCase is BrowserTestCase) testCase.notifyObservers(); |
| 1671 } else { | 1668 } else { |
| 1672 _tests.addFirst(testCase); | 1669 _tests.addFirst(testCase); |
| 1673 } | 1670 } |
| 1674 _tryRunTest(); | 1671 _tryRunTest(); |
| 1675 }); | 1672 }); |
| 1676 } | 1673 } |
| 1677 | 1674 |
| 1678 _numProcesses++; | 1675 _numProcesses++; |
| 1679 if (isBrowserCommand) { | 1676 if (isBrowserCommand) { |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1751 runCommand(); | 1748 runCommand(); |
| 1752 } else { | 1749 } else { |
| 1753 completer.complete(testCase); | 1750 completer.complete(testCase); |
| 1754 } | 1751 } |
| 1755 }); | 1752 }); |
| 1756 } | 1753 } |
| 1757 runCommand(); | 1754 runCommand(); |
| 1758 | 1755 |
| 1759 return completer.future; | 1756 return completer.future; |
| 1760 } | 1757 } |
| 1758 |
| 1759 void eventStartTestCase(TestCase testCase) { |
| 1760 for (var listener in _eventListener) { |
| 1761 listener.start(testCase); |
| 1762 } |
| 1763 } |
| 1764 |
| 1765 void eventFinishedTestCase(TestCase testCase) { |
| 1766 if (testCase.lastCommandOutput.unexpectedOutput) { |
| 1767 _numFailedTests++; |
| 1768 } |
| 1769 for (var listener in _eventListener) { |
| 1770 listener.done(testCase); |
| 1771 } |
| 1772 } |
| 1773 |
| 1774 void eventTestAdded(TestCase testCase) { |
| 1775 for (var listener in _eventListener) { |
| 1776 listener.testAdded(); |
| 1777 } |
| 1778 } |
| 1779 |
| 1780 void eventAllTestsKnown() { |
| 1781 for (var listener in _eventListener) { |
| 1782 listener.allTestsKnown(); |
| 1783 } |
| 1784 } |
| 1785 |
| 1786 void eventAllTestsDone() { |
| 1787 for (var listener in _eventListener) { |
| 1788 listener.allDone(); |
| 1789 } |
| 1790 } |
| 1761 } | 1791 } |
| 1762 | 1792 |
| OLD | NEW |