Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 import 'dart:convert' show JSON; | 5 import 'dart:convert'; |
| 6 import 'dart:io'; | 6 import 'dart:io'; |
| 7 | 7 |
| 8 import "package:status_file/expectation.dart"; | 8 import "package:status_file/expectation.dart"; |
| 9 | 9 |
| 10 import 'command.dart'; | 10 import 'command.dart'; |
| 11 import 'command_output.dart'; | 11 import 'command_output.dart'; |
| 12 import 'configuration.dart'; | 12 import 'configuration.dart'; |
| 13 import 'path.dart'; | 13 import 'path.dart'; |
| 14 import 'summary_report.dart'; | 14 import 'summary_report.dart'; |
| 15 import 'test_runner.dart'; | 15 import 'test_runner.dart'; |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 44 String failed(String message) => _color(message, _red); | 44 String failed(String message) => _color(message, _red); |
| 45 | 45 |
| 46 static String _color(String message, int color) => | 46 static String _color(String message, int color) => |
| 47 "$_escape[${color}m$message$_escape[0m"; | 47 "$_escape[${color}m$message$_escape[0m"; |
| 48 } | 48 } |
| 49 | 49 |
| 50 class EventListener { | 50 class EventListener { |
| 51 void testAdded() {} | 51 void testAdded() {} |
| 52 void done(TestCase test) {} | 52 void done(TestCase test) {} |
| 53 void allTestsKnown() {} | 53 void allTestsKnown() {} |
| 54 void allDone() {} | 54 void allDone(Configuration configuration) {} |
| 55 } | 55 } |
| 56 | 56 |
| 57 class ExitCodeSetter extends EventListener { | 57 class ExitCodeSetter extends EventListener { |
| 58 void done(TestCase test) { | 58 void done(TestCase test) { |
| 59 if (test.unexpectedOutput) { | 59 if (test.unexpectedOutput) { |
| 60 exitCode = 1; | 60 exitCode = 1; |
| 61 } | 61 } |
| 62 } | 62 } |
| 63 } | 63 } |
| 64 | 64 |
| 65 class IgnoredTestMonitor extends EventListener { | 65 class IgnoredTestMonitor extends EventListener { |
| 66 static final int maxIgnored = 10; | 66 static final int maxIgnored = 10; |
| 67 | 67 |
| 68 int countIgnored = 0; | 68 int countIgnored = 0; |
| 69 | 69 |
| 70 void done(TestCase test) { | 70 void done(TestCase test) { |
| 71 if (test.lastCommandOutput.result(test) == Expectation.ignore) { | 71 if (test.lastCommandOutput.result(test) == Expectation.ignore) { |
| 72 countIgnored++; | 72 countIgnored++; |
| 73 if (countIgnored > maxIgnored) { | 73 if (countIgnored > maxIgnored) { |
| 74 print("/nMore than $maxIgnored tests were ignored due to flakes in"); | 74 print("/nMore than $maxIgnored tests were ignored due to flakes in"); |
| 75 print("the test infrastructure. Notify whesse@google.com."); | 75 print("the test infrastructure. Notify whesse@google.com."); |
| 76 print("Output of the last ignored test was:"); | 76 print("Output of the last ignored test was:"); |
| 77 print(_buildFailureOutput(test)); | 77 print(_buildFailureOutput(test)); |
| 78 exit(1); | 78 exit(1); |
| 79 } | 79 } |
| 80 } | 80 } |
| 81 } | 81 } |
| 82 | 82 |
| 83 void allDone() { | 83 void allDone(Configuration configuration) { |
| 84 if (countIgnored > 0) { | 84 if (countIgnored > 0) { |
| 85 print("Ignored $countIgnored tests due to flaky infrastructure"); | 85 print("Ignored $countIgnored tests due to flaky infrastructure"); |
| 86 } | 86 } |
| 87 } | 87 } |
| 88 } | 88 } |
| 89 | 89 |
| 90 class FlakyLogWriter extends EventListener { | 90 class FlakyLogWriter extends EventListener { |
| 91 void done(TestCase test) { | 91 void done(TestCase test) { |
| 92 if (test.isFlaky && test.result != Expectation.pass) { | 92 if (test.isFlaky && test.result != Expectation.pass) { |
| 93 var buf = new StringBuffer(); | 93 var buf = new StringBuffer(); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 133 * duration: 200.2, | 133 * duration: 200.2, |
| 134 * }, | 134 * }, |
| 135 * ], | 135 * ], |
| 136 * } | 136 * } |
| 137 * }, | 137 * }, |
| 138 */ | 138 */ |
| 139 IOSink _sink; | 139 IOSink _sink; |
| 140 | 140 |
| 141 void done(TestCase test) { | 141 void done(TestCase test) { |
| 142 var name = test.displayName; | 142 var name = test.displayName; |
| 143 var configuration = { | |
| 144 'mode': test.configuration.mode.name, | |
| 145 'arch': test.configuration.architecture.name, | |
| 146 'compiler': test.configuration.compiler.name, | |
| 147 'runtime': test.configuration.runtime.name, | |
| 148 'checked': test.configuration.isChecked, | |
| 149 'strong': test.configuration.isStrong, | |
| 150 'host_checked': test.configuration.isHostChecked, | |
| 151 'minified': test.configuration.isMinified, | |
| 152 'csp': test.configuration.isCsp, | |
| 153 'system': test.configuration.system.name, | |
| 154 'vm_options': test.configuration.vmOptions, | |
| 155 'use_sdk': test.configuration.useSdk, | |
| 156 'builder_tag': test.configuration.builderTag | |
| 157 }; | |
| 158 | |
| 159 var outcome = '${test.lastCommandOutput.result(test)}'; | 143 var outcome = '${test.lastCommandOutput.result(test)}'; |
| 160 var expectations = | 144 var expectations = |
| 161 test.expectedOutcomes.map((expectation) => "$expectation").toList(); | 145 test.expectedOutcomes.map((expectation) => "$expectation").toList(); |
| 162 | 146 |
| 163 var commandResults = []; | 147 var commandResults = []; |
| 164 double totalDuration = 0.0; | 148 double totalDuration = 0.0; |
| 165 for (var command in test.commands) { | 149 for (var command in test.commands) { |
| 166 var output = test.commandOutputs[command]; | 150 var output = test.commandOutputs[command]; |
| 167 if (output != null) { | 151 if (output != null) { |
| 168 double duration = output.time.inMicroseconds / 1000.0; | 152 double duration = output.time.inMicroseconds / 1000.0; |
| 169 totalDuration += duration; | 153 totalDuration += duration; |
| 170 commandResults.add({ | 154 commandResults.add({ |
| 171 'name': command.displayName, | 155 'name': command.displayName, |
| 172 'duration': duration, | 156 'duration': duration, |
| 173 }); | 157 }); |
| 174 } | 158 } |
| 175 } | 159 } |
| 176 _writeTestOutcomeRecord({ | 160 _writeTestOutcomeRecord({ |
| 177 'name': name, | 161 'name': name, |
| 178 'configuration': configuration, | 162 'configuration': test.configuration.toSummaryMap(), |
| 179 'test_result': { | 163 'test_result': { |
| 180 'outcome': outcome, | 164 'outcome': outcome, |
| 181 'expected_outcomes': expectations, | 165 'expected_outcomes': expectations, |
| 182 'duration': totalDuration, | 166 'duration': totalDuration, |
| 183 'command_results': commandResults, | 167 'command_results': commandResults, |
| 184 }, | 168 }, |
| 185 }); | 169 }); |
| 186 } | 170 } |
| 187 | 171 |
| 188 void allDone() { | 172 void allDone(Configuration configuration) { |
| 189 if (_sink != null) _sink.close(); | 173 if (_sink != null) _sink.close(); |
| 190 } | 174 } |
| 191 | 175 |
| 192 void _writeTestOutcomeRecord(Map record) { | 176 void _writeTestOutcomeRecord(Map record) { |
| 177 // TODO(mkroghj) change the location of this file | |
| 178 // to be in the debug_output_directory | |
| 179 // if the current location is not used. | |
| 193 if (_sink == null) { | 180 if (_sink == null) { |
| 194 _sink = new File(TestUtils.testOutcomeFileName) | 181 _sink = new File(TestUtils.testOutcomeFileName) |
| 195 .openWrite(mode: FileMode.APPEND); | 182 .openWrite(mode: FileMode.APPEND); |
| 196 } | 183 } |
| 197 _sink.write("${JSON.encode(record)}\n"); | 184 _sink.write("${JSON.encode(record)}\n"); |
| 198 } | 185 } |
| 199 } | 186 } |
| 200 | 187 |
| 201 class UnexpectedCrashLogger extends EventListener { | 188 class UnexpectedCrashLogger extends EventListener { |
| 202 final archivedBinaries = <String, String>{}; | 189 final archivedBinaries = <String, String>{}; |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 276 | 263 |
| 277 void done(TestCase testCase) { | 264 void done(TestCase testCase) { |
| 278 for (var commandOutput in testCase.commandOutputs.values) { | 265 for (var commandOutput in testCase.commandOutputs.values) { |
| 279 var command = commandOutput.command; | 266 var command = commandOutput.command; |
| 280 _commandOutputs.add(commandOutput); | 267 _commandOutputs.add(commandOutput); |
| 281 _command2testCases.putIfAbsent(command, () => <TestCase>[]); | 268 _command2testCases.putIfAbsent(command, () => <TestCase>[]); |
| 282 _command2testCases[command].add(testCase); | 269 _command2testCases[command].add(testCase); |
| 283 } | 270 } |
| 284 } | 271 } |
| 285 | 272 |
| 286 void allDone() { | 273 void allDone(Configuration configuration) { |
| 287 Duration d = (new DateTime.now()).difference(_startTime); | 274 Duration d = (new DateTime.now()).difference(_startTime); |
| 288 print('\n--- Total time: ${_timeString(d)} ---'); | 275 print('\n--- Total time: ${_timeString(d)} ---'); |
| 289 var outputs = _commandOutputs.toList(); | 276 var outputs = _commandOutputs.toList(); |
| 290 outputs.sort((a, b) { | 277 outputs.sort((a, b) { |
| 291 return b.time.inMilliseconds - a.time.inMilliseconds; | 278 return b.time.inMilliseconds - a.time.inMilliseconds; |
| 292 }); | 279 }); |
| 293 for (int i = 0; i < 20 && i < outputs.length; i++) { | 280 for (int i = 0; i < 20 && i < outputs.length; i++) { |
| 294 var commandOutput = outputs[i]; | 281 var commandOutput = outputs[i]; |
| 295 var command = commandOutput.command; | 282 var command = commandOutput.command; |
| 296 var testCases = _command2testCases[command]; | 283 var testCases = _command2testCases[command]; |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 309 class StatusFileUpdatePrinter extends EventListener { | 296 class StatusFileUpdatePrinter extends EventListener { |
| 310 var statusToConfigs = new Map<String, List<String>>(); | 297 var statusToConfigs = new Map<String, List<String>>(); |
| 311 var _failureSummary = <String>[]; | 298 var _failureSummary = <String>[]; |
| 312 | 299 |
| 313 void done(TestCase test) { | 300 void done(TestCase test) { |
| 314 if (test.unexpectedOutput) { | 301 if (test.unexpectedOutput) { |
| 315 _printFailureOutput(test); | 302 _printFailureOutput(test); |
| 316 } | 303 } |
| 317 } | 304 } |
| 318 | 305 |
| 319 void allDone() { | 306 void allDone(Configuration configuration) { |
| 320 _printFailureSummary(); | 307 _printFailureSummary(); |
| 321 } | 308 } |
| 322 | 309 |
| 323 void _printFailureOutput(TestCase test) { | 310 void _printFailureOutput(TestCase test) { |
| 324 String status = '${test.displayName}: ${test.result}'; | 311 String status = '${test.displayName}: ${test.result}'; |
| 325 List<String> configs = | 312 List<String> configs = |
| 326 statusToConfigs.putIfAbsent(status, () => <String>[]); | 313 statusToConfigs.putIfAbsent(status, () => <String>[]); |
| 327 configs.add(test.configurationString); | 314 configs.add(test.configurationString); |
| 328 if (test.lastCommandOutput.hasTimedOut) { | 315 if (test.lastCommandOutput.hasTimedOut) { |
| 329 print('\n${test.displayName} timed out on ${test.configurationString}'); | 316 print('\n${test.displayName} timed out on ${test.configurationString}'); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 372 | 359 |
| 373 class SkippedCompilationsPrinter extends EventListener { | 360 class SkippedCompilationsPrinter extends EventListener { |
| 374 int _skippedCompilations = 0; | 361 int _skippedCompilations = 0; |
| 375 | 362 |
| 376 void done(TestCase test) { | 363 void done(TestCase test) { |
| 377 for (var commandOutput in test.commandOutputs.values) { | 364 for (var commandOutput in test.commandOutputs.values) { |
| 378 if (commandOutput.compilationSkipped) _skippedCompilations++; | 365 if (commandOutput.compilationSkipped) _skippedCompilations++; |
| 379 } | 366 } |
| 380 } | 367 } |
| 381 | 368 |
| 382 void allDone() { | 369 void allDone(Configuration configuration) { |
| 383 if (_skippedCompilations > 0) { | 370 if (_skippedCompilations > 0) { |
| 384 print('\n$_skippedCompilations compilations were skipped because ' | 371 print('\n$_skippedCompilations compilations were skipped because ' |
| 385 'the previous output was already up to date.\n'); | 372 'the previous output was already up to date.\n'); |
| 386 } | 373 } |
| 387 } | 374 } |
| 388 } | 375 } |
| 389 | 376 |
| 390 class LineProgressIndicator extends EventListener { | 377 class LineProgressIndicator extends EventListener { |
| 391 void done(TestCase test) { | 378 void done(TestCase test) { |
| 392 var status = 'pass'; | 379 var status = 'pass'; |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 413 print(line); | 400 print(line); |
| 414 } | 401 } |
| 415 print(''); | 402 print(''); |
| 416 if (_printSummary) { | 403 if (_printSummary) { |
| 417 _failureSummary.addAll(lines); | 404 _failureSummary.addAll(lines); |
| 418 _failureSummary.add(''); | 405 _failureSummary.add(''); |
| 419 } | 406 } |
| 420 } | 407 } |
| 421 } | 408 } |
| 422 | 409 |
| 423 void allDone() { | 410 void allDone(Configuration configuration) { |
| 424 if (_printSummary) { | 411 if (_printSummary) { |
| 425 if (!_failureSummary.isEmpty) { | 412 if (!_failureSummary.isEmpty) { |
| 426 print('\n=== Failure summary:\n'); | 413 print('\n=== Failure summary:\n'); |
| 427 for (var line in _failureSummary) { | 414 for (var line in _failureSummary) { |
| 428 print(line); | 415 print(line); |
| 429 } | 416 } |
| 430 print(''); | 417 print(''); |
| 431 | 418 |
| 432 print(_buildSummaryEnd(_failedTests)); | 419 print(_buildSummaryEnd(_failedTests)); |
| 433 } | 420 } |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 480 int _foundTests = 0; | 467 int _foundTests = 0; |
| 481 int _passedTests = 0; | 468 int _passedTests = 0; |
| 482 int _failedTests = 0; | 469 int _failedTests = 0; |
| 483 bool _allTestsKnown = false; | 470 bool _allTestsKnown = false; |
| 484 DateTime _startTime; | 471 DateTime _startTime; |
| 485 } | 472 } |
| 486 | 473 |
| 487 abstract class CompactIndicator extends ProgressIndicator { | 474 abstract class CompactIndicator extends ProgressIndicator { |
| 488 CompactIndicator(DateTime startTime) : super(startTime); | 475 CompactIndicator(DateTime startTime) : super(startTime); |
| 489 | 476 |
| 490 void allDone() { | 477 void allDone(Configuration configuration) { |
| 491 if (_failedTests > 0) { | 478 if (_failedTests > 0) { |
| 492 // We may have printed many failure logs, so reprint the summary data. | 479 // We may have printed many failure logs, so reprint the summary data. |
| 493 _printProgress(); | 480 _printProgress(); |
| 494 } | 481 } |
| 495 print(''); | 482 print(''); |
| 496 } | 483 } |
| 497 | 484 |
| 498 void _printDoneProgress(TestCase test) => _printProgress(); | 485 void _printDoneProgress(TestCase test) => _printProgress(); |
| 499 | 486 |
| 500 void _printProgress(); | 487 void _printProgress(); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 548 var status = 'pass'; | 535 var status = 'pass'; |
| 549 if (test.unexpectedOutput) { | 536 if (test.unexpectedOutput) { |
| 550 status = 'fail'; | 537 status = 'fail'; |
| 551 } | 538 } |
| 552 var percent = ((_completedTests() / _foundTests) * 100).toInt().toString(); | 539 var percent = ((_completedTests() / _foundTests) * 100).toInt().toString(); |
| 553 print('Done ${test.configurationString} ${test.displayName}: $status'); | 540 print('Done ${test.configurationString} ${test.displayName}: $status'); |
| 554 print('@@@STEP_CLEAR@@@'); | 541 print('@@@STEP_CLEAR@@@'); |
| 555 print('@@@STEP_TEXT@ $percent% +$_passedTests -$_failedTests @@@'); | 542 print('@@@STEP_TEXT@ $percent% +$_passedTests -$_failedTests @@@'); |
| 556 } | 543 } |
| 557 | 544 |
| 558 void allDone() { | 545 void allDone(Configuration configuration) { |
| 559 if (!_failureSummary.isEmpty) { | 546 if (!_failureSummary.isEmpty) { |
| 560 print('@@@STEP_FAILURE@@@'); | 547 print('@@@STEP_FAILURE@@@'); |
| 561 if (stepName != null) { | 548 if (stepName != null) { |
| 562 print('@@@BUILD_STEP $stepName failures@@@'); | 549 print('@@@BUILD_STEP $stepName failures@@@'); |
| 563 } | 550 } |
| 564 for (String line in _failureSummary) { | 551 for (String line in _failureSummary) { |
| 565 print(line); | 552 print(line); |
| 566 } | 553 } |
| 567 print(''); | 554 print(''); |
| 568 } | 555 } |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 671 } | 658 } |
| 672 | 659 |
| 673 String _buildSummaryEnd(int failedTests) { | 660 String _buildSummaryEnd(int failedTests) { |
| 674 if (failedTests == 0) { | 661 if (failedTests == 0) { |
| 675 return '\n===\n=== All tests succeeded\n===\n'; | 662 return '\n===\n=== All tests succeeded\n===\n'; |
| 676 } else { | 663 } else { |
| 677 var pluralSuffix = failedTests != 1 ? 's' : ''; | 664 var pluralSuffix = failedTests != 1 ? 's' : ''; |
| 678 return '\n===\n=== ${failedTests} test$pluralSuffix failed\n===\n'; | 665 return '\n===\n=== ${failedTests} test$pluralSuffix failed\n===\n'; |
| 679 } | 666 } |
| 680 } | 667 } |
| 668 | |
| 669 class TestResultLogWriter extends EventListener { | |
| 670 Map<String, Map> _configurations = {}; | |
| 671 List<Map> _results = []; | |
| 672 | |
| 673 void done(TestCase test) { | |
| 674 // We try to find an existing configuration, so as to not duplicate this | |
| 675 // for each test. | |
| 676 var thisConf = test.configuration.toSummaryMap(); | |
|
Bill Hesse
2017/09/01 11:56:13
Make toSummaryMap return a cached object, that onl
mkroghj
2017/09/02 09:40:22
The reason why I chose it was because that is the
Bill Hesse
2017/09/04 07:49:59
Yes. It is tricky to make each configuration retu
| |
| 677 String key = _configurations.keys.firstWhere( | |
| 678 (key) => areSummaryMapsEqual(_configurations[key], thisConf), | |
| 679 orElse: () { | |
| 680 var newKey = "conf${_configurations.length + 1}"; | |
| 681 _configurations[newKey] = thisConf; | |
| 682 return newKey; | |
| 683 }); | |
| 684 _results.add({ | |
| 685 'configuration': key, | |
| 686 'name': test.displayName, | |
| 687 'commands': test.commands.map((command) { | |
|
Bill Hesse
2017/09/01 11:56:13
You could move the computation of this list outsid
mkroghj
2017/09/04 10:43:34
Done.
| |
| 688 var output = test.commandOutputs[command]; | |
| 689 if (output != null) { | |
| 690 var outputMap = { | |
| 691 'name': command.displayName, | |
| 692 'exitCode': output.exitCode, | |
| 693 'compilationSkipped': output.compilationSkipped, | |
| 694 'timeout': output.hasTimedOut, | |
| 695 'duration': output.time.inMilliseconds | |
| 696 }; | |
| 697 if (test.unexpectedOutput) { | |
|
Bill Hesse
2017/09/01 11:56:13
I thought the whole point here was that we wouldn'
mkroghj
2017/09/02 09:40:22
I think unexpectedOutput checks for isCrash or isF
| |
| 698 if (!output.stdout.isEmpty) { | |
| 699 outputMap["stdout"] = encodeStringForJson( | |
| 700 _linesWithoutCarriageReturn(output.stdout).join('\n')); | |
| 701 } | |
| 702 if (!output.stderr.isEmpty) { | |
| 703 outputMap["stderr"] = encodeStringForJson( | |
| 704 _linesWithoutCarriageReturn(output.stderr).join('\n')); | |
| 705 } | |
| 706 } | |
| 707 return outputMap; | |
| 708 } else { | |
| 709 return {'name': command.displayName}; | |
|
Bill Hesse
2017/09/01 11:56:13
Put this up after "if (output == null)", then you
mkroghj
2017/09/02 09:40:22
I don't think I have an output == null test somewh
Bill Hesse
2017/09/04 07:49:59
I meant that you should reverse the test above, pu
| |
| 710 } | |
| 711 }).toList() | |
| 712 }); | |
| 713 } | |
| 714 | |
| 715 String encodeStringForJson(String str) => BASE64.encode(UTF8.encode(str)); | |
| 716 | |
| 717 void allDone(Configuration configuration) { | |
| 718 var path = new Path(configuration.debugOutputDirectory); | |
|
Bill Hesse
2017/09/01 11:56:13
Can you use file URLs here? We don't want new cod
mkroghj
2017/09/02 09:40:22
The test-runner owns a Configuration _globalConfig
| |
| 719 path = path.append(TestUtils.testResultFileName); | |
| 720 String fullPath = path.toNativePath(); | |
| 721 var file = new File(fullPath); | |
| 722 file.createSync(recursive: true); | |
| 723 file.writeAsStringSync( | |
| 724 JSON.encode({'configurations': _configurations, 'results': _results})); | |
| 725 } | |
| 726 | |
| 727 bool areSummaryMapsEqual(Map map1, Map map2) { | |
|
Bill Hesse
2017/09/01 11:56:13
Shouldn't be needed.
| |
| 728 return map1.keys | |
| 729 .every((key) => map2.containsKey(key) && map1[key] == map2[key]); | |
| 730 } | |
| 731 } | |
| OLD | NEW |