Index: tools/testing/dart/test_runner.dart |
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart |
index 7549f073fcd6a491185934c2b39284b46afd862a..ec13aea7a1a260c2b57dc84bea0f51a1ddb3d61c 100644 |
--- a/tools/testing/dart/test_runner.dart |
+++ b/tools/testing/dart/test_runner.dart |
@@ -19,10 +19,11 @@ import 'dart:math' as math; |
import 'android.dart'; |
import 'browser_controller.dart'; |
+import 'command.dart'; |
+import 'command_output.dart'; |
import 'configuration.dart'; |
import 'dependency_graph.dart' as dgraph; |
import 'expectation.dart'; |
-import 'path.dart'; |
import 'runtime_configuration.dart'; |
import 'test_progress.dart'; |
import 'test_suite.dart'; |
@@ -52,670 +53,6 @@ const EXCLUDED_ENVIRONMENT_VARIABLES = const [ |
'NO_PROXY' |
]; |
-/** A command executed as a step in a test case. */ |
-class Command { |
- /** A descriptive name for this command. */ |
- String displayName; |
- |
- /** Number of times this command *can* be retried */ |
- int get maxNumRetries => 2; |
- |
- /** Reproduction command */ |
- String get reproductionCommand => null; |
- |
- // We compute the Command.hashCode lazily and cache it here, since it might |
- // be expensive to compute (and hashCode is called often). |
- int _cachedHashCode; |
- |
- Command._(this.displayName); |
- |
- int get hashCode { |
- if (_cachedHashCode == null) { |
- var builder = new HashCodeBuilder(); |
- _buildHashCode(builder); |
- _cachedHashCode = builder.value; |
- } |
- return _cachedHashCode; |
- } |
- |
- operator ==(Object other) => |
- identical(this, other) || |
- (runtimeType == other.runtimeType && _equal(other as Command)); |
- |
- void _buildHashCode(HashCodeBuilder builder) { |
- builder.addJson(displayName); |
- } |
- |
- bool _equal(covariant Command other) => |
- hashCode == other.hashCode && displayName == other.displayName; |
- |
- String toString() => reproductionCommand; |
- |
- Future<bool> get outputIsUpToDate => new Future.value(false); |
-} |
- |
-class ProcessCommand extends Command { |
- /** Path to the executable of this command. */ |
- String executable; |
- |
- /** Command line arguments to the executable. */ |
- List<String> arguments; |
- |
- /** Environment for the command */ |
- Map<String, String> environmentOverrides; |
- |
- /** Working directory for the command */ |
- final String workingDirectory; |
- |
- ProcessCommand._(String displayName, this.executable, this.arguments, |
- [this.environmentOverrides = null, this.workingDirectory = null]) |
- : super._(displayName) { |
- if (io.Platform.operatingSystem == 'windows') { |
- // Windows can't handle the first command if it is a .bat file or the like |
- // with the slashes going the other direction. |
- // NOTE: Issue 1306 |
- executable = executable.replaceAll('/', '\\'); |
- } |
- } |
- |
- void _buildHashCode(HashCodeBuilder builder) { |
- super._buildHashCode(builder); |
- builder.addJson(executable); |
- builder.addJson(workingDirectory); |
- builder.addJson(arguments); |
- builder.addJson(environmentOverrides); |
- } |
- |
- bool _equal(ProcessCommand other) => |
- super._equal(other) && |
- executable == other.executable && |
- deepJsonCompare(arguments, other.arguments) && |
- workingDirectory == other.workingDirectory && |
- deepJsonCompare(environmentOverrides, other.environmentOverrides); |
- |
- String get reproductionCommand { |
- var env = new StringBuffer(); |
- environmentOverrides?.forEach((key, value) => |
- (io.Platform.operatingSystem == 'windows') |
- ? env.write('set $key=${escapeCommandLineArgument(value)} & ') |
- : env.write('$key=${escapeCommandLineArgument(value)} ')); |
- var command = ([executable]..addAll(batchArguments)..addAll(arguments)) |
- .map(escapeCommandLineArgument) |
- .join(' '); |
- if (workingDirectory != null) { |
- command = "$command (working directory: $workingDirectory)"; |
- } |
- return "$env$command"; |
- } |
- |
- Future<bool> get outputIsUpToDate => new Future.value(false); |
- |
- /// Arguments that are passed to the process when starting batch mode. |
- /// |
- /// In non-batch mode, they should be passed before [arguments]. |
- List<String> get batchArguments => const []; |
-} |
- |
-class CompilationCommand extends ProcessCommand { |
- final String _outputFile; |
- final bool _neverSkipCompilation; |
- final List<Uri> _bootstrapDependencies; |
- |
- CompilationCommand._( |
- String displayName, |
- this._outputFile, |
- this._neverSkipCompilation, |
- this._bootstrapDependencies, |
- String executable, |
- List<String> arguments, |
- Map<String, String> environmentOverrides) |
- : super._(displayName, executable, arguments, environmentOverrides); |
- |
- Future<bool> get outputIsUpToDate { |
- if (_neverSkipCompilation) return new Future.value(false); |
- |
- Future<List<Uri>> readDepsFile(String path) { |
- var file = new io.File(new Path(path).toNativePath()); |
- if (!file.existsSync()) { |
- return new Future.value(null); |
- } |
- return file.readAsLines().then((List<String> lines) { |
- var dependencies = new List<Uri>(); |
- for (var line in lines) { |
- line = line.trim(); |
- if (line.length > 0) { |
- dependencies.add(Uri.parse(line)); |
- } |
- } |
- return dependencies; |
- }); |
- } |
- |
- return readDepsFile("$_outputFile.deps").then((dependencies) { |
- if (dependencies != null) { |
- dependencies.addAll(_bootstrapDependencies); |
- var jsOutputLastModified = TestUtils.lastModifiedCache |
- .getLastModified(new Uri(scheme: 'file', path: _outputFile)); |
- if (jsOutputLastModified != null) { |
- for (var dependency in dependencies) { |
- var dependencyLastModified = |
- TestUtils.lastModifiedCache.getLastModified(dependency); |
- if (dependencyLastModified == null || |
- dependencyLastModified.isAfter(jsOutputLastModified)) { |
- return false; |
- } |
- } |
- return true; |
- } |
- } |
- return false; |
- }); |
- } |
- |
- void _buildHashCode(HashCodeBuilder builder) { |
- super._buildHashCode(builder); |
- builder.addJson(_outputFile); |
- builder.addJson(_neverSkipCompilation); |
- builder.addJson(_bootstrapDependencies); |
- } |
- |
- bool _equal(CompilationCommand other) => |
- super._equal(other) && |
- _outputFile == other._outputFile && |
- _neverSkipCompilation == other._neverSkipCompilation && |
- deepJsonCompare(_bootstrapDependencies, other._bootstrapDependencies); |
-} |
- |
-class KernelCompilationCommand extends CompilationCommand { |
- KernelCompilationCommand._( |
- String displayName, |
- String outputFile, |
- bool neverSkipCompilation, |
- List<Uri> bootstrapDependencies, |
- String executable, |
- List<String> arguments, |
- Map<String, String> environmentOverrides) |
- : super._(displayName, outputFile, neverSkipCompilation, |
- bootstrapDependencies, executable, arguments, environmentOverrides); |
- |
- int get maxNumRetries => 1; |
-} |
- |
-/// This is just a Pair(String, Map) class with hashCode and operator == |
-class AddFlagsKey { |
- final String flags; |
- final Map env; |
- AddFlagsKey(this.flags, this.env); |
- // Just use object identity for environment map |
- bool operator ==(Object other) => |
- other is AddFlagsKey && flags == other.flags && env == other.env; |
- int get hashCode => flags.hashCode ^ env.hashCode; |
-} |
- |
-class ContentShellCommand extends ProcessCommand { |
- ContentShellCommand._( |
- String executable, |
- String htmlFile, |
- List<String> options, |
- List<String> dartFlags, |
- Map<String, String> environmentOverrides) |
- : super._("content_shell", executable, _getArguments(options, htmlFile), |
- _getEnvironment(environmentOverrides, dartFlags)); |
- |
- // Cache the modified environments in a map from the old environment and |
- // the string of Dart flags to the new environment. Avoid creating new |
- // environment object for each command object. |
- static Map<AddFlagsKey, Map<String, String>> environments = {}; |
- |
- static Map<String, String> _getEnvironment( |
- Map<String, String> env, List<String> dartFlags) { |
- var needDartFlags = dartFlags != null && dartFlags.isNotEmpty; |
- if (needDartFlags) { |
- if (env == null) { |
- env = const <String, String>{}; |
- } |
- var flags = dartFlags.join(' '); |
- return environments.putIfAbsent( |
- new AddFlagsKey(flags, env), |
- () => new Map<String, String>.from(env) |
- ..addAll({'DART_FLAGS': flags, 'DART_FORWARDING_PRINT': '1'})); |
- } |
- return env; |
- } |
- |
- static List<String> _getArguments(List<String> options, String htmlFile) { |
- var arguments = options.toList(); |
- arguments.add(htmlFile); |
- return arguments; |
- } |
- |
- int get maxNumRetries => 3; |
-} |
- |
-class BrowserTestCommand extends Command { |
- Runtime get browser => configuration.runtime; |
- final String url; |
- final Configuration configuration; |
- final bool retry; |
- |
- BrowserTestCommand._(this.url, this.configuration, this.retry) |
- : super._(configuration.runtime.name); |
- |
- void _buildHashCode(HashCodeBuilder builder) { |
- super._buildHashCode(builder); |
- builder.addJson(browser.name); |
- builder.addJson(url); |
- builder.add(configuration); |
- builder.add(retry); |
- } |
- |
- bool _equal(BrowserTestCommand other) => |
- super._equal(other) && |
- browser == other.browser && |
- url == other.url && |
- identical(configuration, other.configuration) && |
- retry == other.retry; |
- |
- String get reproductionCommand { |
- var parts = [ |
- io.Platform.resolvedExecutable, |
- 'tools/testing/dart/launch_browser.dart', |
- browser.name, |
- url |
- ]; |
- return parts.map(escapeCommandLineArgument).join(' '); |
- } |
- |
- int get maxNumRetries => 4; |
-} |
- |
-class BrowserHtmlTestCommand extends BrowserTestCommand { |
- List<String> expectedMessages; |
- BrowserHtmlTestCommand._(String url, Configuration configuration, |
- this.expectedMessages, bool retry) |
- : super._(url, configuration, retry); |
- |
- void _buildHashCode(HashCodeBuilder builder) { |
- super._buildHashCode(builder); |
- builder.addJson(expectedMessages); |
- } |
- |
- bool _equal(BrowserHtmlTestCommand other) => |
- super._equal(other) && |
- identical(expectedMessages, other.expectedMessages); |
-} |
- |
-class AnalysisCommand extends ProcessCommand { |
- final String flavor; |
- |
- AnalysisCommand._(this.flavor, String displayName, String executable, |
- List<String> arguments, Map<String, String> environmentOverrides) |
- : super._(displayName, executable, arguments, environmentOverrides); |
- |
- void _buildHashCode(HashCodeBuilder builder) { |
- super._buildHashCode(builder); |
- builder.addJson(flavor); |
- } |
- |
- bool _equal(AnalysisCommand other) => |
- super._equal(other) && flavor == other.flavor; |
-} |
- |
-class VmCommand extends ProcessCommand { |
- VmCommand._(String executable, List<String> arguments, |
- Map<String, String> environmentOverrides) |
- : super._("vm", executable, arguments, environmentOverrides); |
-} |
- |
-class VmBatchCommand extends ProcessCommand implements VmCommand { |
- final String dartFile; |
- final bool checked; |
- |
- VmBatchCommand._(String executable, String dartFile, List<String> arguments, |
- Map<String, String> environmentOverrides, |
- {this.checked: true}) |
- : this.dartFile = dartFile, |
- super._('vm-batch', executable, arguments, environmentOverrides); |
- |
- @override |
- List<String> get batchArguments => |
- checked ? ['--checked', dartFile] : [dartFile]; |
- |
- @override |
- bool _equal(VmBatchCommand other) { |
- return super._equal(other) && |
- dartFile == other.dartFile && |
- checked == other.checked; |
- } |
- |
- @override |
- void _buildHashCode(HashCodeBuilder builder) { |
- super._buildHashCode(builder); |
- builder.addJson(dartFile); |
- builder.addJson(checked); |
- } |
-} |
- |
-class AdbPrecompilationCommand extends Command { |
- final String precompiledRunnerFilename; |
- final String processTestFilename; |
- final String precompiledTestDirectory; |
- final List<String> arguments; |
- final bool useBlobs; |
- |
- AdbPrecompilationCommand._( |
- this.precompiledRunnerFilename, |
- this.processTestFilename, |
- this.precompiledTestDirectory, |
- this.arguments, |
- this.useBlobs) |
- : super._("adb_precompilation"); |
- |
- void _buildHashCode(HashCodeBuilder builder) { |
- super._buildHashCode(builder); |
- builder.add(precompiledRunnerFilename); |
- builder.add(precompiledTestDirectory); |
- builder.add(arguments); |
- builder.add(useBlobs); |
- } |
- |
- bool _equal(AdbPrecompilationCommand other) => |
- super._equal(other) && |
- precompiledRunnerFilename == other.precompiledRunnerFilename && |
- useBlobs == other.useBlobs && |
- arguments == other.arguments && |
- precompiledTestDirectory == other.precompiledTestDirectory; |
- |
- String toString() => 'Steps to push precompiled runner and precompiled code ' |
- 'to an attached device. Uses (and requires) adb.'; |
-} |
- |
-class JSCommandlineCommand extends ProcessCommand { |
- JSCommandlineCommand._( |
- String displayName, String executable, List<String> arguments, |
- [Map<String, String> environmentOverrides = null]) |
- : super._(displayName, executable, arguments, environmentOverrides); |
-} |
- |
-class PubCommand extends ProcessCommand { |
- final String command; |
- |
- PubCommand._(String pubCommand, String pubExecutable, |
- String pubspecYamlDirectory, String pubCacheDirectory, List<String> args) |
- : command = pubCommand, |
- super._( |
- 'pub_$pubCommand', |
- new io.File(pubExecutable).absolute.path, |
- [pubCommand]..addAll(args), |
- {'PUB_CACHE': pubCacheDirectory}, |
- pubspecYamlDirectory); |
- |
- void _buildHashCode(HashCodeBuilder builder) { |
- super._buildHashCode(builder); |
- builder.addJson(command); |
- } |
- |
- bool _equal(PubCommand other) => |
- super._equal(other) && command == other.command; |
-} |
- |
-/* [ScriptCommand]s are executed by dart code. */ |
-abstract class ScriptCommand extends Command { |
- ScriptCommand._(String displayName) : super._(displayName); |
- |
- Future<ScriptCommandOutputImpl> run(); |
-} |
- |
-class CleanDirectoryCopyCommand extends ScriptCommand { |
- final String _sourceDirectory; |
- final String _destinationDirectory; |
- |
- CleanDirectoryCopyCommand._(this._sourceDirectory, this._destinationDirectory) |
- : super._('dir_copy'); |
- |
- String get reproductionCommand => |
- "Copying '$_sourceDirectory' to '$_destinationDirectory'."; |
- |
- Future<ScriptCommandOutputImpl> run() { |
- var watch = new Stopwatch()..start(); |
- |
- var destination = new io.Directory(_destinationDirectory); |
- |
- return destination.exists().then((bool exists) { |
- Future cleanDirectoryFuture; |
- if (exists) { |
- cleanDirectoryFuture = TestUtils.deleteDirectory(_destinationDirectory); |
- } else { |
- cleanDirectoryFuture = new Future.value(null); |
- } |
- return cleanDirectoryFuture.then((_) { |
- return TestUtils.copyDirectory(_sourceDirectory, _destinationDirectory); |
- }); |
- }).then((_) { |
- return new ScriptCommandOutputImpl( |
- this, Expectation.pass, "", watch.elapsed); |
- }).catchError((error) { |
- return new ScriptCommandOutputImpl( |
- this, Expectation.fail, "An error occured: $error.", watch.elapsed); |
- }); |
- } |
- |
- void _buildHashCode(HashCodeBuilder builder) { |
- super._buildHashCode(builder); |
- builder.addJson(_sourceDirectory); |
- builder.addJson(_destinationDirectory); |
- } |
- |
- bool _equal(CleanDirectoryCopyCommand other) => |
- super._equal(other) && |
- _sourceDirectory == other._sourceDirectory && |
- _destinationDirectory == other._destinationDirectory; |
-} |
- |
-/* |
- * [MakeSymlinkCommand] makes a symbolic link to another directory. |
- */ |
-class MakeSymlinkCommand extends ScriptCommand { |
- String _link; |
- String _target; |
- |
- MakeSymlinkCommand._(this._link, this._target) : super._('make_symlink'); |
- |
- String get reproductionCommand => |
- "Make symbolic link '$_link' (target: $_target)'."; |
- |
- Future<ScriptCommandOutputImpl> run() { |
- var watch = new Stopwatch()..start(); |
- var targetFile = new io.Directory(_target); |
- return targetFile.exists().then((bool targetExists) { |
- if (!targetExists) { |
- throw new Exception("Target '$_target' does not exist"); |
- } |
- var link = new io.Link(_link); |
- |
- return link.exists().then((bool exists) { |
- if (exists) return link.delete(); |
- }).then((_) => link.create(_target)); |
- }).then((_) { |
- return new ScriptCommandOutputImpl( |
- this, Expectation.pass, "", watch.elapsed); |
- }).catchError((error) { |
- return new ScriptCommandOutputImpl( |
- this, Expectation.fail, "An error occured: $error.", watch.elapsed); |
- }); |
- } |
- |
- void _buildHashCode(HashCodeBuilder builder) { |
- super._buildHashCode(builder); |
- builder.addJson(_link); |
- builder.addJson(_target); |
- } |
- |
- bool _equal(MakeSymlinkCommand other) => |
- super._equal(other) && _link == other._link && _target == other._target; |
-} |
- |
-class CommandBuilder { |
- static final CommandBuilder instance = new CommandBuilder._(); |
- |
- bool _cleared = false; |
- final _cachedCommands = new Map<Command, Command>(); |
- |
- CommandBuilder._(); |
- |
- void clearCommandCache() { |
- _cachedCommands.clear(); |
- _cleared = true; |
- } |
- |
- ContentShellCommand getContentShellCommand( |
- String executable, |
- String htmlFile, |
- List<String> options, |
- List<String> dartFlags, |
- Map<String, String> environment) { |
- ContentShellCommand command = new ContentShellCommand._( |
- executable, htmlFile, options, dartFlags, environment); |
- return _getUniqueCommand(command); |
- } |
- |
- BrowserTestCommand getBrowserTestCommand( |
- String url, Configuration configuration, bool retry) { |
- var command = new BrowserTestCommand._(url, configuration, retry); |
- return _getUniqueCommand(command); |
- } |
- |
- BrowserHtmlTestCommand getBrowserHtmlTestCommand(String url, |
- Configuration configuration, List<String> expectedMessages, bool retry) { |
- var command = new BrowserHtmlTestCommand._( |
- url, configuration, expectedMessages, retry); |
- return _getUniqueCommand(command); |
- } |
- |
- CompilationCommand getCompilationCommand( |
- String displayName, |
- String outputFile, |
- bool neverSkipCompilation, |
- List<Uri> bootstrapDependencies, |
- String executable, |
- List<String> arguments, |
- Map<String, String> environment) { |
- var command = new CompilationCommand._( |
- displayName, |
- outputFile, |
- neverSkipCompilation, |
- bootstrapDependencies, |
- executable, |
- arguments, |
- environment); |
- return _getUniqueCommand(command); |
- } |
- |
- CompilationCommand getKernelCompilationCommand( |
- String displayName, |
- String outputFile, |
- bool neverSkipCompilation, |
- List<Uri> bootstrapDependencies, |
- String executable, |
- List<String> arguments, |
- Map<String, String> environment) { |
- var command = new KernelCompilationCommand._( |
- displayName, |
- outputFile, |
- neverSkipCompilation, |
- bootstrapDependencies, |
- executable, |
- arguments, |
- environment); |
- return _getUniqueCommand(command); |
- } |
- |
- AnalysisCommand getAnalysisCommand(String displayName, String executable, |
- List<String> arguments, Map<String, String> environmentOverrides, |
- {String flavor: 'dart2analyzer'}) { |
- var command = new AnalysisCommand._( |
- flavor, displayName, executable, arguments, environmentOverrides); |
- return _getUniqueCommand(command); |
- } |
- |
- VmCommand getVmCommand(String executable, List<String> arguments, |
- Map<String, String> environmentOverrides) { |
- var command = new VmCommand._(executable, arguments, environmentOverrides); |
- return _getUniqueCommand(command); |
- } |
- |
- VmBatchCommand getVmBatchCommand(String executable, String tester, |
- List<String> arguments, Map<String, String> environmentOverrides, |
- {bool checked: true}) { |
- var command = new VmBatchCommand._( |
- executable, tester, arguments, environmentOverrides, |
- checked: checked); |
- return _getUniqueCommand(command); |
- } |
- |
- AdbPrecompilationCommand getAdbPrecompiledCommand( |
- String precompiledRunner, |
- String processTest, |
- String testDirectory, |
- List<String> arguments, |
- bool useBlobs) { |
- var command = new AdbPrecompilationCommand._( |
- precompiledRunner, processTest, testDirectory, arguments, useBlobs); |
- return _getUniqueCommand(command); |
- } |
- |
- Command getJSCommandlineCommand( |
- String displayName, String executable, List<String> arguments, |
- [Map<String, String> environment]) { |
- var command = new JSCommandlineCommand._( |
- displayName, executable, arguments, environment); |
- return _getUniqueCommand(command); |
- } |
- |
- Command getProcessCommand( |
- String displayName, String executable, List<String> arguments, |
- [Map<String, String> environment, String workingDirectory]) { |
- var command = new ProcessCommand._( |
- displayName, executable, arguments, environment, workingDirectory); |
- return _getUniqueCommand(command); |
- } |
- |
- Command getCopyCommand(String sourceDirectory, String destinationDirectory) { |
- var command = |
- new CleanDirectoryCopyCommand._(sourceDirectory, destinationDirectory); |
- return _getUniqueCommand(command); |
- } |
- |
- Command getPubCommand(String pubCommand, String pubExecutable, |
- String pubspecYamlDirectory, String pubCacheDirectory, |
- {List<String> arguments: const <String>[]}) { |
- var command = new PubCommand._(pubCommand, pubExecutable, |
- pubspecYamlDirectory, pubCacheDirectory, arguments); |
- return _getUniqueCommand(command); |
- } |
- |
- Command getMakeSymlinkCommand(String link, String target) { |
- return _getUniqueCommand(new MakeSymlinkCommand._(link, target)); |
- } |
- |
- T _getUniqueCommand<T extends Command>(T command) { |
- // All Command classes implement hashCode and operator==. |
- // We check if this command has already been built. |
- // If so, we return the cached one. Otherwise we |
- // store the one given as [command] argument. |
- if (_cleared) { |
- throw new Exception( |
- "CommandBuilder.get[type]Command called after cache cleared"); |
- } |
- var cachedCommand = _cachedCommands[command]; |
- if (cachedCommand != null) { |
- return cachedCommand as T; |
- } |
- _cachedCommands[command] = command; |
- return command; |
- } |
-} |
- |
/** |
* TestCase contains all the information needed to run a test and evaluate |
* its output. Running a test involves starting a separate process, with |
@@ -889,906 +226,6 @@ class BrowserTestCase extends TestCase { |
String get testingUrl => _testingUrl; |
} |
-class UnittestSuiteMessagesMixin { |
- bool _isAsyncTest(String testOutput) { |
- return testOutput.contains("unittest-suite-wait-for-done"); |
- } |
- |
- bool _isAsyncTestSuccessful(String testOutput) { |
- return testOutput.contains("unittest-suite-success"); |
- } |
- |
- Expectation _negateOutcomeIfIncompleteAsyncTest( |
- Expectation outcome, String testOutput) { |
- // If this is an asynchronous test and the asynchronous operation didn't |
- // complete successfully, it's outcome is Expectation.FAIL. |
- // TODO: maybe we should introduce a AsyncIncomplete marker or so |
- if (outcome == Expectation.pass) { |
- if (_isAsyncTest(testOutput) && !_isAsyncTestSuccessful(testOutput)) { |
- return Expectation.fail; |
- } |
- } |
- return outcome; |
- } |
-} |
- |
-/** |
- * CommandOutput records the output of a completed command: the process's exit |
- * code, the standard output and standard error, whether the process timed out, |
- * and the time the process took to run. It does not contain a pointer to the |
- * [TestCase] this is the output of, so some functions require the test case |
- * to be passed as an argument. |
- */ |
-abstract class CommandOutput { |
- Command get command; |
- |
- Expectation result(TestCase testCase); |
- |
- bool get hasCrashed; |
- |
- bool get hasTimedOut; |
- |
- bool didFail(TestCase testCase); |
- |
- bool hasFailed(TestCase testCase); |
- |
- bool get canRunDependendCommands; |
- |
- bool get successful; // otherwise we might to retry running |
- |
- Duration get time; |
- |
- int get exitCode; |
- |
- int get pid; |
- |
- List<int> get stdout; |
- |
- List<int> get stderr; |
- |
- List<String> get diagnostics; |
- |
- bool get compilationSkipped; |
-} |
- |
-class CommandOutputImpl extends UniqueObject implements CommandOutput { |
- Command command; |
- int exitCode; |
- |
- bool timedOut; |
- List<int> stdout; |
- List<int> stderr; |
- Duration time; |
- List<String> diagnostics; |
- bool compilationSkipped; |
- int pid; |
- |
- /** |
- * A flag to indicate we have already printed a warning about ignoring the VM |
- * crash, to limit the amount of output produced per test. |
- */ |
- bool alreadyPrintedWarning = false; |
- |
- CommandOutputImpl( |
- Command this.command, |
- int this.exitCode, |
- bool this.timedOut, |
- List<int> this.stdout, |
- List<int> this.stderr, |
- Duration this.time, |
- bool this.compilationSkipped, |
- int this.pid) { |
- diagnostics = []; |
- } |
- |
- Expectation result(TestCase testCase) { |
- if (hasCrashed) return Expectation.crash; |
- if (hasTimedOut) return Expectation.timeout; |
- if (hasFailed(testCase)) return Expectation.fail; |
- if (hasNonUtf8) return Expectation.nonUtf8Error; |
- return Expectation.pass; |
- } |
- |
- bool get hasCrashed { |
- // dart2js exits with code 253 in case of unhandled exceptions. |
- // The dart binary exits with code 253 in case of an API error such |
- // as an invalid snapshot file. |
- // In either case an exit code of 253 is considered a crash. |
- if (exitCode == 253) return true; |
- if (io.Platform.operatingSystem == 'windows') { |
- // The VM uses std::abort to terminate on asserts. |
- // std::abort terminates with exit code 3 on Windows. |
- if (exitCode == 3 || exitCode == CRASHING_BROWSER_EXITCODE) { |
- return !timedOut; |
- } |
- // If a program receives an uncaught system exception, the program |
- // terminates with the exception code as exit code. |
- // The 0x3FFFFF00 mask here tries to determine if an exception indicates |
- // a crash of the program. |
- // System exception codes can be found in 'winnt.h', for example |
- // "#define STATUS_ACCESS_VIOLATION ((DWORD) 0xC0000005)" |
- return (!timedOut && (exitCode < 0) && ((0x3FFFFF00 & exitCode) == 0)); |
- } |
- return !timedOut && ((exitCode < 0)); |
- } |
- |
- bool get hasTimedOut => timedOut; |
- |
- bool didFail(TestCase testCase) { |
- return (exitCode != 0 && !hasCrashed); |
- } |
- |
- bool get canRunDependendCommands { |
- // FIXME(kustermann): We may need to change this |
- return !hasTimedOut && exitCode == 0; |
- } |
- |
- bool get successful { |
- // FIXME(kustermann): We may need to change this |
- return !hasTimedOut && exitCode == 0; |
- } |
- |
- // Reverse result of a negative test. |
- bool hasFailed(TestCase testCase) { |
- return testCase.isNegative ? !didFail(testCase) : didFail(testCase); |
- } |
- |
- bool get hasNonUtf8 => exitCode == NON_UTF_FAKE_EXITCODE; |
- |
- Expectation _negateOutcomeIfNegativeTest( |
- Expectation outcome, bool isNegative) { |
- if (!isNegative) return outcome; |
- if (outcome == Expectation.ignore) return outcome; |
- if (outcome.canBeOutcomeOf(Expectation.fail)) { |
- return Expectation.pass; |
- } |
- return Expectation.fail; |
- } |
-} |
- |
-class ContentShellCommandOutputImpl extends CommandOutputImpl { |
- // Although tests are reported as passing, content shell sometimes exits with |
- // a nonzero exitcode which makes our dartium builders extremely falky. |
- // See: http://dartbug.com/15139. |
- // TODO(rnystrom): Is this still needed? The underlying bug is closed. |
- static int WHITELISTED_CONTENTSHELL_EXITCODE = -1073740022; |
- static bool isWindows = io.Platform.operatingSystem == 'windows'; |
- static bool _failedBecauseOfFlakyInfrastructure( |
- Command command, bool timedOut, List<int> stderrBytes) { |
- // If the browser test failed, it may have been because content shell |
- // and the virtual framebuffer X server didn't hook up, or it crashed with |
- // a core dump. Sometimes content shell crashes after it has set the stdout |
- // to PASS, so we have to do this check first. |
- // Content shell also fails with a broken pipe message: Issue 26739 |
- var zygoteCrash = |
- new RegExp(r"ERROR:zygote_linux\.cc\(\d+\)] write: Broken pipe"); |
- var stderr = decodeUtf8(stderrBytes); |
- // TODO(7564): See http://dartbug.com/7564 |
- // This may not be happening anymore. Test by removing this suppression. |
- if (stderr.contains(MESSAGE_CANNOT_OPEN_DISPLAY) || |
- stderr.contains(MESSAGE_FAILED_TO_RUN_COMMAND)) { |
- DebugLogger.warning( |
- "Warning: Failure because of missing XDisplay. Test ignored"); |
- return true; |
- } |
- // TODO(26739): See http://dartbug.com/26739 |
- if (zygoteCrash.hasMatch(stderr)) { |
- DebugLogger.warning("Warning: Failure because of content_shell " |
- "zygote crash. Test ignored"); |
- return true; |
- } |
- return false; |
- } |
- |
- bool _infraFailure; |
- |
- ContentShellCommandOutputImpl( |
- Command command, |
- int exitCode, |
- bool timedOut, |
- List<int> stdout, |
- List<int> stderr, |
- Duration time, |
- bool compilationSkipped) |
- : _infraFailure = |
- _failedBecauseOfFlakyInfrastructure(command, timedOut, stderr), |
- super(command, exitCode, timedOut, stdout, stderr, time, |
- compilationSkipped, 0); |
- |
- Expectation result(TestCase testCase) { |
- if (_infraFailure) { |
- return Expectation.ignore; |
- } |
- |
- // Handle crashes and timeouts first |
- if (hasCrashed) return Expectation.crash; |
- if (hasTimedOut) return Expectation.timeout; |
- if (hasNonUtf8) return Expectation.nonUtf8Error; |
- |
- var outcome = _getOutcome(); |
- |
- if (testCase.hasRuntimeError) { |
- if (!outcome.canBeOutcomeOf(Expectation.runtimeError)) { |
- return Expectation.missingRuntimeError; |
- } |
- } |
- if (testCase.isNegative) { |
- if (outcome.canBeOutcomeOf(Expectation.fail)) return Expectation.pass; |
- return Expectation.fail; |
- } |
- return outcome; |
- } |
- |
- bool get successful => canRunDependendCommands; |
- |
- bool get canRunDependendCommands { |
- // We cannot rely on the exit code of content_shell as a method to |
- // determine if we were successful or not. |
- return super.canRunDependendCommands && !didFail(null); |
- } |
- |
- bool get hasCrashed { |
- return super.hasCrashed || _rendererCrashed; |
- } |
- |
- Expectation _getOutcome() { |
- if (_browserTestFailure) { |
- return Expectation.runtimeError; |
- } |
- return Expectation.pass; |
- } |
- |
- bool get _rendererCrashed => |
- decodeUtf8(super.stdout).contains("#CRASHED - rendere"); |
- |
- bool get _browserTestFailure { |
- // Browser tests fail unless stdout contains |
- // 'Content-Type: text/plain' followed by 'PASS'. |
- bool hasContentType = false; |
- var stdoutLines = decodeUtf8(super.stdout).split("\n"); |
- var containsFail = false; |
- var containsPass = false; |
- for (String line in stdoutLines) { |
- switch (line) { |
- case 'Content-Type: text/plain': |
- hasContentType = true; |
- break; |
- case 'FAIL': |
- if (hasContentType) { |
- containsFail = true; |
- } |
- break; |
- case 'PASS': |
- if (hasContentType) { |
- containsPass = true; |
- } |
- break; |
- } |
- } |
- if (hasContentType) { |
- if (containsFail && containsPass) { |
- DebugLogger.warning("Test had 'FAIL' and 'PASS' in stdout. ($command)"); |
- } |
- if (!containsFail && !containsPass) { |
- DebugLogger.warning("Test had neither 'FAIL' nor 'PASS' in stdout. " |
- "($command)"); |
- return true; |
- } |
- if (containsFail) { |
- return true; |
- } |
- assert(containsPass); |
- if (exitCode != 0) { |
- var message = "All tests passed, but exitCode != 0. " |
- "Actual exitcode: $exitCode. " |
- "($command)"; |
- DebugLogger.warning(message); |
- diagnostics.add(message); |
- } |
- return (!hasCrashed && |
- exitCode != 0 && |
- (!isWindows || exitCode != WHITELISTED_CONTENTSHELL_EXITCODE)); |
- } |
- DebugLogger.warning("Couldn't find 'Content-Type: text/plain' in output. " |
- "($command)."); |
- return true; |
- } |
-} |
- |
-// TODO(29869): Remove this class after verifying it isn't used. |
-class HTMLBrowserCommandOutputImpl extends ContentShellCommandOutputImpl { |
- HTMLBrowserCommandOutputImpl( |
- Command command, |
- int exitCode, |
- bool timedOut, |
- List<int> stdout, |
- List<int> stderr, |
- Duration time, |
- bool compilationSkipped) |
- : super(command, exitCode, timedOut, stdout, stderr, time, |
- compilationSkipped); |
- |
- bool didFail(TestCase testCase) { |
- return _getOutcome() != Expectation.pass; |
- } |
- |
- bool get _browserTestFailure { |
- // We should not need to convert back and forward. |
- var output = decodeUtf8(super.stdout); |
- if (output.contains("FAIL")) return true; |
- return !output.contains("PASS"); |
- } |
-} |
- |
-class BrowserTestJsonResult { |
- static const ALLOWED_TYPES = const [ |
- 'sync_exception', |
- 'window_onerror', |
- 'script_onerror', |
- 'window_compilationerror', |
- 'print', |
- 'message_received', |
- 'dom', |
- 'debug' |
- ]; |
- |
- final Expectation outcome; |
- final String htmlDom; |
- final List<dynamic> events; |
- |
- BrowserTestJsonResult(this.outcome, this.htmlDom, this.events); |
- |
- static BrowserTestJsonResult parseFromString(String content) { |
- void validate(String assertion, bool value) { |
- if (!value) { |
- throw "InvalidFormat sent from browser driving page: $assertion:\n\n" |
- "$content"; |
- } |
- } |
- |
- try { |
- var events = JSON.decode(content); |
- if (events != null) { |
- validate("Message must be a List", events is List); |
- |
- var messagesByType = <String, List<String>>{}; |
- ALLOWED_TYPES.forEach((type) => messagesByType[type] = <String>[]); |
- |
- for (var entry in events) { |
- validate("An entry must be a Map", entry is Map); |
- |
- var type = entry['type']; |
- var value = entry['value'] as String; |
- var timestamp = entry['timestamp']; |
- |
- validate("'type' of an entry must be a String", type is String); |
- validate("'type' has to be in $ALLOWED_TYPES.", |
- ALLOWED_TYPES.contains(type)); |
- validate( |
- "'timestamp' of an entry must be a number", timestamp is num); |
- |
- messagesByType[type].add(value); |
- } |
- validate("The message must have exactly one 'dom' entry.", |
- messagesByType['dom'].length == 1); |
- |
- var dom = messagesByType['dom'][0]; |
- if (dom.endsWith('\n')) { |
- dom = '$dom\n'; |
- } |
- |
- return new BrowserTestJsonResult( |
- _getOutcome(messagesByType), dom, events as List<dynamic>); |
- } |
- } catch (error) { |
- // If something goes wrong, we know the content was not in the correct |
- // JSON format. So we can't parse it. |
- // The caller is responsible for falling back to the old way of |
- // determining if a test failed. |
- } |
- |
- return null; |
- } |
- |
- static Expectation _getOutcome(Map<String, List<String>> messagesByType) { |
- occured(String type) => messagesByType[type].length > 0; |
- searchForMsg(List<String> types, String message) { |
- return types.any((type) => messagesByType[type].contains(message)); |
- } |
- |
- // FIXME(kustermann,ricow): I think this functionality doesn't work in |
- // test_controller.js: So far I haven't seen anything being reported on |
- // "window.compilationerror" |
- if (occured('window_compilationerror')) { |
- return Expectation.compileTimeError; |
- } |
- |
- if (occured('sync_exception') || |
- occured('window_onerror') || |
- occured('script_onerror')) { |
- return Expectation.runtimeError; |
- } |
- |
- if (messagesByType['dom'][0].contains('FAIL')) { |
- return Expectation.runtimeError; |
- } |
- |
- // We search for these messages in 'print' and 'message_received' because |
- // the unittest implementation posts these messages using |
- // "window.postMessage()" instead of the normal "print()" them. |
- |
- var isAsyncTest = searchForMsg( |
- ['print', 'message_received'], 'unittest-suite-wait-for-done'); |
- var isAsyncSuccess = |
- searchForMsg(['print', 'message_received'], 'unittest-suite-success') || |
- searchForMsg(['print', 'message_received'], 'unittest-suite-done'); |
- |
- if (isAsyncTest) { |
- if (isAsyncSuccess) { |
- return Expectation.pass; |
- } |
- return Expectation.runtimeError; |
- } |
- |
- var mainStarted = |
- searchForMsg(['print', 'message_received'], 'dart-calling-main'); |
- var mainDone = |
- searchForMsg(['print', 'message_received'], 'dart-main-done'); |
- |
- if (mainStarted && mainDone) { |
- return Expectation.pass; |
- } |
- return Expectation.fail; |
- } |
-} |
- |
-class BrowserControllerTestOutcome extends CommandOutputImpl |
- with UnittestSuiteMessagesMixin { |
- BrowserTestOutput _result; |
- Expectation _rawOutcome; |
- |
- factory BrowserControllerTestOutcome( |
- Command command, BrowserTestOutput result) { |
- String indent(String string, int numSpaces) { |
- var spaces = new List.filled(numSpaces, ' ').join(''); |
- return string |
- .replaceAll('\r\n', '\n') |
- .split('\n') |
- .map((line) => "$spaces$line") |
- .join('\n'); |
- } |
- |
- String stdout = ""; |
- String stderr = ""; |
- Expectation outcome; |
- |
- var parsedResult = |
- BrowserTestJsonResult.parseFromString(result.lastKnownMessage); |
- if (parsedResult != null) { |
- outcome = parsedResult.outcome; |
- } else { |
- // Old way of determining whether a test failed or passed. |
- if (result.lastKnownMessage.contains("FAIL")) { |
- outcome = Expectation.runtimeError; |
- } else if (result.lastKnownMessage.contains("PASS")) { |
- outcome = Expectation.pass; |
- } else { |
- outcome = Expectation.runtimeError; |
- } |
- } |
- |
- if (result.didTimeout) { |
- if (result.delayUntilTestStarted != null) { |
- stderr = "This test timed out. The delay until the test actually " |
- "started was: ${result.delayUntilTestStarted}."; |
- } else { |
- stderr = "This test has not notified test.py that it started running."; |
- } |
- } |
- |
- if (parsedResult != null) { |
- stdout = "events:\n${indent(prettifyJson(parsedResult.events), 2)}\n\n"; |
- } else { |
- stdout = "message:\n${indent(result.lastKnownMessage, 2)}\n\n"; |
- } |
- |
- stderr = '$stderr\n\n' |
- 'BrowserOutput while running the test (* EXPERIMENTAL *):\n' |
- 'BrowserOutput.stdout:\n' |
- '${indent(result.browserOutput.stdout.toString(), 2)}\n' |
- 'BrowserOutput.stderr:\n' |
- '${indent(result.browserOutput.stderr.toString(), 2)}\n' |
- '\n'; |
- return new BrowserControllerTestOutcome._internal( |
- command, result, outcome, encodeUtf8(stdout), encodeUtf8(stderr)); |
- } |
- |
- BrowserControllerTestOutcome._internal( |
- Command command, |
- BrowserTestOutput result, |
- this._rawOutcome, |
- List<int> stdout, |
- List<int> stderr) |
- : super(command, 0, result.didTimeout, stdout, stderr, result.duration, |
- false, 0) { |
- _result = result; |
- } |
- |
- Expectation result(TestCase testCase) { |
- // Handle timeouts first |
- if (_result.didTimeout) { |
- if (testCase.configuration.runtime == Runtime.ie11) { |
- // TODO(28955): See http://dartbug.com/28955 |
- DebugLogger.warning("Timeout of ie11 on test ${testCase.displayName}"); |
- return Expectation.ignore; |
- } |
- return Expectation.timeout; |
- } |
- |
- if (hasNonUtf8) return Expectation.nonUtf8Error; |
- |
- // Multitests are handled specially |
- if (testCase.hasRuntimeError) { |
- if (_rawOutcome == Expectation.runtimeError) return Expectation.pass; |
- return Expectation.missingRuntimeError; |
- } |
- |
- return _negateOutcomeIfNegativeTest(_rawOutcome, testCase.isNegative); |
- } |
-} |
- |
-class AnalysisCommandOutputImpl extends CommandOutputImpl { |
- // An error line has 8 fields that look like: |
- // ERROR|COMPILER|MISSING_SOURCE|file:/tmp/t.dart|15|1|24|Missing source. |
- final int ERROR_LEVEL = 0; |
- final int ERROR_TYPE = 1; |
- final int FILENAME = 3; |
- final int FORMATTED_ERROR = 7; |
- |
- AnalysisCommandOutputImpl( |
- Command command, |
- int exitCode, |
- bool timedOut, |
- List<int> stdout, |
- List<int> stderr, |
- Duration time, |
- bool compilationSkipped) |
- : super(command, exitCode, timedOut, stdout, stderr, time, |
- compilationSkipped, 0); |
- |
- Expectation result(TestCase testCase) { |
- // TODO(kustermann): If we run the analyzer not in batch mode, make sure |
- // that command.exitCodes matches 2 (errors), 1 (warnings), 0 (no warnings, |
- // no errors) |
- |
- // Handle crashes and timeouts first |
- if (hasCrashed) return Expectation.crash; |
- if (hasTimedOut) return Expectation.timeout; |
- if (hasNonUtf8) return Expectation.nonUtf8Error; |
- |
- // Get the errors/warnings from the analyzer |
- List<String> errors = []; |
- List<String> warnings = []; |
- parseAnalyzerOutput(errors, warnings); |
- |
- // Handle errors / missing errors |
- if (testCase.expectCompileError) { |
- if (errors.length > 0) { |
- return Expectation.pass; |
- } |
- return Expectation.missingCompileTimeError; |
- } |
- if (errors.length > 0) { |
- return Expectation.compileTimeError; |
- } |
- |
- // Handle static warnings / missing static warnings |
- if (testCase.hasStaticWarning) { |
- if (warnings.length > 0) { |
- return Expectation.pass; |
- } |
- return Expectation.missingStaticWarning; |
- } |
- if (warnings.length > 0) { |
- return Expectation.staticWarning; |
- } |
- |
- assert(errors.length == 0 && warnings.length == 0); |
- assert(!testCase.hasCompileError && !testCase.hasStaticWarning); |
- return Expectation.pass; |
- } |
- |
- void parseAnalyzerOutput(List<String> outErrors, List<String> outWarnings) { |
- // Parse a line delimited by the | character using \ as an escape character |
- // like: FOO|BAR|FOO\|BAR|FOO\\BAZ as 4 fields: FOO BAR FOO|BAR FOO\BAZ |
- List<String> splitMachineError(String line) { |
- StringBuffer field = new StringBuffer(); |
- List<String> result = []; |
- bool escaped = false; |
- for (var i = 0; i < line.length; i++) { |
- var c = line[i]; |
- if (!escaped && c == '\\') { |
- escaped = true; |
- continue; |
- } |
- escaped = false; |
- if (c == '|') { |
- result.add(field.toString()); |
- field = new StringBuffer(); |
- continue; |
- } |
- field.write(c); |
- } |
- result.add(field.toString()); |
- return result; |
- } |
- |
- for (String line in decodeUtf8(super.stderr).split("\n")) { |
- if (line.length == 0) continue; |
- List<String> fields = splitMachineError(line); |
- // We only consider errors/warnings for files of interest. |
- if (fields.length > FORMATTED_ERROR) { |
- if (fields[ERROR_LEVEL] == 'ERROR') { |
- outErrors.add(fields[FORMATTED_ERROR]); |
- } else if (fields[ERROR_LEVEL] == 'WARNING') { |
- outWarnings.add(fields[FORMATTED_ERROR]); |
- } |
- // OK to Skip error output that doesn't match the machine format |
- } |
- } |
- } |
-} |
- |
-class VmCommandOutputImpl extends CommandOutputImpl |
- with UnittestSuiteMessagesMixin { |
- static const DART_VM_EXITCODE_DFE_ERROR = 252; |
- static const DART_VM_EXITCODE_COMPILE_TIME_ERROR = 254; |
- static const DART_VM_EXITCODE_UNCAUGHT_EXCEPTION = 255; |
- |
- VmCommandOutputImpl(Command command, int exitCode, bool timedOut, |
- List<int> stdout, List<int> stderr, Duration time, int pid) |
- : super(command, exitCode, timedOut, stdout, stderr, time, false, pid); |
- |
- Expectation result(TestCase testCase) { |
- // Handle crashes and timeouts first |
- if (exitCode == DART_VM_EXITCODE_DFE_ERROR) return Expectation.dartkCrash; |
- if (hasCrashed) return Expectation.crash; |
- if (hasTimedOut) return Expectation.timeout; |
- if (hasNonUtf8) return Expectation.nonUtf8Error; |
- |
- // Multitests are handled specially |
- if (testCase.expectCompileError) { |
- if (exitCode == DART_VM_EXITCODE_COMPILE_TIME_ERROR) { |
- return Expectation.pass; |
- } |
- return Expectation.missingCompileTimeError; |
- } |
- if (testCase.hasRuntimeError) { |
- // TODO(kustermann): Do we consider a "runtimeError" only an uncaught |
- // exception or does any nonzero exit code fullfil this requirement? |
- if (exitCode != 0) { |
- return Expectation.pass; |
- } |
- return Expectation.missingRuntimeError; |
- } |
- |
- // The actual outcome depends on the exitCode |
- Expectation outcome; |
- if (exitCode == DART_VM_EXITCODE_COMPILE_TIME_ERROR) { |
- outcome = Expectation.compileTimeError; |
- } else if (exitCode == DART_VM_EXITCODE_UNCAUGHT_EXCEPTION) { |
- outcome = Expectation.runtimeError; |
- } else if (exitCode != 0) { |
- // This is a general fail, in case we get an unknown nonzero exitcode. |
- outcome = Expectation.fail; |
- } else { |
- outcome = Expectation.pass; |
- } |
- outcome = _negateOutcomeIfIncompleteAsyncTest(outcome, decodeUtf8(stdout)); |
- return _negateOutcomeIfNegativeTest(outcome, testCase.isNegative); |
- } |
-} |
- |
-class CompilationCommandOutputImpl extends CommandOutputImpl { |
- static const DART2JS_EXITCODE_CRASH = 253; |
- |
- CompilationCommandOutputImpl( |
- Command command, |
- int exitCode, |
- bool timedOut, |
- List<int> stdout, |
- List<int> stderr, |
- Duration time, |
- bool compilationSkipped) |
- : super(command, exitCode, timedOut, stdout, stderr, time, |
- compilationSkipped, 0); |
- |
- Expectation result(TestCase testCase) { |
- // Handle general crash/timeout detection. |
- if (hasCrashed) return Expectation.crash; |
- if (hasTimedOut) { |
- bool isWindows = io.Platform.operatingSystem == 'windows'; |
- bool isBrowserTestCase = |
- testCase.commands.any((command) => command is BrowserTestCommand); |
- // TODO(26060) Dart2js batch mode hangs on Windows under heavy load. |
- return (isWindows && isBrowserTestCase) |
- ? Expectation.ignore |
- : Expectation.timeout; |
- } |
- if (hasNonUtf8) return Expectation.nonUtf8Error; |
- |
- // Handle dart2js specific crash detection |
- if (exitCode == DART2JS_EXITCODE_CRASH || |
- exitCode == VmCommandOutputImpl.DART_VM_EXITCODE_COMPILE_TIME_ERROR || |
- exitCode == VmCommandOutputImpl.DART_VM_EXITCODE_UNCAUGHT_EXCEPTION) { |
- return Expectation.crash; |
- } |
- |
- // Multitests are handled specially |
- if (testCase.expectCompileError) { |
- // Nonzero exit code of the compiler means compilation failed |
- // TODO(kustermann): Do we have a special exit code in that case??? |
- if (exitCode != 0) { |
- return Expectation.pass; |
- } |
- return Expectation.missingCompileTimeError; |
- } |
- |
- // TODO(kustermann): This is a hack, remove it |
- if (testCase.hasRuntimeError && testCase.commands.length > 1) { |
- // We expected to run the test, but we got an compile time error. |
- // If the compilation succeeded, we wouldn't be in here! |
- assert(exitCode != 0); |
- return Expectation.compileTimeError; |
- } |
- |
- Expectation outcome = |
- exitCode == 0 ? Expectation.pass : Expectation.compileTimeError; |
- return _negateOutcomeIfNegativeTest(outcome, testCase.isNegative); |
- } |
-} |
- |
-class KernelCompilationCommandOutputImpl extends CompilationCommandOutputImpl { |
- KernelCompilationCommandOutputImpl( |
- Command command, |
- int exitCode, |
- bool timedOut, |
- List<int> stdout, |
- List<int> stderr, |
- Duration time, |
- bool compilationSkipped) |
- : super(command, exitCode, timedOut, stdout, stderr, time, |
- compilationSkipped); |
- |
- bool get canRunDependendCommands { |
- // See [BatchRunnerProcess]: 0 means success, 1 means compile-time error. |
- // TODO(asgerf): When the frontend supports it, continue running even if |
- // there were compile-time errors. See kernel_sdk issue #18. |
- return !hasCrashed && !timedOut && exitCode == 0; |
- } |
- |
- Expectation result(TestCase testCase) { |
- Expectation result = super.result(testCase); |
- if (result.canBeOutcomeOf(Expectation.crash)) { |
- return Expectation.dartkCrash; |
- } else if (result.canBeOutcomeOf(Expectation.timeout)) { |
- return Expectation.dartkTimeout; |
- } else if (result.canBeOutcomeOf(Expectation.compileTimeError)) { |
- return Expectation.dartkCompileTimeError; |
- } |
- return result; |
- } |
- |
- // If the compiler was able to produce a Kernel IR file we want to run the |
- // result on the Dart VM. We therefore mark the [KernelCompilationCommand] as |
- // successful. |
- // => This ensures we test that the DartVM produces correct CompileTime errors |
- // as it is supposed to for our test suites. |
- bool get successful => canRunDependendCommands; |
-} |
- |
-class JsCommandlineOutputImpl extends CommandOutputImpl |
- with UnittestSuiteMessagesMixin { |
- JsCommandlineOutputImpl(Command command, int exitCode, bool timedOut, |
- List<int> stdout, List<int> stderr, Duration time) |
- : super(command, exitCode, timedOut, stdout, stderr, time, false, 0); |
- |
- Expectation result(TestCase testCase) { |
- // Handle crashes and timeouts first |
- if (hasCrashed) return Expectation.crash; |
- if (hasTimedOut) return Expectation.timeout; |
- if (hasNonUtf8) return Expectation.nonUtf8Error; |
- |
- if (testCase.hasRuntimeError) { |
- if (exitCode != 0) return Expectation.pass; |
- return Expectation.missingRuntimeError; |
- } |
- |
- var outcome = exitCode == 0 ? Expectation.pass : Expectation.runtimeError; |
- outcome = _negateOutcomeIfIncompleteAsyncTest(outcome, decodeUtf8(stdout)); |
- return _negateOutcomeIfNegativeTest(outcome, testCase.isNegative); |
- } |
-} |
- |
-class PubCommandOutputImpl extends CommandOutputImpl { |
- PubCommandOutputImpl(PubCommand command, int exitCode, bool timedOut, |
- List<int> stdout, List<int> stderr, Duration time) |
- : super(command, exitCode, timedOut, stdout, stderr, time, false, 0); |
- |
- Expectation result(TestCase testCase) { |
- // Handle crashes and timeouts first |
- if (hasCrashed) return Expectation.crash; |
- if (hasTimedOut) return Expectation.timeout; |
- if (hasNonUtf8) return Expectation.nonUtf8Error; |
- |
- if (exitCode == 0) { |
- return Expectation.pass; |
- } else if ((command as PubCommand).command == 'get') { |
- return Expectation.pubGetError; |
- } else { |
- return Expectation.fail; |
- } |
- } |
-} |
- |
-class ScriptCommandOutputImpl extends CommandOutputImpl { |
- final Expectation _result; |
- |
- ScriptCommandOutputImpl(ScriptCommand command, this._result, |
- String scriptExecutionInformation, Duration time) |
- : super(command, 0, false, [], [], time, false, 0) { |
- var lines = scriptExecutionInformation.split("\n"); |
- diagnostics.addAll(lines); |
- } |
- |
- Expectation result(TestCase testCase) => _result; |
- |
- bool get canRunDependendCommands => _result == Expectation.pass; |
- |
- bool get successful => _result == Expectation.pass; |
-} |
- |
-CommandOutput createCommandOutput(Command command, int exitCode, bool timedOut, |
- List<int> stdout, List<int> stderr, Duration time, bool compilationSkipped, |
- [int pid = 0]) { |
- if (command is ContentShellCommand) { |
- return new ContentShellCommandOutputImpl( |
- command, exitCode, timedOut, stdout, stderr, time, compilationSkipped); |
- } else if (command is BrowserTestCommand) { |
- return new HTMLBrowserCommandOutputImpl( |
- command, exitCode, timedOut, stdout, stderr, time, compilationSkipped); |
- } else if (command is AnalysisCommand) { |
- return new AnalysisCommandOutputImpl( |
- command, exitCode, timedOut, stdout, stderr, time, compilationSkipped); |
- } else if (command is VmCommand) { |
- return new VmCommandOutputImpl( |
- command, exitCode, timedOut, stdout, stderr, time, pid); |
- } else if (command is KernelCompilationCommand) { |
- return new KernelCompilationCommandOutputImpl( |
- command, exitCode, timedOut, stdout, stderr, time, compilationSkipped); |
- } else if (command is AdbPrecompilationCommand) { |
- return new VmCommandOutputImpl( |
- command, exitCode, timedOut, stdout, stderr, time, pid); |
- } else if (command is CompilationCommand) { |
- if (command.displayName == 'precompiler' || |
- command.displayName == 'app_jit') { |
- return new VmCommandOutputImpl( |
- command, exitCode, timedOut, stdout, stderr, time, pid); |
- } |
- return new CompilationCommandOutputImpl( |
- command, exitCode, timedOut, stdout, stderr, time, compilationSkipped); |
- } else if (command is JSCommandlineCommand) { |
- return new JsCommandlineOutputImpl( |
- command, exitCode, timedOut, stdout, stderr, time); |
- } else if (command is PubCommand) { |
- return new PubCommandOutputImpl( |
- command, exitCode, timedOut, stdout, stderr, time); |
- } |
- |
- return new CommandOutputImpl(command, exitCode, timedOut, stdout, stderr, |
- time, compilationSkipped, pid); |
-} |
- |
/** |
* An OutputLog records the output from a test, but truncates it if |
* it is longer than MAX_HEAD characters, and just keeps the head and |
@@ -2741,8 +1178,8 @@ class CommandExecutorImpl implements CommandExecutor { |
return _getBatchRunner("dart2js") |
.runCommand("dart2js", command, timeout, command.arguments); |
} else if (command is AnalysisCommand && globalConfiguration.batch) { |
- return _getBatchRunner(command.flavor) |
- .runCommand(command.flavor, command, timeout, command.arguments); |
+ return _getBatchRunner(command.displayName) |
+ .runCommand(command.displayName, command, timeout, command.arguments); |
} else if (command is ScriptCommand) { |
return command.run(); |
} else if (command is AdbPrecompilationCommand) { |
@@ -2863,8 +1300,7 @@ class CommandExecutorImpl implements CommandExecutor { |
var completer = new Completer<CommandOutput>(); |
var callback = (BrowserTestOutput output) { |
- completer |
- .complete(new BrowserControllerTestOutcome(browserCommand, output)); |
+ completer.complete(new BrowserCommandOutputImpl(browserCommand, output)); |
}; |
BrowserTest browserTest; |
@@ -3211,10 +1647,6 @@ class ProcessQueue { |
testCaseEnqueuer.enqueueTestSuites(testSuites); |
} |
- void freeEnqueueingStructures() { |
- CommandBuilder.instance.clearCommandCache(); |
- } |
- |
void eventFinishedTestCase(TestCase testCase) { |
for (var listener in _eventListener) { |
listener.done(testCase); |
@@ -3228,7 +1660,6 @@ class ProcessQueue { |
} |
void eventAllTestsKnown() { |
- freeEnqueueingStructures(); |
for (var listener in _eventListener) { |
listener.allTestsKnown(); |
} |