| Index: tools/testing/dart/test_progress.dart
|
| diff --git a/tools/testing/dart/test_progress.dart b/tools/testing/dart/test_progress.dart
|
| deleted file mode 100644
|
| index bb31d29f6922a3ecf3b37fb303bb8f945c9f42aa..0000000000000000000000000000000000000000
|
| --- a/tools/testing/dart/test_progress.dart
|
| +++ /dev/null
|
| @@ -1,670 +0,0 @@
|
| -// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -
|
| -library test_progress;
|
| -
|
| -import "dart:async";
|
| -import "dart:io";
|
| -import "dart:io" as io;
|
| -import "dart:convert" show JSON;
|
| -import "path.dart";
|
| -import "status_file_parser.dart";
|
| -import "test_runner.dart";
|
| -import "test_suite.dart";
|
| -import "utils.dart";
|
| -
|
| -String _pad(String s, int length) {
|
| - StringBuffer buffer = new StringBuffer();
|
| - for (int i = s.length; i < length; i++) {
|
| - buffer.write(' ');
|
| - }
|
| - buffer.write(s);
|
| - return buffer.toString();
|
| -}
|
| -
|
| -String _padTime(int time) {
|
| - if (time == 0) {
|
| - return '00';
|
| - } else if (time < 10) {
|
| - return '0$time';
|
| - } else {
|
| - return '$time';
|
| - }
|
| -}
|
| -
|
| -String _timeString(Duration d) {
|
| - var min = d.inMinutes;
|
| - var sec = d.inSeconds % 60;
|
| - return '${_padTime(min)}:${_padTime(sec)}';
|
| -}
|
| -
|
| -class Formatter {
|
| - const Formatter();
|
| - String passed(msg) => msg;
|
| - String failed(msg) => msg;
|
| -}
|
| -
|
| -class ColorFormatter extends Formatter {
|
| - static int BOLD = 1;
|
| - static int GREEN = 32;
|
| - static int RED = 31;
|
| - static int NONE = 0;
|
| - static String ESCAPE = decodeUtf8([27]);
|
| -
|
| - String passed(String msg) => _color(msg, GREEN);
|
| - String failed(String msg) => _color(msg, RED);
|
| -
|
| - static String _color(String msg, int color) {
|
| - return "$ESCAPE[${color}m$msg$ESCAPE[0m";
|
| - }
|
| -}
|
| -
|
| -
|
| -List<String> _buildFailureOutput(TestCase test,
|
| - [Formatter formatter = const Formatter()]) {
|
| -
|
| - List<String> getLinesWithoutCarriageReturn(List<int> output) {
|
| - return decodeUtf8(output).replaceAll('\r\n', '\n')
|
| - .replaceAll('\r', '\n').split('\n');
|
| - }
|
| -
|
| - List<String> output = new List<String>();
|
| - output.add('');
|
| - output.add(formatter.failed('FAILED: ${test.configurationString}'
|
| - ' ${test.displayName}'));
|
| - StringBuffer expected = new StringBuffer();
|
| - expected.write('Expected: ');
|
| - for (var expectation in test.expectedOutcomes) {
|
| - expected.write('$expectation ');
|
| - }
|
| - output.add(expected.toString());
|
| - output.add('Actual: ${test.result}');
|
| - if (!test.lastCommandOutput.hasTimedOut) {
|
| - if (test.commandOutputs.length != test.commands.length
|
| - && !test.expectCompileError) {
|
| - output.add('Unexpected compile-time error.');
|
| - } else {
|
| - if (test.expectCompileError) {
|
| - output.add('Compile-time error expected.');
|
| - }
|
| - if (test.hasRuntimeError) {
|
| - output.add('Runtime error expected.');
|
| - }
|
| - if (test.configuration['checked'] && test.isNegativeIfChecked) {
|
| - output.add('Dynamic type error expected.');
|
| - }
|
| - }
|
| - }
|
| - for (var i = 0; i < test.commands.length; i++) {
|
| - var command = test.commands[i];
|
| - var commandOutput = test.commandOutputs[command];
|
| - if (commandOutput != null) {
|
| - output.add("CommandOutput[${command.displayName}]:");
|
| - if (!commandOutput.diagnostics.isEmpty) {
|
| - String prefix = 'diagnostics:';
|
| - for (var s in commandOutput.diagnostics) {
|
| - output.add('$prefix ${s}');
|
| - prefix = ' ';
|
| - }
|
| - }
|
| - if (!commandOutput.stdout.isEmpty) {
|
| - output.add('');
|
| - output.add('stdout:');
|
| - output.addAll(getLinesWithoutCarriageReturn(commandOutput.stdout));
|
| - }
|
| - if (!commandOutput.stderr.isEmpty) {
|
| - output.add('');
|
| - output.add('stderr:');
|
| - output.addAll(getLinesWithoutCarriageReturn(commandOutput.stderr));
|
| - }
|
| - }
|
| - }
|
| - if (test is BrowserTestCase) {
|
| - // Additional command for rerunning the steps locally after the fact.
|
| - var command =
|
| - test.configuration["_servers_"].httpServerCommandline();
|
| - output.add('');
|
| - output.add('To retest, run: $command');
|
| - }
|
| - for (var i = 0; i < test.commands.length; i++) {
|
| - var command = test.commands[i];
|
| - var commandOutput = test.commandOutputs[command];
|
| - output.add('');
|
| - output.add('Command[${command.displayName}]: $command');
|
| - if (commandOutput != null) {
|
| - output.add('Took ${commandOutput.time}');
|
| - } else {
|
| - output.add('Did not run');
|
| - }
|
| - }
|
| -
|
| - var arguments = ['python', 'tools/test.py'];
|
| - arguments.addAll(test.configuration['_reproducing_arguments_']);
|
| - arguments.add(test.displayName);
|
| - var testPyCommandline = arguments.map(escapeCommandLineArgument).join(' ');
|
| -
|
| - output.add('');
|
| - output.add('Short reproduction command (experimental):');
|
| - output.add(" $testPyCommandline");
|
| - return output;
|
| -}
|
| -
|
| -String _buildSummaryEnd(int failedTests) {
|
| - if (failedTests == 0) {
|
| - return '\n===\n=== All tests succeeded\n===\n';
|
| - } else {
|
| - var pluralSuffix = failedTests != 1 ? 's' : '';
|
| - return '\n===\n=== ${failedTests} test$pluralSuffix failed\n===\n';
|
| - }
|
| -}
|
| -
|
| -
|
| -class EventListener {
|
| - void testAdded() { }
|
| - void done(TestCase test) { }
|
| - void allTestsKnown() { }
|
| - void allDone() { }
|
| -}
|
| -
|
| -class ExitCodeSetter extends EventListener {
|
| - void done(TestCase test) {
|
| - if (test.unexpectedOutput) {
|
| - io.exitCode = 1;
|
| - }
|
| - }
|
| -}
|
| -
|
| -class FlakyLogWriter extends EventListener {
|
| - void done(TestCase test) {
|
| - if (test.isFlaky && test.result != Expectation.PASS) {
|
| - var buf = new StringBuffer();
|
| - for (var l in _buildFailureOutput(test)) {
|
| - buf.write("$l\n");
|
| - }
|
| - _appendToFlakyFile(buf.toString());
|
| - }
|
| - }
|
| -
|
| - void _appendToFlakyFile(String msg) {
|
| - var file = new File(TestUtils.flakyFileName());
|
| - var fd = file.openSync(mode: FileMode.APPEND);
|
| - fd.writeStringSync(msg);
|
| - fd.closeSync();
|
| - }
|
| -}
|
| -
|
| -class TestOutcomeLogWriter extends EventListener {
|
| - /*
|
| - * The ".test-outcome.log" file contains one line for every executed test.
|
| - * Such a line is an encoded JSON data structure of the following form:
|
| - * The durations are double values in milliseconds.
|
| - *
|
| - * {
|
| - * name: 'co19/LibTest/math/x',
|
| - * configuration: {
|
| - * mode : 'release',
|
| - * compiler : 'dart2js',
|
| - * ....
|
| - * },
|
| - * test_result: {
|
| - * outcome: 'RuntimeError',
|
| - * expected_outcomes: ['Pass', 'Fail'],
|
| - * duration: 2600.64,
|
| - * command_results: [
|
| - * {
|
| - * name: 'dart2js',
|
| - * duration: 2400.44,
|
| - * },
|
| - * {
|
| - * name: 'ff',
|
| - * duration: 200.2,
|
| - * },
|
| - * ],
|
| - * }
|
| - * },
|
| - */
|
| -
|
| - static final INTERESTED_CONFIGURATION_PARAMETERS =
|
| - ['mode', 'arch', 'compiler', 'runtime', 'checked', 'host_checked',
|
| - 'minified', 'csp', 'system', 'vm_options', 'use_sdk',
|
| - 'use_repository_packages', 'use_public_packages', 'builder_tag'];
|
| -
|
| - IOSink _sink;
|
| -
|
| - void done(TestCase test) {
|
| - var name = test.displayName;
|
| - var configuration = {};
|
| - for (var key in INTERESTED_CONFIGURATION_PARAMETERS) {
|
| - configuration[key] = test.configuration[key];
|
| - }
|
| - var outcome = '${test.lastCommandOutput.result(test)}';
|
| - var expectations =
|
| - test.expectedOutcomes.map((expectation) => "$expectation").toList();
|
| -
|
| - var commandResults = [];
|
| - double totalDuration = 0.0;
|
| - for (var command in test.commands) {
|
| - var output = test.commandOutputs[command];
|
| - if (output != null) {
|
| - double duration = output.time.inMicroseconds/1000.0;
|
| - totalDuration += duration;
|
| - commandResults.add({
|
| - 'name': command.displayName,
|
| - 'duration': duration,
|
| - });
|
| - }
|
| - }
|
| - _writeTestOutcomeRecord({
|
| - 'name' : name,
|
| - 'configuration' : configuration,
|
| - 'test_result' : {
|
| - 'outcome' : outcome,
|
| - 'expected_outcomes' : expectations,
|
| - 'duration' : totalDuration,
|
| - 'command_results' : commandResults,
|
| - },
|
| - });
|
| - }
|
| -
|
| - void allDone() {
|
| - if (_sink != null) _sink.close();
|
| - }
|
| -
|
| - void _writeTestOutcomeRecord(Map record) {
|
| - if (_sink == null) {
|
| - _sink = new File(TestUtils.testOutcomeFileName())
|
| - .openWrite(mode: FileMode.APPEND);
|
| - }
|
| - _sink.write("${JSON.encode(record)}\n");
|
| - }
|
| -}
|
| -
|
| -
|
| -class UnexpectedCrashDumpArchiver extends EventListener {
|
| - void done(TestCase test) {
|
| - if (test.unexpectedOutput && test.result == Expectation.CRASH) {
|
| - var name = "core.dart.${test.lastCommandOutput.pid}";
|
| - var file = new File(name);
|
| - if (file.existsSync()) {
|
| - // Find the binary - we assume this is the first part of the command
|
| - var binName = test.lastCommandExecuted.toString().split(' ').first;
|
| - var binFile = new File(binName);
|
| - var binBaseName = new Path(binName).filename;
|
| - if (binFile.existsSync()) {
|
| - var tmpPath = new Path(Directory.systemTemp.path);
|
| - var dir = new Path(TestUtils.mkdirRecursive(tmpPath,
|
| - new Path('coredump_${test.lastCommandOutput.pid}')).path);
|
| - TestUtils.copyFile(new Path(name), dir.append(name));
|
| - TestUtils.copyFile(new Path(binName), dir.append(binBaseName));
|
| - print("\nCopied core dump and binary for unexpected crash to: "
|
| - "$dir");
|
| - }
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| -class SummaryPrinter extends EventListener {
|
| - void allTestsKnown() {
|
| - if (SummaryReport.total > 0) {
|
| - SummaryReport.printReport();
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| -class TimingPrinter extends EventListener {
|
| - final _command2testCases = new Map<Command, List<TestCase>>();
|
| - final _commandOutputs = new Set<CommandOutput>();
|
| - DateTime _startTime;
|
| -
|
| - TimingPrinter(this._startTime);
|
| -
|
| - void done(TestCase testCase) {
|
| - for (var commandOutput in testCase.commandOutputs.values) {
|
| - var command = commandOutput.command;
|
| - _commandOutputs.add(commandOutput);
|
| - _command2testCases.putIfAbsent(command, () => <TestCase>[]);
|
| - _command2testCases[command].add(testCase);
|
| - }
|
| - }
|
| -
|
| - void allDone() {
|
| - Duration d = (new DateTime.now()).difference(_startTime);
|
| - print('\n--- Total time: ${_timeString(d)} ---');
|
| - var outputs = _commandOutputs.toList();
|
| - outputs.sort((a, b) {
|
| - return b.time.inMilliseconds - a.time.inMilliseconds;
|
| - });
|
| - for (int i = 0; i < 20 && i < outputs.length; i++) {
|
| - var commandOutput = outputs[i];
|
| - var command = commandOutput.command;
|
| - var testCases = _command2testCases[command];
|
| -
|
| - var testCasesDescription = testCases.map((testCase) {
|
| - return "${testCase.configurationString}/${testCase.displayName}";
|
| - }).join(', ');
|
| -
|
| - print('${commandOutput.time} - '
|
| - '${command.displayName} - '
|
| - '$testCasesDescription');
|
| - }
|
| - }
|
| -}
|
| -
|
| -class StatusFileUpdatePrinter extends EventListener {
|
| - var statusToConfigs = new Map<String, List<String>>();
|
| - var _failureSummary = <String>[];
|
| -
|
| - void done(TestCase test) {
|
| - if (test.unexpectedOutput) {
|
| - _printFailureOutput(test);
|
| - }
|
| - }
|
| -
|
| - void allDone() {
|
| - _printFailureSummary();
|
| - }
|
| -
|
| -
|
| - void _printFailureOutput(TestCase test) {
|
| - String status = '${test.displayName}: ${test.result}';
|
| - List<String> configs =
|
| - statusToConfigs.putIfAbsent(status, () => <String>[]);
|
| - configs.add(test.configurationString);
|
| - if (test.lastCommandOutput.hasTimedOut) {
|
| - print('\n${test.displayName} timed out on ${test.configurationString}');
|
| - }
|
| - }
|
| -
|
| - String _extractRuntime(String configuration) {
|
| - // Extract runtime from a configuration, for example,
|
| - // 'none-vm-checked release_ia32'.
|
| - List<String> runtime = configuration.split(' ')[0].split('-');
|
| - return '${runtime[0]}-${runtime[1]}';
|
| - }
|
| -
|
| - void _printFailureSummary() {
|
| - var groupedStatuses = new Map<String, List<String>>();
|
| - statusToConfigs.forEach((String status, List<String> configs) {
|
| - var runtimeToConfiguration = new Map<String, List<String>>();
|
| - for (String config in configs) {
|
| - String runtime = _extractRuntime(config);
|
| - var runtimeConfigs =
|
| - runtimeToConfiguration.putIfAbsent(runtime, () => <String>[]);
|
| - runtimeConfigs.add(config);
|
| - }
|
| - runtimeToConfiguration.forEach((String runtime,
|
| - List<String> runtimeConfigs) {
|
| - runtimeConfigs.sort((a, b) => a.compareTo(b));
|
| - List<String> statuses =
|
| - groupedStatuses.putIfAbsent('$runtime: $runtimeConfigs',
|
| - () => <String>[]);
|
| - statuses.add(status);
|
| - });
|
| - });
|
| -
|
| - print('\n\nNecessary status file updates:');
|
| - groupedStatuses.forEach((String config, List<String> statuses) {
|
| - print('');
|
| - print('$config:');
|
| - statuses.sort((a, b) => a.compareTo(b));
|
| - for (String status in statuses) {
|
| - print(' $status');
|
| - }
|
| - });
|
| - }
|
| -}
|
| -
|
| -class SkippedCompilationsPrinter extends EventListener {
|
| - int _skippedCompilations = 0;
|
| -
|
| - void done(TestCase test) {
|
| - for (var commandOutput in test.commandOutputs.values) {
|
| - if (commandOutput.compilationSkipped)
|
| - _skippedCompilations++;
|
| - }
|
| - }
|
| -
|
| - void allDone() {
|
| - if (_skippedCompilations > 0) {
|
| - print('\n$_skippedCompilations compilations were skipped because '
|
| - 'the previous output was already up to date\n');
|
| - }
|
| - }
|
| -}
|
| -
|
| -class LeftOverTempDirPrinter extends EventListener {
|
| - final MIN_NUMBER_OF_TEMP_DIRS = 50;
|
| -
|
| - static RegExp _getTemporaryDirectoryRegexp() {
|
| - // These are the patterns of temporary directory names created by
|
| - // 'Directory.systemTemp.createTemp()' on linux/macos and windows.
|
| - if (['macos', 'linux'].contains(Platform.operatingSystem)) {
|
| - return new RegExp(r'^temp_dir1_......$');
|
| - } else {
|
| - return new RegExp(r'tempdir-........-....-....-....-............$');
|
| - }
|
| - }
|
| -
|
| - static Stream<Directory> getLeftOverTemporaryDirectories() {
|
| - var regExp = _getTemporaryDirectoryRegexp();
|
| - return Directory.systemTemp.list().where(
|
| - (FileSystemEntity fse) {
|
| - if (fse is Directory) {
|
| - if (regExp.hasMatch(new Path(fse.path).filename)) {
|
| - return true;
|
| - }
|
| - }
|
| - return false;
|
| - });
|
| - }
|
| -
|
| - void allDone() {
|
| - getLeftOverTemporaryDirectories().length.then((int count) {
|
| - if (count > MIN_NUMBER_OF_TEMP_DIRS) {
|
| - DebugLogger.warning("There are ${count} directories "
|
| - "in the system tempdir "
|
| - "('${Directory.systemTemp.path}')! "
|
| - "Maybe left over directories?\n");
|
| - }
|
| - }).catchError((error) {
|
| - DebugLogger.warning("Could not list temp directories, got: $error");
|
| - });
|
| - }
|
| -}
|
| -
|
| -class LineProgressIndicator extends EventListener {
|
| - void done(TestCase test) {
|
| - var status = 'pass';
|
| - if (test.unexpectedOutput) {
|
| - status = 'fail';
|
| - }
|
| - print('Done ${test.configurationString} ${test.displayName}: $status');
|
| - }
|
| -}
|
| -
|
| -
|
| -class TestFailurePrinter extends EventListener {
|
| - bool _printSummary;
|
| - var _formatter;
|
| - var _failureSummary = <String>[];
|
| - var _failedTests= 0;
|
| -
|
| - TestFailurePrinter(this._printSummary,
|
| - [this._formatter = const Formatter()]);
|
| -
|
| - void done(TestCase test) {
|
| - if (test.unexpectedOutput) {
|
| - _failedTests++;
|
| - var lines = _buildFailureOutput(test, _formatter);
|
| - for (var line in lines) {
|
| - print(line);
|
| - }
|
| - print('');
|
| - if (_printSummary) {
|
| - _failureSummary.addAll(lines);
|
| - _failureSummary.add('');
|
| - }
|
| - }
|
| - }
|
| -
|
| - void allDone() {
|
| - if (_printSummary) {
|
| - if (!_failureSummary.isEmpty) {
|
| - print('\n=== Failure summary:\n');
|
| - for (String line in _failureSummary) {
|
| - print(line);
|
| - }
|
| - print('');
|
| -
|
| - print(_buildSummaryEnd(_failedTests));
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -class ProgressIndicator extends EventListener {
|
| - ProgressIndicator(this._startTime);
|
| -
|
| -
|
| - void testAdded() { _foundTests++; }
|
| -
|
| - void done(TestCase test) {
|
| - if (test.unexpectedOutput) {
|
| - _failedTests++;
|
| - } else {
|
| - _passedTests++;
|
| - }
|
| - _printDoneProgress(test);
|
| - }
|
| -
|
| - void allTestsKnown() {
|
| - _allTestsKnown = true;
|
| - }
|
| -
|
| - void _printDoneProgress(TestCase test) {}
|
| -
|
| - int _completedTests() => _passedTests + _failedTests;
|
| -
|
| - int _foundTests = 0;
|
| - int _passedTests = 0;
|
| - int _failedTests = 0;
|
| - bool _allTestsKnown = false;
|
| - DateTime _startTime;
|
| -}
|
| -
|
| -abstract class CompactIndicator extends ProgressIndicator {
|
| - CompactIndicator(DateTime startTime)
|
| - : super(startTime);
|
| -
|
| - void allDone() {
|
| - if (_failedTests > 0) {
|
| - // We may have printed many failure logs, so reprint the summary data.
|
| - _printProgress();
|
| - }
|
| - print('');
|
| - }
|
| -
|
| - void _printDoneProgress(TestCase test) => _printProgress();
|
| -
|
| - void _printProgress();
|
| -}
|
| -
|
| -
|
| -class CompactProgressIndicator extends CompactIndicator {
|
| - Formatter _formatter;
|
| -
|
| - CompactProgressIndicator(DateTime startTime, this._formatter)
|
| - : super(startTime);
|
| -
|
| - void _printProgress() {
|
| - var percent = ((_completedTests() / _foundTests) * 100).toInt().toString();
|
| - var progressPadded = _pad(_allTestsKnown ? percent : '--', 3);
|
| - var passedPadded = _pad(_passedTests.toString(), 5);
|
| - var failedPadded = _pad(_failedTests.toString(), 5);
|
| - Duration d = (new DateTime.now()).difference(_startTime);
|
| - var progressLine =
|
| - '\r[${_timeString(d)} | $progressPadded% | '
|
| - '+${_formatter.passed(passedPadded)} | '
|
| - '-${_formatter.failed(failedPadded)}]';
|
| - stdout.write(progressLine);
|
| - }
|
| -}
|
| -
|
| -
|
| -class VerboseProgressIndicator extends ProgressIndicator {
|
| - VerboseProgressIndicator(DateTime startTime)
|
| - : super(startTime);
|
| -
|
| - void _printDoneProgress(TestCase test) {
|
| - var status = 'pass';
|
| - if (test.unexpectedOutput) {
|
| - status = 'fail';
|
| - }
|
| - print('Done ${test.configurationString} ${test.displayName}: $status');
|
| - }
|
| -}
|
| -
|
| -
|
| -class BuildbotProgressIndicator extends ProgressIndicator {
|
| - static String stepName;
|
| - var _failureSummary = <String>[];
|
| -
|
| - BuildbotProgressIndicator(DateTime startTime) : super(startTime);
|
| -
|
| - void done(TestCase test) {
|
| - super.done(test);
|
| - if (test.unexpectedOutput) {
|
| - _failureSummary.addAll(_buildFailureOutput(test));
|
| - }
|
| - }
|
| -
|
| - void _printDoneProgress(TestCase test) {
|
| - var status = 'pass';
|
| - if (test.unexpectedOutput) {
|
| - status = 'fail';
|
| - }
|
| - var percent = ((_completedTests() / _foundTests) * 100).toInt().toString();
|
| - print('Done ${test.configurationString} ${test.displayName}: $status');
|
| - print('@@@STEP_CLEAR@@@');
|
| - print('@@@STEP_TEXT@ $percent% +$_passedTests -$_failedTests @@@');
|
| - }
|
| -
|
| - void allDone() {
|
| - if (!_failureSummary.isEmpty) {
|
| - print('@@@STEP_FAILURE@@@');
|
| - if (stepName != null) {
|
| - print('@@@BUILD_STEP $stepName failures@@@');
|
| - }
|
| - for (String line in _failureSummary) {
|
| - print(line);
|
| - }
|
| - print('');
|
| - }
|
| - print(_buildSummaryEnd(_failedTests));
|
| - }
|
| -}
|
| -
|
| -
|
| -EventListener progressIndicatorFromName(String name,
|
| - DateTime startTime,
|
| - Formatter formatter) {
|
| - switch (name) {
|
| - case 'compact':
|
| - return new CompactProgressIndicator(startTime, formatter);
|
| - case 'line':
|
| - return new LineProgressIndicator();
|
| - case 'verbose':
|
| - return new VerboseProgressIndicator(startTime);
|
| - case 'status':
|
| - return new ProgressIndicator(startTime);
|
| - case 'buildbot':
|
| - return new BuildbotProgressIndicator(startTime);
|
| - default:
|
| - assert(false);
|
| - break;
|
| - }
|
| -}
|
|
|