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