Chromium Code Reviews| 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 // 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |