| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * Classes and methods for executing tests. | 6 * Classes and methods for executing tests. |
| 7 * | 7 * |
| 8 * This module includes: | 8 * This module includes: |
| 9 * - Managing parallel execution of tests, including timeout checks. | 9 * - Managing parallel execution of tests, including timeout checks. |
| 10 * - Evaluating the output of each test as pass/fail/crash/timeout. | 10 * - Evaluating the output of each test as pass/fail/crash/timeout. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 | 32 |
| 33 const MESSAGE_CANNOT_OPEN_DISPLAY = 'Gtk-WARNING **: cannot open display'; | 33 const MESSAGE_CANNOT_OPEN_DISPLAY = 'Gtk-WARNING **: cannot open display'; |
| 34 const MESSAGE_FAILED_TO_RUN_COMMAND = 'Failed to run command. return code=1'; | 34 const MESSAGE_FAILED_TO_RUN_COMMAND = 'Failed to run command. return code=1'; |
| 35 | 35 |
| 36 typedef void TestCaseEvent(TestCase testCase); | 36 typedef void TestCaseEvent(TestCase testCase); |
| 37 typedef void ExitCodeEvent(int exitCode); | 37 typedef void ExitCodeEvent(int exitCode); |
| 38 typedef void EnqueueMoreWork(ProcessQueue queue); | 38 typedef void EnqueueMoreWork(ProcessQueue queue); |
| 39 | 39 |
| 40 // Some IO tests use these variables and get confused if the host environment | 40 // Some IO tests use these variables and get confused if the host environment |
| 41 // variables are inherited so they are excluded. | 41 // variables are inherited so they are excluded. |
| 42 const List<String> EXCLUDED_ENVIRONMENT_VARIABLES = | 42 const List<String> EXCLUDED_ENVIRONMENT_VARIABLES = const [ |
| 43 const ['http_proxy', 'https_proxy', 'no_proxy', | 43 'http_proxy', |
| 44 'HTTP_PROXY', 'HTTPS_PROXY', 'NO_PROXY']; | 44 'https_proxy', |
| 45 | 45 'no_proxy', |
| 46 'HTTP_PROXY', |
| 47 'HTTPS_PROXY', |
| 48 'NO_PROXY' |
| 49 ]; |
| 46 | 50 |
| 47 /** A command executed as a step in a test case. */ | 51 /** A command executed as a step in a test case. */ |
| 48 class Command { | 52 class Command { |
| 49 /** A descriptive name for this command. */ | 53 /** A descriptive name for this command. */ |
| 50 String displayName; | 54 String displayName; |
| 51 | 55 |
| 52 /** Number of times this command *can* be retried */ | 56 /** Number of times this command *can* be retried */ |
| 53 int get maxNumRetries => 2; | 57 int get maxNumRetries => 2; |
| 54 | 58 |
| 55 /** Reproduction command */ | 59 /** Reproduction command */ |
| 56 String get reproductionCommand => null; | 60 String get reproductionCommand => null; |
| 57 | 61 |
| 58 // We compute the Command.hashCode lazily and cache it here, since it might | 62 // We compute the Command.hashCode lazily and cache it here, since it might |
| 59 // be expensive to compute (and hashCode is called often). | 63 // be expensive to compute (and hashCode is called often). |
| 60 int _cachedHashCode; | 64 int _cachedHashCode; |
| 61 | 65 |
| 62 Command._(this.displayName); | 66 Command._(this.displayName); |
| 63 | 67 |
| 64 int get hashCode { | 68 int get hashCode { |
| 65 if (_cachedHashCode == null) { | 69 if (_cachedHashCode == null) { |
| 66 var builder = new HashCodeBuilder(); | 70 var builder = new HashCodeBuilder(); |
| 67 _buildHashCode(builder); | 71 _buildHashCode(builder); |
| 68 _cachedHashCode = builder.value; | 72 _cachedHashCode = builder.value; |
| 69 } | 73 } |
| 70 return _cachedHashCode; | 74 return _cachedHashCode; |
| 71 } | 75 } |
| 72 | 76 |
| 73 operator ==(other) => identical(this, other) || | 77 operator ==(other) => |
| 78 identical(this, other) || |
| 74 (runtimeType == other.runtimeType && _equal(other)); | 79 (runtimeType == other.runtimeType && _equal(other)); |
| 75 | 80 |
| 76 void _buildHashCode(HashCodeBuilder builder) { | 81 void _buildHashCode(HashCodeBuilder builder) { |
| 77 builder.addJson(displayName); | 82 builder.addJson(displayName); |
| 78 } | 83 } |
| 79 | 84 |
| 80 bool _equal(Command other) => | 85 bool _equal(Command other) => |
| 81 hashCode == other.hashCode && | 86 hashCode == other.hashCode && displayName == other.displayName; |
| 82 displayName == other.displayName; | |
| 83 | 87 |
| 84 String toString() => reproductionCommand; | 88 String toString() => reproductionCommand; |
| 85 | 89 |
| 86 Future<bool> get outputIsUpToDate => new Future.value(false); | 90 Future<bool> get outputIsUpToDate => new Future.value(false); |
| 87 } | 91 } |
| 88 | 92 |
| 89 class ProcessCommand extends Command { | 93 class ProcessCommand extends Command { |
| 90 /** Path to the executable of this command. */ | 94 /** Path to the executable of this command. */ |
| 91 String executable; | 95 String executable; |
| 92 | 96 |
| 93 /** Command line arguments to the executable. */ | 97 /** Command line arguments to the executable. */ |
| 94 List<String> arguments; | 98 List<String> arguments; |
| 95 | 99 |
| 96 /** Environment for the command */ | 100 /** Environment for the command */ |
| 97 Map<String, String> environmentOverrides; | 101 Map<String, String> environmentOverrides; |
| 98 | 102 |
| 99 /** Working directory for the command */ | 103 /** Working directory for the command */ |
| 100 final String workingDirectory; | 104 final String workingDirectory; |
| 101 | 105 |
| 102 ProcessCommand._(String displayName, this.executable, | 106 ProcessCommand._(String displayName, this.executable, this.arguments, |
| 103 this.arguments, | 107 [this.environmentOverrides = null, this.workingDirectory = null]) |
| 104 [this.environmentOverrides = null, | |
| 105 this.workingDirectory = null]) | |
| 106 : super._(displayName) { | 108 : super._(displayName) { |
| 107 if (io.Platform.operatingSystem == 'windows') { | 109 if (io.Platform.operatingSystem == 'windows') { |
| 108 // Windows can't handle the first command if it is a .bat file or the like | 110 // Windows can't handle the first command if it is a .bat file or the like |
| 109 // with the slashes going the other direction. | 111 // with the slashes going the other direction. |
| 110 // NOTE: Issue 1306 | 112 // NOTE: Issue 1306 |
| 111 executable = executable.replaceAll('/', '\\'); | 113 executable = executable.replaceAll('/', '\\'); |
| 112 } | 114 } |
| 113 } | 115 } |
| 114 | 116 |
| 115 void _buildHashCode(HashCodeBuilder builder) { | 117 void _buildHashCode(HashCodeBuilder builder) { |
| 116 super._buildHashCode(builder); | 118 super._buildHashCode(builder); |
| 117 builder.addJson(executable); | 119 builder.addJson(executable); |
| 118 builder.addJson(workingDirectory); | 120 builder.addJson(workingDirectory); |
| 119 builder.addJson(arguments); | 121 builder.addJson(arguments); |
| 120 builder.addJson(environmentOverrides); | 122 builder.addJson(environmentOverrides); |
| 121 } | 123 } |
| 122 | 124 |
| 123 bool _equal(ProcessCommand other) => | 125 bool _equal(ProcessCommand other) => |
| 124 super._equal(other) && | 126 super._equal(other) && |
| 125 executable == other.executable && | 127 executable == other.executable && |
| 126 deepJsonCompare(arguments, other.arguments) && | 128 deepJsonCompare(arguments, other.arguments) && |
| 127 workingDirectory == other.workingDirectory && | 129 workingDirectory == other.workingDirectory && |
| 128 deepJsonCompare(environmentOverrides, other.environmentOverrides); | 130 deepJsonCompare(environmentOverrides, other.environmentOverrides); |
| 129 | 131 |
| 130 String get reproductionCommand { | 132 String get reproductionCommand { |
| 131 var env = new StringBuffer(); | 133 var env = new StringBuffer(); |
| 132 environmentOverrides.forEach((key, value) => | 134 environmentOverrides.forEach((key, value) => |
| 133 (io.Platform.operatingSystem == 'windows') ? | 135 (io.Platform.operatingSystem == 'windows') |
| 134 env.write('set $key=${escapeCommandLineArgument(value)} & ') : | 136 ? env.write('set $key=${escapeCommandLineArgument(value)} & ') |
| 135 env.write('$key=${escapeCommandLineArgument(value)} ')); | 137 : env.write('$key=${escapeCommandLineArgument(value)} ')); |
| 136 var command = ([executable]..addAll(arguments)) | 138 var command = ([executable]..addAll(arguments)) |
| 137 .map(escapeCommandLineArgument).join(' '); | 139 .map(escapeCommandLineArgument) |
| 140 .join(' '); |
| 138 if (workingDirectory != null) { | 141 if (workingDirectory != null) { |
| 139 command = "$command (working directory: $workingDirectory)"; | 142 command = "$command (working directory: $workingDirectory)"; |
| 140 } | 143 } |
| 141 return "$env$command"; | 144 return "$env$command"; |
| 142 } | 145 } |
| 143 | 146 |
| 144 Future<bool> get outputIsUpToDate => new Future.value(false); | 147 Future<bool> get outputIsUpToDate => new Future.value(false); |
| 145 } | 148 } |
| 146 | 149 |
| 147 class CompilationCommand extends ProcessCommand { | 150 class CompilationCommand extends ProcessCommand { |
| 148 final String _outputFile; | 151 final String _outputFile; |
| 149 final bool _neverSkipCompilation; | 152 final bool _neverSkipCompilation; |
| 150 final List<Uri> _bootstrapDependencies; | 153 final List<Uri> _bootstrapDependencies; |
| 151 | 154 |
| 152 CompilationCommand._(String displayName, | 155 CompilationCommand._( |
| 153 this._outputFile, | 156 String displayName, |
| 154 this._neverSkipCompilation, | 157 this._outputFile, |
| 155 this._bootstrapDependencies, | 158 this._neverSkipCompilation, |
| 156 String executable, | 159 this._bootstrapDependencies, |
| 157 List<String> arguments, | 160 String executable, |
| 158 Map<String, String> environmentOverrides) | 161 List<String> arguments, |
| 162 Map<String, String> environmentOverrides) |
| 159 : super._(displayName, executable, arguments, environmentOverrides); | 163 : super._(displayName, executable, arguments, environmentOverrides); |
| 160 | 164 |
| 161 Future<bool> get outputIsUpToDate { | 165 Future<bool> get outputIsUpToDate { |
| 162 if (_neverSkipCompilation) return new Future.value(false); | 166 if (_neverSkipCompilation) return new Future.value(false); |
| 163 | 167 |
| 164 Future<List<Uri>> readDepsFile(String path) { | 168 Future<List<Uri>> readDepsFile(String path) { |
| 165 var file = new io.File(new Path(path).toNativePath()); | 169 var file = new io.File(new Path(path).toNativePath()); |
| 166 if (!file.existsSync()) { | 170 if (!file.existsSync()) { |
| 167 return new Future.value(null); | 171 return new Future.value(null); |
| 168 } | 172 } |
| 169 return file.readAsLines().then((List<String> lines) { | 173 return file.readAsLines().then((List<String> lines) { |
| 170 var dependencies = new List<Uri>(); | 174 var dependencies = new List<Uri>(); |
| 171 for (var line in lines) { | 175 for (var line in lines) { |
| 172 line = line.trim(); | 176 line = line.trim(); |
| 173 if (line.length > 0) { | 177 if (line.length > 0) { |
| 174 dependencies.add(Uri.parse(line)); | 178 dependencies.add(Uri.parse(line)); |
| 175 } | 179 } |
| 176 } | 180 } |
| 177 return dependencies; | 181 return dependencies; |
| 178 }); | 182 }); |
| 179 } | 183 } |
| 180 | 184 |
| 181 return readDepsFile("$_outputFile.deps").then((dependencies) { | 185 return readDepsFile("$_outputFile.deps").then((dependencies) { |
| 182 if (dependencies != null) { | 186 if (dependencies != null) { |
| 183 dependencies.addAll(_bootstrapDependencies); | 187 dependencies.addAll(_bootstrapDependencies); |
| 184 var jsOutputLastModified = TestUtils.lastModifiedCache.getLastModified( | 188 var jsOutputLastModified = TestUtils.lastModifiedCache |
| 185 new Uri(scheme: 'file', path: _outputFile)); | 189 .getLastModified(new Uri(scheme: 'file', path: _outputFile)); |
| 186 if (jsOutputLastModified != null) { | 190 if (jsOutputLastModified != null) { |
| 187 for (var dependency in dependencies) { | 191 for (var dependency in dependencies) { |
| 188 var dependencyLastModified = | 192 var dependencyLastModified = |
| 189 TestUtils.lastModifiedCache.getLastModified(dependency); | 193 TestUtils.lastModifiedCache.getLastModified(dependency); |
| 190 if (dependencyLastModified == null || | 194 if (dependencyLastModified == null || |
| 191 dependencyLastModified.isAfter(jsOutputLastModified)) { | 195 dependencyLastModified.isAfter(jsOutputLastModified)) { |
| 192 return false; | 196 return false; |
| 193 } | 197 } |
| 194 } | 198 } |
| 195 return true; | 199 return true; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 213 deepJsonCompare(_bootstrapDependencies, other._bootstrapDependencies); | 217 deepJsonCompare(_bootstrapDependencies, other._bootstrapDependencies); |
| 214 } | 218 } |
| 215 | 219 |
| 216 /// This is just a Pair(String, Map) class with hashCode and operator == | 220 /// This is just a Pair(String, Map) class with hashCode and operator == |
| 217 class AddFlagsKey { | 221 class AddFlagsKey { |
| 218 final String flags; | 222 final String flags; |
| 219 final Map env; | 223 final Map env; |
| 220 AddFlagsKey(this.flags, this.env); | 224 AddFlagsKey(this.flags, this.env); |
| 221 // Just use object identity for environment map | 225 // Just use object identity for environment map |
| 222 bool operator ==(other) => | 226 bool operator ==(other) => |
| 223 other is AddFlagsKey && flags == other.flags && env == other.env; | 227 other is AddFlagsKey && flags == other.flags && env == other.env; |
| 224 int get hashCode => flags.hashCode ^ env.hashCode; | 228 int get hashCode => flags.hashCode ^ env.hashCode; |
| 225 } | 229 } |
| 226 | 230 |
| 227 class ContentShellCommand extends ProcessCommand { | 231 class ContentShellCommand extends ProcessCommand { |
| 228 ContentShellCommand._(String executable, | 232 ContentShellCommand._( |
| 229 String htmlFile, | 233 String executable, |
| 230 List<String> options, | 234 String htmlFile, |
| 231 List<String> dartFlags, | 235 List<String> options, |
| 232 Map<String, String> environmentOverrides) | 236 List<String> dartFlags, |
| 233 : super._("content_shell", | 237 Map<String, String> environmentOverrides) |
| 234 executable, | 238 : super._("content_shell", executable, _getArguments(options, htmlFile), |
| 235 _getArguments(options, htmlFile), | 239 _getEnvironment(environmentOverrides, dartFlags)); |
| 236 _getEnvironment(environmentOverrides, dartFlags)); | |
| 237 | 240 |
| 238 // Cache the modified environments in a map from the old environment and | 241 // Cache the modified environments in a map from the old environment and |
| 239 // the string of Dart flags to the new environment. Avoid creating new | 242 // the string of Dart flags to the new environment. Avoid creating new |
| 240 // environment object for each command object. | 243 // environment object for each command object. |
| 241 static Map<AddFlagsKey, Map> environments = | 244 static Map<AddFlagsKey, Map> environments = new Map<AddFlagsKey, Map>(); |
| 242 new Map<AddFlagsKey, Map>(); | |
| 243 | 245 |
| 244 static Map _getEnvironment(Map env, List<String> dartFlags) { | 246 static Map _getEnvironment(Map env, List<String> dartFlags) { |
| 245 var needDartFlags = dartFlags != null && dartFlags.length > 0; | 247 var needDartFlags = dartFlags != null && dartFlags.length > 0; |
| 246 if (needDartFlags) { | 248 if (needDartFlags) { |
| 247 if (env == null) { | 249 if (env == null) { |
| 248 env = const { }; | 250 env = const {}; |
| 249 } | 251 } |
| 250 var flags = dartFlags.join(' '); | 252 var flags = dartFlags.join(' '); |
| 251 return environments.putIfAbsent(new AddFlagsKey(flags, env), | 253 return environments.putIfAbsent( |
| 254 new AddFlagsKey(flags, env), |
| 252 () => new Map.from(env) | 255 () => new Map.from(env) |
| 253 ..addAll({'DART_FLAGS': flags, 'DART_FORWARDING_PRINT': '1'})); | 256 ..addAll({'DART_FLAGS': flags, 'DART_FORWARDING_PRINT': '1'})); |
| 254 } | 257 } |
| 255 return env; | 258 return env; |
| 256 } | 259 } |
| 257 | 260 |
| 258 static List<String> _getArguments(List<String> options, String htmlFile) { | 261 static List<String> _getArguments(List<String> options, String htmlFile) { |
| 259 var arguments = new List.from(options); | 262 var arguments = new List.from(options); |
| 260 arguments.add(htmlFile); | 263 arguments.add(htmlFile); |
| 261 return arguments; | 264 return arguments; |
| 262 } | 265 } |
| 263 | 266 |
| 264 int get maxNumRetries => 3; | 267 int get maxNumRetries => 3; |
| 265 } | 268 } |
| 266 | 269 |
| 267 class BrowserTestCommand extends Command { | 270 class BrowserTestCommand extends Command { |
| 268 final String browser; | 271 final String browser; |
| 269 final String url; | 272 final String url; |
| 270 final Map configuration; | 273 final Map configuration; |
| 271 final bool retry; | 274 final bool retry; |
| 272 | 275 |
| 273 BrowserTestCommand._(String _browser, | 276 BrowserTestCommand._( |
| 274 this.url, | 277 String _browser, this.url, this.configuration, this.retry) |
| 275 this.configuration, | 278 : super._(_browser), |
| 276 this.retry) | 279 browser = _browser; |
| 277 : super._(_browser), browser = _browser; | |
| 278 | 280 |
| 279 void _buildHashCode(HashCodeBuilder builder) { | 281 void _buildHashCode(HashCodeBuilder builder) { |
| 280 super._buildHashCode(builder); | 282 super._buildHashCode(builder); |
| 281 builder.addJson(browser); | 283 builder.addJson(browser); |
| 282 builder.addJson(url); | 284 builder.addJson(url); |
| 283 builder.add(configuration); | 285 builder.add(configuration); |
| 284 builder.add(retry); | 286 builder.add(retry); |
| 285 } | 287 } |
| 286 | 288 |
| 287 bool _equal(BrowserTestCommand other) => | 289 bool _equal(BrowserTestCommand other) => |
| 288 super._equal(other) && | 290 super._equal(other) && |
| 289 browser == other.browser && | 291 browser == other.browser && |
| 290 url == other.url && | 292 url == other.url && |
| 291 identical(configuration, other.configuration) && | 293 identical(configuration, other.configuration) && |
| 292 retry == other.retry; | 294 retry == other.retry; |
| 293 | 295 |
| 294 String get reproductionCommand { | 296 String get reproductionCommand { |
| 295 var parts = [io.Platform.resolvedExecutable, | 297 var parts = [ |
| 296 'tools/testing/dart/launch_browser.dart', | 298 io.Platform.resolvedExecutable, |
| 297 browser, | 299 'tools/testing/dart/launch_browser.dart', |
| 298 url]; | 300 browser, |
| 301 url |
| 302 ]; |
| 299 return parts.map(escapeCommandLineArgument).join(' '); | 303 return parts.map(escapeCommandLineArgument).join(' '); |
| 300 } | 304 } |
| 301 | 305 |
| 302 int get maxNumRetries => 4; | 306 int get maxNumRetries => 4; |
| 303 } | 307 } |
| 304 | 308 |
| 305 class BrowserHtmlTestCommand extends BrowserTestCommand { | 309 class BrowserHtmlTestCommand extends BrowserTestCommand { |
| 306 List<String> expectedMessages; | 310 List<String> expectedMessages; |
| 307 BrowserHtmlTestCommand._(String browser, | 311 BrowserHtmlTestCommand._(String browser, String url, Map configuration, |
| 308 String url, | 312 this.expectedMessages, bool retry) |
| 309 Map configuration, | |
| 310 this.expectedMessages, | |
| 311 bool retry) | |
| 312 : super._(browser, url, configuration, retry); | 313 : super._(browser, url, configuration, retry); |
| 313 | 314 |
| 314 void _buildHashCode(HashCodeBuilder builder) { | 315 void _buildHashCode(HashCodeBuilder builder) { |
| 315 super._buildHashCode(builder); | 316 super._buildHashCode(builder); |
| 316 builder.addJson(expectedMessages); | 317 builder.addJson(expectedMessages); |
| 317 } | 318 } |
| 318 | 319 |
| 319 bool _equal(BrowserHtmlTestCommand other) => | 320 bool _equal(BrowserHtmlTestCommand other) => |
| 320 super._equal(other) && | 321 super._equal(other) && |
| 321 identical(expectedMessages, other.expectedMessages); | 322 identical(expectedMessages, other.expectedMessages); |
| 322 } | 323 } |
| 323 | 324 |
| 324 class AnalysisCommand extends ProcessCommand { | 325 class AnalysisCommand extends ProcessCommand { |
| 325 final String flavor; | 326 final String flavor; |
| 326 | 327 |
| 327 AnalysisCommand._(this.flavor, | 328 AnalysisCommand._(this.flavor, String displayName, String executable, |
| 328 String displayName, | 329 List<String> arguments, Map<String, String> environmentOverrides) |
| 329 String executable, | |
| 330 List<String> arguments, | |
| 331 Map<String, String> environmentOverrides) | |
| 332 : super._(displayName, executable, arguments, environmentOverrides); | 330 : super._(displayName, executable, arguments, environmentOverrides); |
| 333 | 331 |
| 334 void _buildHashCode(HashCodeBuilder builder) { | 332 void _buildHashCode(HashCodeBuilder builder) { |
| 335 super._buildHashCode(builder); | 333 super._buildHashCode(builder); |
| 336 builder.addJson(flavor); | 334 builder.addJson(flavor); |
| 337 } | 335 } |
| 338 | 336 |
| 339 bool _equal(AnalysisCommand other) => | 337 bool _equal(AnalysisCommand other) => |
| 340 super._equal(other) && | 338 super._equal(other) && flavor == other.flavor; |
| 341 flavor == other.flavor; | |
| 342 } | 339 } |
| 343 | 340 |
| 344 class VmCommand extends ProcessCommand { | 341 class VmCommand extends ProcessCommand { |
| 345 VmCommand._(String executable, | 342 VmCommand._(String executable, List<String> arguments, |
| 346 List<String> arguments, | 343 Map<String, String> environmentOverrides) |
| 347 Map<String,String> environmentOverrides) | |
| 348 : super._("vm", executable, arguments, environmentOverrides); | 344 : super._("vm", executable, arguments, environmentOverrides); |
| 349 } | 345 } |
| 350 | 346 |
| 351 class JSCommandlineCommand extends ProcessCommand { | 347 class JSCommandlineCommand extends ProcessCommand { |
| 352 JSCommandlineCommand._(String displayName, | 348 JSCommandlineCommand._( |
| 353 String executable, | 349 String displayName, String executable, List<String> arguments, |
| 354 List<String> arguments, | 350 [Map<String, String> environmentOverrides = null]) |
| 355 [Map<String, String> environmentOverrides = null]) | 351 : super._(displayName, executable, arguments, environmentOverrides); |
| 356 : super._(displayName, | |
| 357 executable, | |
| 358 arguments, | |
| 359 environmentOverrides); | |
| 360 } | 352 } |
| 361 | 353 |
| 362 class PubCommand extends ProcessCommand { | 354 class PubCommand extends ProcessCommand { |
| 363 final String command; | 355 final String command; |
| 364 | 356 |
| 365 PubCommand._(String pubCommand, | 357 PubCommand._(String pubCommand, String pubExecutable, |
| 366 String pubExecutable, | 358 String pubspecYamlDirectory, String pubCacheDirectory) |
| 367 String pubspecYamlDirectory, | 359 : super._( |
| 368 String pubCacheDirectory) | 360 'pub_$pubCommand', |
| 369 : super._('pub_$pubCommand', | 361 new io.File(pubExecutable).absolute.path, |
| 370 new io.File(pubExecutable).absolute.path, | 362 [pubCommand], |
| 371 [pubCommand], | 363 {'PUB_CACHE': pubCacheDirectory}, |
| 372 {'PUB_CACHE' : pubCacheDirectory}, | 364 pubspecYamlDirectory), |
| 373 pubspecYamlDirectory), command = pubCommand; | 365 command = pubCommand; |
| 374 | 366 |
| 375 void _buildHashCode(HashCodeBuilder builder) { | 367 void _buildHashCode(HashCodeBuilder builder) { |
| 376 super._buildHashCode(builder); | 368 super._buildHashCode(builder); |
| 377 builder.addJson(command); | 369 builder.addJson(command); |
| 378 } | 370 } |
| 379 | 371 |
| 380 bool _equal(PubCommand other) => | 372 bool _equal(PubCommand other) => |
| 381 super._equal(other) && | 373 super._equal(other) && command == other.command; |
| 382 command == other.command; | |
| 383 } | 374 } |
| 384 | 375 |
| 385 /* [ScriptCommand]s are executed by dart code. */ | 376 /* [ScriptCommand]s are executed by dart code. */ |
| 386 abstract class ScriptCommand extends Command { | 377 abstract class ScriptCommand extends Command { |
| 387 ScriptCommand._(String displayName) : super._(displayName); | 378 ScriptCommand._(String displayName) : super._(displayName); |
| 388 | 379 |
| 389 Future<ScriptCommandOutputImpl> run(); | 380 Future<ScriptCommandOutputImpl> run(); |
| 390 } | 381 } |
| 391 | 382 |
| 392 class CleanDirectoryCopyCommand extends ScriptCommand { | 383 class CleanDirectoryCopyCommand extends ScriptCommand { |
| 393 final String _sourceDirectory; | 384 final String _sourceDirectory; |
| 394 final String _destinationDirectory; | 385 final String _destinationDirectory; |
| 395 | 386 |
| 396 CleanDirectoryCopyCommand._(this._sourceDirectory, this._destinationDirectory) | 387 CleanDirectoryCopyCommand._(this._sourceDirectory, this._destinationDirectory) |
| 397 : super._('dir_copy'); | 388 : super._('dir_copy'); |
| 398 | 389 |
| 399 String get reproductionCommand => | 390 String get reproductionCommand => |
| 400 "Copying '$_sourceDirectory' to '$_destinationDirectory'."; | 391 "Copying '$_sourceDirectory' to '$_destinationDirectory'."; |
| 401 | 392 |
| 402 Future<ScriptCommandOutputImpl> run() { | 393 Future<ScriptCommandOutputImpl> run() { |
| 403 var watch = new Stopwatch()..start(); | 394 var watch = new Stopwatch()..start(); |
| 404 | 395 |
| 405 var destination = new io.Directory(_destinationDirectory); | 396 var destination = new io.Directory(_destinationDirectory); |
| 406 | 397 |
| 407 return destination.exists().then((bool exists) { | 398 return destination.exists().then((bool exists) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 433 super._equal(other) && | 424 super._equal(other) && |
| 434 _sourceDirectory == other._sourceDirectory && | 425 _sourceDirectory == other._sourceDirectory && |
| 435 _destinationDirectory == other._destinationDirectory; | 426 _destinationDirectory == other._destinationDirectory; |
| 436 } | 427 } |
| 437 | 428 |
| 438 class ModifyPubspecYamlCommand extends ScriptCommand { | 429 class ModifyPubspecYamlCommand extends ScriptCommand { |
| 439 String _pubspecYamlFile; | 430 String _pubspecYamlFile; |
| 440 String _destinationFile; | 431 String _destinationFile; |
| 441 Map<String, Map> _dependencyOverrides; | 432 Map<String, Map> _dependencyOverrides; |
| 442 | 433 |
| 443 ModifyPubspecYamlCommand._(this._pubspecYamlFile, | 434 ModifyPubspecYamlCommand._( |
| 444 this._destinationFile, | 435 this._pubspecYamlFile, this._destinationFile, this._dependencyOverrides) |
| 445 this._dependencyOverrides) | 436 : super._("modify_pubspec") { |
| 446 : super._("modify_pubspec") { | |
| 447 assert(_pubspecYamlFile.endsWith("pubspec.yaml")); | 437 assert(_pubspecYamlFile.endsWith("pubspec.yaml")); |
| 448 assert(_destinationFile.endsWith("pubspec.yaml")); | 438 assert(_destinationFile.endsWith("pubspec.yaml")); |
| 449 } | 439 } |
| 450 | 440 |
| 451 String get reproductionCommand => | 441 String get reproductionCommand => |
| 452 "Adding necessary dependency overrides to '$_pubspecYamlFile' " | 442 "Adding necessary dependency overrides to '$_pubspecYamlFile' " |
| 453 "(destination = $_destinationFile)."; | 443 "(destination = $_destinationFile)."; |
| 454 | 444 |
| 455 Future<ScriptCommandOutputImpl> run() { | 445 Future<ScriptCommandOutputImpl> run() { |
| 456 var watch = new Stopwatch()..start(); | 446 var watch = new Stopwatch()..start(); |
| 457 | 447 |
| 458 var pubspecLockFile = | 448 var pubspecLockFile = _destinationFile.substring( |
| 459 _destinationFile.substring(0, _destinationFile.length - ".yaml".length) | 449 0, _destinationFile.length - ".yaml".length) + |
| 460 + ".lock"; | 450 ".lock"; |
| 461 | 451 |
| 462 var file = new io.File(_pubspecYamlFile); | 452 var file = new io.File(_pubspecYamlFile); |
| 463 var destinationFile = new io.File(_destinationFile); | 453 var destinationFile = new io.File(_destinationFile); |
| 464 var lockfile = new io.File(pubspecLockFile); | 454 var lockfile = new io.File(pubspecLockFile); |
| 465 return file.readAsString().then((String yamlString) { | 455 return file.readAsString().then((String yamlString) { |
| 466 var dependencyOverrideSection = new StringBuffer(); | 456 var dependencyOverrideSection = new StringBuffer(); |
| 467 if (_dependencyOverrides.isNotEmpty) { | 457 if (_dependencyOverrides.isNotEmpty) { |
| 468 dependencyOverrideSection.write( | 458 dependencyOverrideSection.write("\n" |
| 469 "\n" | |
| 470 "# This section was autogenerated by test.py!\n" | 459 "# This section was autogenerated by test.py!\n" |
| 471 "dependency_overrides:\n"); | 460 "dependency_overrides:\n"); |
| 472 _dependencyOverrides.forEach((String packageName, Map override) { | 461 _dependencyOverrides.forEach((String packageName, Map override) { |
| 473 dependencyOverrideSection.write(" $packageName:\n"); | 462 dependencyOverrideSection.write(" $packageName:\n"); |
| 474 override.forEach((overrideKey, overrideValue) { | 463 override.forEach((overrideKey, overrideValue) { |
| 475 dependencyOverrideSection.write( | 464 dependencyOverrideSection |
| 476 " $overrideKey: $overrideValue\n"); | 465 .write(" $overrideKey: $overrideValue\n"); |
| 477 }); | 466 }); |
| 478 }); | 467 }); |
| 479 } | 468 } |
| 480 var modifiedYamlString = "$yamlString\n$dependencyOverrideSection"; | 469 var modifiedYamlString = "$yamlString\n$dependencyOverrideSection"; |
| 481 return destinationFile.writeAsString(modifiedYamlString).then((_) { | 470 return destinationFile.writeAsString(modifiedYamlString).then((_) { |
| 482 lockfile.exists().then((bool lockfileExists) { | 471 lockfile.exists().then((bool lockfileExists) { |
| 483 if (lockfileExists) { | 472 if (lockfileExists) { |
| 484 return lockfile.delete(); | 473 return lockfile.delete(); |
| 485 } | 474 } |
| 486 }); | 475 }); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 522 | 511 |
| 523 Future<ScriptCommandOutputImpl> run() { | 512 Future<ScriptCommandOutputImpl> run() { |
| 524 var watch = new Stopwatch()..start(); | 513 var watch = new Stopwatch()..start(); |
| 525 var targetFile = new io.Directory(_target); | 514 var targetFile = new io.Directory(_target); |
| 526 return targetFile.exists().then((bool targetExists) { | 515 return targetFile.exists().then((bool targetExists) { |
| 527 if (!targetExists) { | 516 if (!targetExists) { |
| 528 throw new Exception("Target '$_target' does not exist"); | 517 throw new Exception("Target '$_target' does not exist"); |
| 529 } | 518 } |
| 530 var link = new io.Link(_link); | 519 var link = new io.Link(_link); |
| 531 | 520 |
| 532 return link.exists() | 521 return link.exists().then((bool exists) { |
| 533 .then((bool exists) { if (exists) return link.delete(); }) | 522 if (exists) return link.delete(); |
| 534 .then((_) => link.create(_target)); | 523 }).then((_) => link.create(_target)); |
| 535 }).then((_) { | 524 }).then((_) { |
| 536 return new ScriptCommandOutputImpl( | 525 return new ScriptCommandOutputImpl( |
| 537 this, Expectation.PASS, "", watch.elapsed); | 526 this, Expectation.PASS, "", watch.elapsed); |
| 538 }).catchError((error) { | 527 }).catchError((error) { |
| 539 return new ScriptCommandOutputImpl( | 528 return new ScriptCommandOutputImpl( |
| 540 this, Expectation.FAIL, "An error occured: $error.", watch.elapsed); | 529 this, Expectation.FAIL, "An error occured: $error.", watch.elapsed); |
| 541 }); | 530 }); |
| 542 } | 531 } |
| 543 | 532 |
| 544 void _buildHashCode(HashCodeBuilder builder) { | 533 void _buildHashCode(HashCodeBuilder builder) { |
| 545 super._buildHashCode(builder); | 534 super._buildHashCode(builder); |
| 546 builder.addJson(_link); | 535 builder.addJson(_link); |
| 547 builder.addJson(_target); | 536 builder.addJson(_target); |
| 548 } | 537 } |
| 549 | 538 |
| 550 bool _equal(MakeSymlinkCommand other) => | 539 bool _equal(MakeSymlinkCommand other) => |
| 551 super._equal(other) && | 540 super._equal(other) && _link == other._link && _target == other._target; |
| 552 _link == other._link && | |
| 553 _target == other._target; | |
| 554 } | 541 } |
| 555 | 542 |
| 556 class CommandBuilder { | 543 class CommandBuilder { |
| 557 static final CommandBuilder instance = new CommandBuilder._(); | 544 static final CommandBuilder instance = new CommandBuilder._(); |
| 558 | 545 |
| 559 bool _cleared = false; | 546 bool _cleared = false; |
| 560 final _cachedCommands = new Map<Command, Command>(); | 547 final _cachedCommands = new Map<Command, Command>(); |
| 561 | 548 |
| 562 CommandBuilder._(); | 549 CommandBuilder._(); |
| 563 | 550 |
| 564 void clearCommandCache() { | 551 void clearCommandCache() { |
| 565 _cachedCommands.clear(); | 552 _cachedCommands.clear(); |
| 566 _cleared = true; | 553 _cleared = true; |
| 567 } | 554 } |
| 568 | 555 |
| 569 ContentShellCommand getContentShellCommand(String executable, | 556 ContentShellCommand getContentShellCommand( |
| 570 String htmlFile, | 557 String executable, |
| 571 List<String> options, | 558 String htmlFile, |
| 572 List<String> dartFlags, | 559 List<String> options, |
| 573 Map<String, String> environment) { | 560 List<String> dartFlags, |
| 561 Map<String, String> environment) { |
| 574 ContentShellCommand command = new ContentShellCommand._( | 562 ContentShellCommand command = new ContentShellCommand._( |
| 575 executable, htmlFile, options, dartFlags, environment); | 563 executable, htmlFile, options, dartFlags, environment); |
| 576 return _getUniqueCommand(command); | 564 return _getUniqueCommand(command); |
| 577 } | 565 } |
| 578 | 566 |
| 579 BrowserTestCommand getBrowserTestCommand(String browser, | 567 BrowserTestCommand getBrowserTestCommand( |
| 580 String url, | 568 String browser, String url, Map configuration, bool retry) { |
| 581 Map configuration, | |
| 582 bool retry) { | |
| 583 var command = new BrowserTestCommand._(browser, url, configuration, retry); | 569 var command = new BrowserTestCommand._(browser, url, configuration, retry); |
| 584 return _getUniqueCommand(command); | 570 return _getUniqueCommand(command); |
| 585 } | 571 } |
| 586 | 572 |
| 587 BrowserHtmlTestCommand getBrowserHtmlTestCommand(String browser, | 573 BrowserHtmlTestCommand getBrowserHtmlTestCommand(String browser, String url, |
| 588 String url, | 574 Map configuration, List<String> expectedMessages, bool retry) { |
| 589 Map configuration, | |
| 590 List<String> expectedMessages, | |
| 591 bool retry) { | |
| 592 var command = new BrowserHtmlTestCommand._( | 575 var command = new BrowserHtmlTestCommand._( |
| 593 browser, url, configuration, expectedMessages, retry); | 576 browser, url, configuration, expectedMessages, retry); |
| 594 return _getUniqueCommand(command); | 577 return _getUniqueCommand(command); |
| 595 } | 578 } |
| 596 | 579 |
| 597 CompilationCommand getCompilationCommand(String displayName, | 580 CompilationCommand getCompilationCommand( |
| 598 outputFile, | 581 String displayName, |
| 599 neverSkipCompilation, | 582 outputFile, |
| 600 List<Uri> bootstrapDependencies, | 583 neverSkipCompilation, |
| 601 String executable, | 584 List<Uri> bootstrapDependencies, |
| 602 List<String> arguments, | 585 String executable, |
| 603 Map<String, String> environment) { | 586 List<String> arguments, |
| 604 var command = | 587 Map<String, String> environment) { |
| 605 new CompilationCommand._( | 588 var command = new CompilationCommand._( |
| 606 displayName, outputFile, neverSkipCompilation, | 589 displayName, |
| 607 bootstrapDependencies, executable, arguments, environment); | 590 outputFile, |
| 591 neverSkipCompilation, |
| 592 bootstrapDependencies, |
| 593 executable, |
| 594 arguments, |
| 595 environment); |
| 608 return _getUniqueCommand(command); | 596 return _getUniqueCommand(command); |
| 609 } | 597 } |
| 610 | 598 |
| 611 AnalysisCommand getAnalysisCommand( | 599 AnalysisCommand getAnalysisCommand( |
| 612 String displayName, executable, arguments, environmentOverrides, | 600 String displayName, executable, arguments, environmentOverrides, |
| 613 {String flavor: 'dart2analyzer'}) { | 601 {String flavor: 'dart2analyzer'}) { |
| 614 var command = new AnalysisCommand._( | 602 var command = new AnalysisCommand._( |
| 615 flavor, displayName, executable, arguments, environmentOverrides); | 603 flavor, displayName, executable, arguments, environmentOverrides); |
| 616 return _getUniqueCommand(command); | 604 return _getUniqueCommand(command); |
| 617 } | 605 } |
| 618 | 606 |
| 619 VmCommand getVmCommand(String executable, | 607 VmCommand getVmCommand(String executable, List<String> arguments, |
| 620 List<String> arguments, | 608 Map<String, String> environmentOverrides) { |
| 621 Map<String, String> environmentOverrides) { | |
| 622 var command = new VmCommand._(executable, arguments, environmentOverrides); | 609 var command = new VmCommand._(executable, arguments, environmentOverrides); |
| 623 return _getUniqueCommand(command); | 610 return _getUniqueCommand(command); |
| 624 } | 611 } |
| 625 | 612 |
| 626 Command getJSCommandlineCommand(String displayName, executable, arguments, | 613 Command getJSCommandlineCommand(String displayName, executable, arguments, |
| 627 [environment = null]) { | 614 [environment = null]) { |
| 628 var command = new JSCommandlineCommand._(displayName, executable, arguments, | 615 var command = new JSCommandlineCommand._( |
| 629 environment); | 616 displayName, executable, arguments, environment); |
| 630 return _getUniqueCommand(command); | 617 return _getUniqueCommand(command); |
| 631 } | 618 } |
| 632 | 619 |
| 633 Command getProcessCommand(String displayName, executable, arguments, | 620 Command getProcessCommand(String displayName, executable, arguments, |
| 634 [environment = null, workingDirectory = null]) { | 621 [environment = null, workingDirectory = null]) { |
| 635 var command = new ProcessCommand._(displayName, executable, arguments, | 622 var command = new ProcessCommand._( |
| 636 environment, workingDirectory); | 623 displayName, executable, arguments, environment, workingDirectory); |
| 637 return _getUniqueCommand(command); | 624 return _getUniqueCommand(command); |
| 638 } | 625 } |
| 639 | 626 |
| 640 Command getCopyCommand(String sourceDirectory, String destinationDirectory) { | 627 Command getCopyCommand(String sourceDirectory, String destinationDirectory) { |
| 641 var command = new CleanDirectoryCopyCommand._(sourceDirectory, | 628 var command = |
| 642 destinationDirectory); | 629 new CleanDirectoryCopyCommand._(sourceDirectory, destinationDirectory); |
| 643 return _getUniqueCommand(command); | 630 return _getUniqueCommand(command); |
| 644 } | 631 } |
| 645 | 632 |
| 646 Command getPubCommand(String pubCommand, | 633 Command getPubCommand(String pubCommand, String pubExecutable, |
| 647 String pubExecutable, | 634 String pubspecYamlDirectory, String pubCacheDirectory) { |
| 648 String pubspecYamlDirectory, | 635 var command = new PubCommand._( |
| 649 String pubCacheDirectory) { | 636 pubCommand, pubExecutable, pubspecYamlDirectory, pubCacheDirectory); |
| 650 var command = new PubCommand._(pubCommand, | |
| 651 pubExecutable, | |
| 652 pubspecYamlDirectory, | |
| 653 pubCacheDirectory); | |
| 654 return _getUniqueCommand(command); | 637 return _getUniqueCommand(command); |
| 655 } | 638 } |
| 656 | 639 |
| 657 Command getMakeSymlinkCommand(String link, String target) { | 640 Command getMakeSymlinkCommand(String link, String target) { |
| 658 return _getUniqueCommand(new MakeSymlinkCommand._(link, target)); | 641 return _getUniqueCommand(new MakeSymlinkCommand._(link, target)); |
| 659 } | 642 } |
| 660 | 643 |
| 661 Command getModifyPubspecCommand(String pubspecYamlFile, Map depsOverrides, | 644 Command getModifyPubspecCommand(String pubspecYamlFile, Map depsOverrides, |
| 662 {String destinationFile: null}) { | 645 {String destinationFile: null}) { |
| 663 if (destinationFile == null) destinationFile = pubspecYamlFile; | 646 if (destinationFile == null) destinationFile = pubspecYamlFile; |
| 664 return _getUniqueCommand(new ModifyPubspecYamlCommand._( | 647 return _getUniqueCommand(new ModifyPubspecYamlCommand._( |
| 665 pubspecYamlFile, destinationFile, depsOverrides)); | 648 pubspecYamlFile, destinationFile, depsOverrides)); |
| 666 } | 649 } |
| 667 | 650 |
| 668 Command _getUniqueCommand(Command command) { | 651 Command _getUniqueCommand(Command command) { |
| 669 // All Command classes implement hashCode and operator==. | 652 // All Command classes implement hashCode and operator==. |
| 670 // We check if this command has already been built. | 653 // We check if this command has already been built. |
| 671 // If so, we return the cached one. Otherwise we | 654 // If so, we return the cached one. Otherwise we |
| 672 // store the one given as [command] argument. | 655 // store the one given as [command] argument. |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 709 static final int HAS_COMPILE_ERROR = 1 << 4; | 692 static final int HAS_COMPILE_ERROR = 1 << 4; |
| 710 static final int HAS_COMPILE_ERROR_IF_CHECKED = 1 << 5; | 693 static final int HAS_COMPILE_ERROR_IF_CHECKED = 1 << 5; |
| 711 static final int EXPECT_COMPILE_ERROR = 1 << 6; | 694 static final int EXPECT_COMPILE_ERROR = 1 << 6; |
| 712 /** | 695 /** |
| 713 * A list of commands to execute. Most test cases have a single command. | 696 * A list of commands to execute. Most test cases have a single command. |
| 714 * Dart2js tests have two commands, one to compile the source and another | 697 * Dart2js tests have two commands, one to compile the source and another |
| 715 * to execute it. Some isolate tests might even have three, if they require | 698 * to execute it. Some isolate tests might even have three, if they require |
| 716 * compiling multiple sources that are run in isolation. | 699 * compiling multiple sources that are run in isolation. |
| 717 */ | 700 */ |
| 718 List<Command> commands; | 701 List<Command> commands; |
| 719 Map<Command, CommandOutput> commandOutputs = new Map<Command,CommandOutput>(); | 702 Map<Command, CommandOutput> commandOutputs = |
| 703 new Map<Command, CommandOutput>(); |
| 720 | 704 |
| 721 Map configuration; | 705 Map configuration; |
| 722 String displayName; | 706 String displayName; |
| 723 int _expectations = 0; | 707 int _expectations = 0; |
| 724 int hash = 0; | 708 int hash = 0; |
| 725 Set<Expectation> expectedOutcomes; | 709 Set<Expectation> expectedOutcomes; |
| 726 | 710 |
| 727 TestCase(this.displayName, | 711 TestCase(this.displayName, this.commands, this.configuration, |
| 728 this.commands, | 712 this.expectedOutcomes, |
| 729 this.configuration, | 713 {isNegative: false, TestInformation info: null}) { |
| 730 this.expectedOutcomes, | |
| 731 {isNegative: false, | |
| 732 TestInformation info: null}) { | |
| 733 if (isNegative || displayName.contains("negative_test")) { | 714 if (isNegative || displayName.contains("negative_test")) { |
| 734 _expectations |= IS_NEGATIVE; | 715 _expectations |= IS_NEGATIVE; |
| 735 } | 716 } |
| 736 if (info != null) { | 717 if (info != null) { |
| 737 _setExpectations(info); | 718 _setExpectations(info); |
| 738 hash = info.originTestPath.relativeTo(TestUtils.dartDir) | 719 hash = |
| 739 .toString().hashCode; | 720 info.originTestPath.relativeTo(TestUtils.dartDir).toString().hashCode; |
| 740 } | 721 } |
| 741 } | 722 } |
| 742 | 723 |
| 743 void _setExpectations(TestInformation info) { | 724 void _setExpectations(TestInformation info) { |
| 744 // We don't want to keep the entire (large) TestInformation structure, | 725 // We don't want to keep the entire (large) TestInformation structure, |
| 745 // so we copy the needed bools into flags set in a single integer. | 726 // so we copy the needed bools into flags set in a single integer. |
| 746 if (info.hasRuntimeError) _expectations |= HAS_RUNTIME_ERROR; | 727 if (info.hasRuntimeError) _expectations |= HAS_RUNTIME_ERROR; |
| 747 if (info.hasStaticWarning) _expectations |= HAS_STATIC_WARNING; | 728 if (info.hasStaticWarning) _expectations |= HAS_STATIC_WARNING; |
| 748 if (info.isNegativeIfChecked) _expectations |= IS_NEGATIVE_IF_CHECKED; | 729 if (info.isNegativeIfChecked) _expectations |= IS_NEGATIVE_IF_CHECKED; |
| 749 if (info.hasCompileError) _expectations |= HAS_COMPILE_ERROR; | 730 if (info.hasCompileError) _expectations |= HAS_COMPILE_ERROR; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 770 return !expectedOutcomes.any((expectation) { | 751 return !expectedOutcomes.any((expectation) { |
| 771 return outcome.canBeOutcomeOf(expectation); | 752 return outcome.canBeOutcomeOf(expectation); |
| 772 }); | 753 }); |
| 773 } | 754 } |
| 774 | 755 |
| 775 Expectation get result => lastCommandOutput.result(this); | 756 Expectation get result => lastCommandOutput.result(this); |
| 776 | 757 |
| 777 CommandOutput get lastCommandOutput { | 758 CommandOutput get lastCommandOutput { |
| 778 if (commandOutputs.length == 0) { | 759 if (commandOutputs.length == 0) { |
| 779 throw new Exception("CommandOutputs is empty, maybe no command was run? (" | 760 throw new Exception("CommandOutputs is empty, maybe no command was run? (" |
| 780 "displayName: '$displayName', " | 761 "displayName: '$displayName', " |
| 781 "configurationString: '$configurationString')"); | 762 "configurationString: '$configurationString')"); |
| 782 } | 763 } |
| 783 return commandOutputs[commands[commandOutputs.length - 1]]; | 764 return commandOutputs[commands[commandOutputs.length - 1]]; |
| 784 } | 765 } |
| 785 | 766 |
| 786 Command get lastCommandExecuted { | 767 Command get lastCommandExecuted { |
| 787 if (commandOutputs.length == 0) { | 768 if (commandOutputs.length == 0) { |
| 788 throw new Exception("CommandOutputs is empty, maybe no command was run? (" | 769 throw new Exception("CommandOutputs is empty, maybe no command was run? (" |
| 789 "displayName: '$displayName', " | 770 "displayName: '$displayName', " |
| 790 "configurationString: '$configurationString')"); | 771 "configurationString: '$configurationString')"); |
| 791 } | 772 } |
| 792 return commands[commandOutputs.length - 1]; | 773 return commands[commandOutputs.length - 1]; |
| 793 } | 774 } |
| 794 | 775 |
| 795 int get timeout { | 776 int get timeout { |
| 796 if (expectedOutcomes.contains(Expectation.SLOW)) { | 777 if (expectedOutcomes.contains(Expectation.SLOW)) { |
| 797 return configuration['timeout'] * SLOW_TIMEOUT_MULTIPLIER; | 778 return configuration['timeout'] * SLOW_TIMEOUT_MULTIPLIER; |
| 798 } else { | 779 } else { |
| 799 return configuration['timeout']; | 780 return configuration['timeout']; |
| 800 } | 781 } |
| 801 } | 782 } |
| 802 | 783 |
| 803 String get configurationString { | 784 String get configurationString { |
| 804 final compiler = configuration['compiler']; | 785 final compiler = configuration['compiler']; |
| 805 final runtime = configuration['runtime']; | 786 final runtime = configuration['runtime']; |
| 806 final mode = configuration['mode']; | 787 final mode = configuration['mode']; |
| 807 final arch = configuration['arch']; | 788 final arch = configuration['arch']; |
| 808 final checked = configuration['checked'] ? '-checked' : ''; | 789 final checked = configuration['checked'] ? '-checked' : ''; |
| 809 return "$compiler-$runtime$checked ${mode}_$arch"; | 790 return "$compiler-$runtime$checked ${mode}_$arch"; |
| 810 } | 791 } |
| 811 | 792 |
| 812 List<String> get batchTestArguments { | 793 List<String> get batchTestArguments { |
| 813 assert(commands.last is ProcessCommand); | 794 assert(commands.last is ProcessCommand); |
| 814 return (commands.last as ProcessCommand).arguments; | 795 return (commands.last as ProcessCommand).arguments; |
| 815 } | 796 } |
| 816 | 797 |
| 817 bool get isFlaky { | 798 bool get isFlaky { |
| 818 if (expectedOutcomes.contains(Expectation.SKIP) || | 799 if (expectedOutcomes.contains(Expectation.SKIP) || |
| 819 expectedOutcomes.contains(Expectation.SKIP_BY_DESIGN)) { | 800 expectedOutcomes.contains(Expectation.SKIP_BY_DESIGN)) { |
| 820 return false; | 801 return false; |
| 821 } | 802 } |
| 822 | 803 |
| 823 return expectedOutcomes | 804 return expectedOutcomes |
| 824 .where((expectation) => !expectation.isMetaExpectation).length > 1; | 805 .where((expectation) => !expectation.isMetaExpectation) |
| 806 .length > |
| 807 1; |
| 825 } | 808 } |
| 826 | 809 |
| 827 bool get isFinished { | 810 bool get isFinished { |
| 828 return commandOutputs.length > 0 && | 811 return commandOutputs.length > 0 && |
| 829 (!lastCommandOutput.successful || | 812 (!lastCommandOutput.successful || |
| 830 commands.length == commandOutputs.length); | 813 commands.length == commandOutputs.length); |
| 831 } | 814 } |
| 832 } | 815 } |
| 833 | 816 |
| 834 | |
| 835 /** | 817 /** |
| 836 * BrowserTestCase has an extra compilation command that is run in a separate | 818 * BrowserTestCase has an extra compilation command that is run in a separate |
| 837 * process, before the regular test is run as in the base class [TestCase]. | 819 * process, before the regular test is run as in the base class [TestCase]. |
| 838 * If the compilation command fails, then the rest of the test is not run. | 820 * If the compilation command fails, then the rest of the test is not run. |
| 839 */ | 821 */ |
| 840 class BrowserTestCase extends TestCase { | 822 class BrowserTestCase extends TestCase { |
| 841 | 823 BrowserTestCase(displayName, commands, configuration, expectedOutcomes, info, |
| 842 BrowserTestCase(displayName, commands, configuration, | 824 isNegative, this._testingUrl) |
| 843 expectedOutcomes, info, isNegative, this._testingUrl) | 825 : super(displayName, commands, configuration, expectedOutcomes, |
| 844 : super(displayName, commands, configuration, | 826 isNegative: isNegative, info: info); |
| 845 expectedOutcomes, isNegative: isNegative, info: info); | |
| 846 | 827 |
| 847 String _testingUrl; | 828 String _testingUrl; |
| 848 | 829 |
| 849 String get testingUrl => _testingUrl; | 830 String get testingUrl => _testingUrl; |
| 850 } | 831 } |
| 851 | 832 |
| 852 class UnittestSuiteMessagesMixin { | 833 class UnittestSuiteMessagesMixin { |
| 853 bool _isAsyncTest(String testOutput) { | 834 bool _isAsyncTest(String testOutput) { |
| 854 return testOutput.contains("unittest-suite-wait-for-done"); | 835 return testOutput.contains("unittest-suite-wait-for-done"); |
| 855 } | 836 } |
| 856 | 837 |
| 857 bool _isAsyncTestSuccessful(String testOutput) { | 838 bool _isAsyncTestSuccessful(String testOutput) { |
| 858 return testOutput.contains("unittest-suite-success"); | 839 return testOutput.contains("unittest-suite-success"); |
| 859 } | 840 } |
| 860 | 841 |
| 861 Expectation _negateOutcomeIfIncompleteAsyncTest(Expectation outcome, | 842 Expectation _negateOutcomeIfIncompleteAsyncTest( |
| 862 String testOutput) { | 843 Expectation outcome, String testOutput) { |
| 863 // If this is an asynchronous test and the asynchronous operation didn't | 844 // If this is an asynchronous test and the asynchronous operation didn't |
| 864 // complete successfully, it's outcome is Expectation.FAIL. | 845 // complete successfully, it's outcome is Expectation.FAIL. |
| 865 // TODO: maybe we should introduce a AsyncIncomplete marker or so | 846 // TODO: maybe we should introduce a AsyncIncomplete marker or so |
| 866 if (outcome == Expectation.PASS) { | 847 if (outcome == Expectation.PASS) { |
| 867 if (_isAsyncTest(testOutput) && | 848 if (_isAsyncTest(testOutput) && !_isAsyncTestSuccessful(testOutput)) { |
| 868 !_isAsyncTestSuccessful(testOutput)) { | |
| 869 return Expectation.FAIL; | 849 return Expectation.FAIL; |
| 870 } | 850 } |
| 871 } | 851 } |
| 872 return outcome; | 852 return outcome; |
| 873 } | 853 } |
| 874 } | 854 } |
| 875 | 855 |
| 876 /** | 856 /** |
| 877 * CommandOutput records the output of a completed command: the process's exit | 857 * CommandOutput records the output of a completed command: the process's exit |
| 878 * code, the standard output and standard error, whether the process timed out, | 858 * code, the standard output and standard error, whether the process timed out, |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 923 bool compilationSkipped; | 903 bool compilationSkipped; |
| 924 int pid; | 904 int pid; |
| 925 | 905 |
| 926 /** | 906 /** |
| 927 * A flag to indicate we have already printed a warning about ignoring the VM | 907 * A flag to indicate we have already printed a warning about ignoring the VM |
| 928 * crash, to limit the amount of output produced per test. | 908 * crash, to limit the amount of output produced per test. |
| 929 */ | 909 */ |
| 930 bool alreadyPrintedWarning = false; | 910 bool alreadyPrintedWarning = false; |
| 931 | 911 |
| 932 // TODO(kustermann): Remove testCase from this class. | 912 // TODO(kustermann): Remove testCase from this class. |
| 933 CommandOutputImpl(Command this.command, | 913 CommandOutputImpl( |
| 934 int this.exitCode, | 914 Command this.command, |
| 935 bool this.timedOut, | 915 int this.exitCode, |
| 936 List<int> this.stdout, | 916 bool this.timedOut, |
| 937 List<int> this.stderr, | 917 List<int> this.stdout, |
| 938 Duration this.time, | 918 List<int> this.stderr, |
| 939 bool this.compilationSkipped, | 919 Duration this.time, |
| 940 int this.pid) { | 920 bool this.compilationSkipped, |
| 921 int this.pid) { |
| 941 diagnostics = []; | 922 diagnostics = []; |
| 942 } | 923 } |
| 943 | 924 |
| 944 Expectation result(TestCase testCase) { | 925 Expectation result(TestCase testCase) { |
| 945 if (hasCrashed) return Expectation.CRASH; | 926 if (hasCrashed) return Expectation.CRASH; |
| 946 if (hasTimedOut) return Expectation.TIMEOUT; | 927 if (hasTimedOut) return Expectation.TIMEOUT; |
| 947 return hasFailed(testCase) ? Expectation.FAIL : Expectation.PASS; | 928 return hasFailed(testCase) ? Expectation.FAIL : Expectation.PASS; |
| 948 } | 929 } |
| 949 | 930 |
| 950 bool get hasCrashed { | 931 bool get hasCrashed { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 984 bool get successful { | 965 bool get successful { |
| 985 // FIXME(kustermann): We may need to change this | 966 // FIXME(kustermann): We may need to change this |
| 986 return !hasTimedOut && exitCode == 0; | 967 return !hasTimedOut && exitCode == 0; |
| 987 } | 968 } |
| 988 | 969 |
| 989 // Reverse result of a negative test. | 970 // Reverse result of a negative test. |
| 990 bool hasFailed(TestCase testCase) { | 971 bool hasFailed(TestCase testCase) { |
| 991 return testCase.isNegative ? !didFail(testCase) : didFail(testCase); | 972 return testCase.isNegative ? !didFail(testCase) : didFail(testCase); |
| 992 } | 973 } |
| 993 | 974 |
| 994 Expectation _negateOutcomeIfNegativeTest(Expectation outcome, | 975 Expectation _negateOutcomeIfNegativeTest( |
| 995 bool isNegative) { | 976 Expectation outcome, bool isNegative) { |
| 996 if (!isNegative) return outcome; | 977 if (!isNegative) return outcome; |
| 997 | 978 |
| 998 if (outcome.canBeOutcomeOf(Expectation.FAIL)) { | 979 if (outcome.canBeOutcomeOf(Expectation.FAIL)) { |
| 999 return Expectation.PASS; | 980 return Expectation.PASS; |
| 1000 } | 981 } |
| 1001 return Expectation.FAIL; | 982 return Expectation.FAIL; |
| 1002 } | 983 } |
| 1003 } | 984 } |
| 1004 | 985 |
| 1005 class BrowserCommandOutputImpl extends CommandOutputImpl { | 986 class BrowserCommandOutputImpl extends CommandOutputImpl { |
| 1006 // Although tests are reported as passing, content shell sometimes exits with | 987 // Although tests are reported as passing, content shell sometimes exits with |
| 1007 // a nonzero exitcode which makes our dartium builders extremely falky. | 988 // a nonzero exitcode which makes our dartium builders extremely falky. |
| 1008 // See: http://dartbug.com/15139. | 989 // See: http://dartbug.com/15139. |
| 1009 static int WHITELISTED_CONTENTSHELL_EXITCODE = -1073740022; | 990 static int WHITELISTED_CONTENTSHELL_EXITCODE = -1073740022; |
| 1010 static bool isWindows = io.Platform.operatingSystem == 'windows'; | 991 static bool isWindows = io.Platform.operatingSystem == 'windows'; |
| 1011 | 992 |
| 1012 bool _failedBecauseOfMissingXDisplay; | 993 bool _failedBecauseOfMissingXDisplay; |
| 1013 | 994 |
| 1014 BrowserCommandOutputImpl( | 995 BrowserCommandOutputImpl( |
| 1015 command, | 996 command, exitCode, timedOut, stdout, stderr, time, compilationSkipped) |
| 1016 exitCode, | 997 : super(command, exitCode, timedOut, stdout, stderr, time, |
| 1017 timedOut, | 998 compilationSkipped, 0) { |
| 1018 stdout, | |
| 1019 stderr, | |
| 1020 time, | |
| 1021 compilationSkipped) : | |
| 1022 super(command, | |
| 1023 exitCode, | |
| 1024 timedOut, | |
| 1025 stdout, | |
| 1026 stderr, | |
| 1027 time, | |
| 1028 compilationSkipped, | |
| 1029 0) { | |
| 1030 _failedBecauseOfMissingXDisplay = _didFailBecauseOfMissingXDisplay(); | 999 _failedBecauseOfMissingXDisplay = _didFailBecauseOfMissingXDisplay(); |
| 1031 if (_failedBecauseOfMissingXDisplay) { | 1000 if (_failedBecauseOfMissingXDisplay) { |
| 1032 DebugLogger.warning("Warning: Test failure because of missing XDisplay"); | 1001 DebugLogger.warning("Warning: Test failure because of missing XDisplay"); |
| 1033 // If we get the X server error, or DRT crashes with a core dump, retry | 1002 // If we get the X server error, or DRT crashes with a core dump, retry |
| 1034 // the test. | 1003 // the test. |
| 1035 } | 1004 } |
| 1036 } | 1005 } |
| 1037 | 1006 |
| 1038 Expectation result(TestCase testCase) { | 1007 Expectation result(TestCase testCase) { |
| 1039 // Handle crashes and timeouts first | 1008 // Handle crashes and timeouts first |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1121 } | 1090 } |
| 1122 break; | 1091 break; |
| 1123 } | 1092 } |
| 1124 } | 1093 } |
| 1125 if (hasContentType) { | 1094 if (hasContentType) { |
| 1126 if (containsFail && containsPass) { | 1095 if (containsFail && containsPass) { |
| 1127 DebugLogger.warning("Test had 'FAIL' and 'PASS' in stdout. ($command)"); | 1096 DebugLogger.warning("Test had 'FAIL' and 'PASS' in stdout. ($command)"); |
| 1128 } | 1097 } |
| 1129 if (!containsFail && !containsPass) { | 1098 if (!containsFail && !containsPass) { |
| 1130 DebugLogger.warning("Test had neither 'FAIL' nor 'PASS' in stdout. " | 1099 DebugLogger.warning("Test had neither 'FAIL' nor 'PASS' in stdout. " |
| 1131 "($command)"); | 1100 "($command)"); |
| 1132 return true; | 1101 return true; |
| 1133 } | 1102 } |
| 1134 if (containsFail) { | 1103 if (containsFail) { |
| 1135 return true; | 1104 return true; |
| 1136 } | 1105 } |
| 1137 assert(containsPass); | 1106 assert(containsPass); |
| 1138 if (exitCode != 0) { | 1107 if (exitCode != 0) { |
| 1139 var message = "All tests passed, but exitCode != 0. " | 1108 var message = "All tests passed, but exitCode != 0. " |
| 1140 "Actual exitcode: $exitCode. " | 1109 "Actual exitcode: $exitCode. " |
| 1141 "($command)"; | 1110 "($command)"; |
| 1142 DebugLogger.warning(message); | 1111 DebugLogger.warning(message); |
| 1143 diagnostics.add(message); | 1112 diagnostics.add(message); |
| 1144 } | 1113 } |
| 1145 return (!hasCrashed && | 1114 return (!hasCrashed && |
| 1146 exitCode != 0 && | 1115 exitCode != 0 && |
| 1147 (!isWindows || exitCode != WHITELISTED_CONTENTSHELL_EXITCODE)); | 1116 (!isWindows || exitCode != WHITELISTED_CONTENTSHELL_EXITCODE)); |
| 1148 } | 1117 } |
| 1149 DebugLogger.warning("Couldn't find 'Content-Type: text/plain' in output. " | 1118 DebugLogger.warning("Couldn't find 'Content-Type: text/plain' in output. " |
| 1150 "($command)."); | 1119 "($command)."); |
| 1151 return true; | 1120 return true; |
| 1152 } | 1121 } |
| 1153 } | 1122 } |
| 1154 | 1123 |
| 1155 class HTMLBrowserCommandOutputImpl extends BrowserCommandOutputImpl { | 1124 class HTMLBrowserCommandOutputImpl extends BrowserCommandOutputImpl { |
| 1156 HTMLBrowserCommandOutputImpl( | 1125 HTMLBrowserCommandOutputImpl( |
| 1157 command, | 1126 command, exitCode, timedOut, stdout, stderr, time, compilationSkipped) |
| 1158 exitCode, | 1127 : super(command, exitCode, timedOut, stdout, stderr, time, |
| 1159 timedOut, | 1128 compilationSkipped); |
| 1160 stdout, | |
| 1161 stderr, | |
| 1162 time, | |
| 1163 compilationSkipped) : | |
| 1164 super(command, | |
| 1165 exitCode, | |
| 1166 timedOut, | |
| 1167 stdout, | |
| 1168 stderr, | |
| 1169 time, | |
| 1170 compilationSkipped); | |
| 1171 | 1129 |
| 1172 bool didFail(TestCase testCase) { | 1130 bool didFail(TestCase testCase) { |
| 1173 return _getOutcome() != Expectation.PASS; | 1131 return _getOutcome() != Expectation.PASS; |
| 1174 } | 1132 } |
| 1175 | 1133 |
| 1176 | |
| 1177 bool get _browserTestFailure { | 1134 bool get _browserTestFailure { |
| 1178 // We should not need to convert back and forward. | 1135 // We should not need to convert back and forward. |
| 1179 var output = decodeUtf8(super.stdout); | 1136 var output = decodeUtf8(super.stdout); |
| 1180 if (output.contains("FAIL")) return true; | 1137 if (output.contains("FAIL")) return true; |
| 1181 return !output.contains("PASS"); | 1138 return !output.contains("PASS"); |
| 1182 } | 1139 } |
| 1183 } | 1140 } |
| 1184 | 1141 |
| 1185 class BrowserTestJsonResult { | 1142 class BrowserTestJsonResult { |
| 1186 static const ALLOWED_TYPES = | 1143 static const ALLOWED_TYPES = const [ |
| 1187 const ['sync_exception', 'window_onerror', 'script_onerror', | 1144 'sync_exception', |
| 1188 'window_compilationerror', 'print', 'message_received', 'dom', | 1145 'window_onerror', |
| 1189 'debug']; | 1146 'script_onerror', |
| 1147 'window_compilationerror', |
| 1148 'print', |
| 1149 'message_received', |
| 1150 'dom', |
| 1151 'debug' |
| 1152 ]; |
| 1190 | 1153 |
| 1191 final Expectation outcome; | 1154 final Expectation outcome; |
| 1192 final String htmlDom; | 1155 final String htmlDom; |
| 1193 final List events; | 1156 final List events; |
| 1194 | 1157 |
| 1195 BrowserTestJsonResult(this.outcome, this.htmlDom, this.events); | 1158 BrowserTestJsonResult(this.outcome, this.htmlDom, this.events); |
| 1196 | 1159 |
| 1197 static BrowserTestJsonResult parseFromString(String content) { | 1160 static BrowserTestJsonResult parseFromString(String content) { |
| 1198 void validate(String assertion, bool value) { | 1161 void validate(String assertion, bool value) { |
| 1199 if (!value) { | 1162 if (!value) { |
| 1200 throw "InvalidFormat sent from browser driving page: $assertion:\n\n" | 1163 throw "InvalidFormat sent from browser driving page: $assertion:\n\n" |
| 1201 "$content"; | 1164 "$content"; |
| 1202 } | 1165 } |
| 1203 } | 1166 } |
| 1204 | 1167 |
| 1205 var events; | 1168 var events; |
| 1206 try { | 1169 try { |
| 1207 events = JSON.decode(content); | 1170 events = JSON.decode(content); |
| 1208 if (events != null) { | 1171 if (events != null) { |
| 1209 validate("Message must be a List", events is List); | 1172 validate("Message must be a List", events is List); |
| 1210 | 1173 |
| 1211 Map<String, List<String>> messagesByType = {}; | 1174 Map<String, List<String>> messagesByType = {}; |
| 1212 ALLOWED_TYPES.forEach((type) => messagesByType[type] = <String>[]); | 1175 ALLOWED_TYPES.forEach((type) => messagesByType[type] = <String>[]); |
| 1213 | 1176 |
| 1214 for (var entry in events) { | 1177 for (var entry in events) { |
| 1215 validate("An entry must be a Map", entry is Map); | 1178 validate("An entry must be a Map", entry is Map); |
| 1216 | 1179 |
| 1217 var type = entry['type']; | 1180 var type = entry['type']; |
| 1218 var value = entry['value']; | 1181 var value = entry['value']; |
| 1219 var timestamp = entry['timestamp']; | 1182 var timestamp = entry['timestamp']; |
| 1220 | 1183 |
| 1221 validate("'type' of an entry must be a String", | 1184 validate("'type' of an entry must be a String", type is String); |
| 1222 type is String); | |
| 1223 validate("'type' has to be in $ALLOWED_TYPES.", | 1185 validate("'type' has to be in $ALLOWED_TYPES.", |
| 1224 ALLOWED_TYPES.contains(type)); | 1186 ALLOWED_TYPES.contains(type)); |
| 1225 validate("'timestamp' of an entry must be a number", | 1187 validate( |
| 1226 timestamp is num); | 1188 "'timestamp' of an entry must be a number", timestamp is num); |
| 1227 | 1189 |
| 1228 messagesByType[type].add(value); | 1190 messagesByType[type].add(value); |
| 1229 } | 1191 } |
| 1230 validate("The message must have exactly one 'dom' entry.", | 1192 validate("The message must have exactly one 'dom' entry.", |
| 1231 messagesByType['dom'].length == 1); | 1193 messagesByType['dom'].length == 1); |
| 1232 | 1194 |
| 1233 var dom = messagesByType['dom'][0]; | 1195 var dom = messagesByType['dom'][0]; |
| 1234 if (dom.endsWith('\n')) { | 1196 if (dom.endsWith('\n')) { |
| 1235 dom = '$dom\n'; | 1197 dom = '$dom\n'; |
| 1236 } | 1198 } |
| 1237 | 1199 |
| 1238 return new BrowserTestJsonResult( | 1200 return new BrowserTestJsonResult( |
| 1239 _getOutcome(messagesByType), dom, events); | 1201 _getOutcome(messagesByType), dom, events); |
| 1240 } | 1202 } |
| 1241 } catch(error) { | 1203 } catch (error) { |
| 1242 // If something goes wrong, we know the content was not in the correct | 1204 // If something goes wrong, we know the content was not in the correct |
| 1243 // JSON format. So we can't parse it. | 1205 // JSON format. So we can't parse it. |
| 1244 // The caller is responsible for falling back to the old way of | 1206 // The caller is responsible for falling back to the old way of |
| 1245 // determining if a test failed. | 1207 // determining if a test failed. |
| 1246 } | 1208 } |
| 1247 | 1209 |
| 1248 return null; | 1210 return null; |
| 1249 } | 1211 } |
| 1250 | 1212 |
| 1251 static Expectation _getOutcome(Map<String, List<String>> messagesByType) { | 1213 static Expectation _getOutcome(Map<String, List<String>> messagesByType) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1268 } | 1230 } |
| 1269 | 1231 |
| 1270 if (messagesByType['dom'][0].contains('FAIL')) { | 1232 if (messagesByType['dom'][0].contains('FAIL')) { |
| 1271 return Expectation.RUNTIME_ERROR; | 1233 return Expectation.RUNTIME_ERROR; |
| 1272 } | 1234 } |
| 1273 | 1235 |
| 1274 // We search for these messages in 'print' and 'message_received' because | 1236 // We search for these messages in 'print' and 'message_received' because |
| 1275 // the unittest implementation posts these messages using | 1237 // the unittest implementation posts these messages using |
| 1276 // "window.postMessage()" instead of the normal "print()" them. | 1238 // "window.postMessage()" instead of the normal "print()" them. |
| 1277 | 1239 |
| 1278 var isAsyncTest = searchForMsg(['print', 'message_received'], | 1240 var isAsyncTest = searchForMsg( |
| 1279 'unittest-suite-wait-for-done'); | 1241 ['print', 'message_received'], 'unittest-suite-wait-for-done'); |
| 1280 var isAsyncSuccess = | 1242 var isAsyncSuccess = |
| 1281 searchForMsg(['print', 'message_received'], 'unittest-suite-success') || | 1243 searchForMsg(['print', 'message_received'], 'unittest-suite-success') || |
| 1282 searchForMsg(['print', 'message_received'], 'unittest-suite-done'); | 1244 searchForMsg(['print', 'message_received'], 'unittest-suite-done'); |
| 1283 | 1245 |
| 1284 if (isAsyncTest) { | 1246 if (isAsyncTest) { |
| 1285 if (isAsyncSuccess) { | 1247 if (isAsyncSuccess) { |
| 1286 return Expectation.PASS; | 1248 return Expectation.PASS; |
| 1287 } | 1249 } |
| 1288 return Expectation.RUNTIME_ERROR; | 1250 return Expectation.RUNTIME_ERROR; |
| 1289 } | 1251 } |
| 1290 | 1252 |
| 1291 var mainStarted = | 1253 var mainStarted = |
| 1292 searchForMsg(['print', 'message_received'], 'dart-calling-main'); | 1254 searchForMsg(['print', 'message_received'], 'dart-calling-main'); |
| 1293 var mainDone = | 1255 var mainDone = |
| 1294 searchForMsg(['print', 'message_received'], 'dart-main-done'); | 1256 searchForMsg(['print', 'message_received'], 'dart-main-done'); |
| 1295 | 1257 |
| 1296 if (mainStarted && mainDone) { | 1258 if (mainStarted && mainDone) { |
| 1297 return Expectation.PASS; | 1259 return Expectation.PASS; |
| 1298 } | 1260 } |
| 1299 return Expectation.FAIL; | 1261 return Expectation.FAIL; |
| 1300 } | 1262 } |
| 1301 } | 1263 } |
| 1302 | 1264 |
| 1303 class BrowserControllerTestOutcome extends CommandOutputImpl | 1265 class BrowserControllerTestOutcome extends CommandOutputImpl |
| 1304 with UnittestSuiteMessagesMixin { | 1266 with UnittestSuiteMessagesMixin { |
| 1305 BrowserTestOutput _result; | 1267 BrowserTestOutput _result; |
| 1306 Expectation _rawOutcome; | 1268 Expectation _rawOutcome; |
| 1307 | 1269 |
| 1308 factory BrowserControllerTestOutcome(Command command, | 1270 factory BrowserControllerTestOutcome( |
| 1309 BrowserTestOutput result) { | 1271 Command command, BrowserTestOutput result) { |
| 1310 void validate(String assertion, bool value) { | 1272 void validate(String assertion, bool value) { |
| 1311 if (!value) { | 1273 if (!value) { |
| 1312 throw "InvalidFormat sent from browser driving page: $assertion:\n\n" | 1274 throw "InvalidFormat sent from browser driving page: $assertion:\n\n" |
| 1313 "${result.lastKnownMessage}"; | 1275 "${result.lastKnownMessage}"; |
| 1314 } | 1276 } |
| 1315 } | 1277 } |
| 1316 | 1278 |
| 1317 String indent(String string, int numSpaces) { | 1279 String indent(String string, int numSpaces) { |
| 1318 var spaces = new List.filled(numSpaces, ' ').join(''); | 1280 var spaces = new List.filled(numSpaces, ' ').join(''); |
| 1319 return string.replaceAll('\r\n', '\n') | 1281 return string |
| 1282 .replaceAll('\r\n', '\n') |
| 1320 .split('\n') | 1283 .split('\n') |
| 1321 .map((line) => "$spaces$line") | 1284 .map((line) => "$spaces$line") |
| 1322 .join('\n'); | 1285 .join('\n'); |
| 1323 } | 1286 } |
| 1324 | 1287 |
| 1325 String stdout = ""; | 1288 String stdout = ""; |
| 1326 String stderr = ""; | 1289 String stderr = ""; |
| 1327 Expectation outcome; | 1290 Expectation outcome; |
| 1328 | 1291 |
| 1329 var parsedResult = | 1292 var parsedResult = |
| 1330 BrowserTestJsonResult.parseFromString(result.lastKnownMessage); | 1293 BrowserTestJsonResult.parseFromString(result.lastKnownMessage); |
| 1331 if (parsedResult != null) { | 1294 if (parsedResult != null) { |
| 1332 outcome = parsedResult.outcome; | 1295 outcome = parsedResult.outcome; |
| 1333 } else { | 1296 } else { |
| 1334 // Old way of determining whether a test failed or passed. | 1297 // Old way of determining whether a test failed or passed. |
| 1335 if (result.lastKnownMessage.contains("FAIL")) { | 1298 if (result.lastKnownMessage.contains("FAIL")) { |
| 1336 outcome = Expectation.RUNTIME_ERROR; | 1299 outcome = Expectation.RUNTIME_ERROR; |
| 1337 } else if (result.lastKnownMessage.contains("PASS")) { | 1300 } else if (result.lastKnownMessage.contains("PASS")) { |
| 1338 outcome = Expectation.PASS; | 1301 outcome = Expectation.PASS; |
| 1339 } else { | 1302 } else { |
| 1340 outcome = Expectation.RUNTIME_ERROR; | 1303 outcome = Expectation.RUNTIME_ERROR; |
| 1341 } | 1304 } |
| 1342 } | 1305 } |
| 1343 | 1306 |
| 1344 if (result.didTimeout) { | 1307 if (result.didTimeout) { |
| 1345 if (result.delayUntilTestStarted != null) { | 1308 if (result.delayUntilTestStarted != null) { |
| 1346 stderr = "This test timed out. The delay until the test actually " | 1309 stderr = "This test timed out. The delay until the test actually " |
| 1347 "started was: ${result.delayUntilTestStarted}."; | 1310 "started was: ${result.delayUntilTestStarted}."; |
| 1348 } else { | 1311 } else { |
| 1349 // TODO(ricow/kustermann) as soon as we record the state periodically, | 1312 // TODO(ricow/kustermann) as soon as we record the state periodically, |
| 1350 // we will have more information and can remove this warning. | 1313 // we will have more information and can remove this warning. |
| 1351 stderr = "This test has not notified test.py that it started running. " | 1314 stderr = "This test has not notified test.py that it started running. " |
| 1352 "This could be a bug in test.py! " | 1315 "This could be a bug in test.py! " |
| 1353 "Please contact ricow/whesse"; | 1316 "Please contact ricow/whesse"; |
| 1354 } | 1317 } |
| 1355 } | 1318 } |
| 1356 | 1319 |
| 1357 if (parsedResult != null) { | 1320 if (parsedResult != null) { |
| 1358 stdout = "events:\n${indent(prettifyJson(parsedResult.events), 2)}\n\n"; | 1321 stdout = "events:\n${indent(prettifyJson(parsedResult.events), 2)}\n\n"; |
| 1359 } else { | 1322 } else { |
| 1360 stdout = "message:\n${indent(result.lastKnownMessage, 2)}\n\n"; | 1323 stdout = "message:\n${indent(result.lastKnownMessage, 2)}\n\n"; |
| 1361 } | 1324 } |
| 1362 | 1325 |
| 1363 stderr = | 1326 stderr = '$stderr\n\n' |
| 1364 '$stderr\n\n' | |
| 1365 'BrowserOutput while running the test (* EXPERIMENTAL *):\n' | 1327 'BrowserOutput while running the test (* EXPERIMENTAL *):\n' |
| 1366 'BrowserOutput.stdout:\n' | 1328 'BrowserOutput.stdout:\n' |
| 1367 '${indent(result.browserOutput.stdout.toString(), 2)}\n' | 1329 '${indent(result.browserOutput.stdout.toString(), 2)}\n' |
| 1368 'BrowserOutput.stderr:\n' | 1330 'BrowserOutput.stderr:\n' |
| 1369 '${indent(result.browserOutput.stderr.toString(), 2)}\n' | 1331 '${indent(result.browserOutput.stderr.toString(), 2)}\n' |
| 1370 '\n'; | 1332 '\n'; |
| 1371 return new BrowserControllerTestOutcome._internal( | 1333 return new BrowserControllerTestOutcome._internal( |
| 1372 command, result, outcome, encodeUtf8(stdout), encodeUtf8(stderr)); | 1334 command, result, outcome, encodeUtf8(stdout), encodeUtf8(stderr)); |
| 1373 } | 1335 } |
| 1374 | 1336 |
| 1375 BrowserControllerTestOutcome._internal( | 1337 BrowserControllerTestOutcome._internal( |
| 1376 Command command, BrowserTestOutput result, this._rawOutcome, | 1338 Command command, |
| 1377 List<int> stdout, List<int> stderr) | 1339 BrowserTestOutput result, |
| 1340 this._rawOutcome, |
| 1341 List<int> stdout, |
| 1342 List<int> stderr) |
| 1378 : super(command, 0, result.didTimeout, stdout, stderr, result.duration, | 1343 : super(command, 0, result.didTimeout, stdout, stderr, result.duration, |
| 1379 false, 0) { | 1344 false, 0) { |
| 1380 _result = result; | 1345 _result = result; |
| 1381 } | 1346 } |
| 1382 | 1347 |
| 1383 Expectation result(TestCase testCase) { | 1348 Expectation result(TestCase testCase) { |
| 1384 // Handle timeouts first | 1349 // Handle timeouts first |
| 1385 if (_result.didTimeout) return Expectation.TIMEOUT; | 1350 if (_result.didTimeout) return Expectation.TIMEOUT; |
| 1386 | 1351 |
| 1387 // Multitests are handled specially | 1352 // Multitests are handled specially |
| 1388 if (testCase.hasRuntimeError) { | 1353 if (testCase.hasRuntimeError) { |
| 1389 if (_rawOutcome == Expectation.RUNTIME_ERROR) return Expectation.PASS; | 1354 if (_rawOutcome == Expectation.RUNTIME_ERROR) return Expectation.PASS; |
| 1390 return Expectation.MISSING_RUNTIME_ERROR; | 1355 return Expectation.MISSING_RUNTIME_ERROR; |
| 1391 } | 1356 } |
| 1392 | 1357 |
| 1393 return _negateOutcomeIfNegativeTest(_rawOutcome, testCase.isNegative); | 1358 return _negateOutcomeIfNegativeTest(_rawOutcome, testCase.isNegative); |
| 1394 } | 1359 } |
| 1395 } | 1360 } |
| 1396 | 1361 |
| 1397 | |
| 1398 class AnalysisCommandOutputImpl extends CommandOutputImpl { | 1362 class AnalysisCommandOutputImpl extends CommandOutputImpl { |
| 1399 // An error line has 8 fields that look like: | 1363 // An error line has 8 fields that look like: |
| 1400 // ERROR|COMPILER|MISSING_SOURCE|file:/tmp/t.dart|15|1|24|Missing source. | 1364 // ERROR|COMPILER|MISSING_SOURCE|file:/tmp/t.dart|15|1|24|Missing source. |
| 1401 final int ERROR_LEVEL = 0; | 1365 final int ERROR_LEVEL = 0; |
| 1402 final int ERROR_TYPE = 1; | 1366 final int ERROR_TYPE = 1; |
| 1403 final int FILENAME = 3; | 1367 final int FILENAME = 3; |
| 1404 final int FORMATTED_ERROR = 7; | 1368 final int FORMATTED_ERROR = 7; |
| 1405 | 1369 |
| 1406 AnalysisCommandOutputImpl(command, | 1370 AnalysisCommandOutputImpl( |
| 1407 exitCode, | 1371 command, exitCode, timedOut, stdout, stderr, time, compilationSkipped) |
| 1408 timedOut, | 1372 : super(command, exitCode, timedOut, stdout, stderr, time, |
| 1409 stdout, | 1373 compilationSkipped, 0); |
| 1410 stderr, | |
| 1411 time, | |
| 1412 compilationSkipped) : | |
| 1413 super(command, | |
| 1414 exitCode, | |
| 1415 timedOut, | |
| 1416 stdout, | |
| 1417 stderr, | |
| 1418 time, | |
| 1419 compilationSkipped, | |
| 1420 0); | |
| 1421 | 1374 |
| 1422 Expectation result(TestCase testCase) { | 1375 Expectation result(TestCase testCase) { |
| 1423 // TODO(kustermann): If we run the analyzer not in batch mode, make sure | 1376 // TODO(kustermann): If we run the analyzer not in batch mode, make sure |
| 1424 // that command.exitCodes matches 2 (errors), 1 (warnings), 0 (no warnings, | 1377 // that command.exitCodes matches 2 (errors), 1 (warnings), 0 (no warnings, |
| 1425 // no errors) | 1378 // no errors) |
| 1426 | 1379 |
| 1427 // Handle crashes and timeouts first | 1380 // Handle crashes and timeouts first |
| 1428 if (hasCrashed) return Expectation.CRASH; | 1381 if (hasCrashed) return Expectation.CRASH; |
| 1429 if (hasTimedOut) return Expectation.TIMEOUT; | 1382 if (hasTimedOut) return Expectation.TIMEOUT; |
| 1430 | 1383 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1448 if (testCase.hasStaticWarning) { | 1401 if (testCase.hasStaticWarning) { |
| 1449 if (warnings.length > 0) { | 1402 if (warnings.length > 0) { |
| 1450 return Expectation.PASS; | 1403 return Expectation.PASS; |
| 1451 } | 1404 } |
| 1452 return Expectation.MISSING_STATIC_WARNING; | 1405 return Expectation.MISSING_STATIC_WARNING; |
| 1453 } | 1406 } |
| 1454 if (warnings.length > 0) { | 1407 if (warnings.length > 0) { |
| 1455 return Expectation.STATIC_WARNING; | 1408 return Expectation.STATIC_WARNING; |
| 1456 } | 1409 } |
| 1457 | 1410 |
| 1458 assert (errors.length == 0 && warnings.length == 0); | 1411 assert(errors.length == 0 && warnings.length == 0); |
| 1459 assert (!testCase.hasCompileError && | 1412 assert(!testCase.hasCompileError && !testCase.hasStaticWarning); |
| 1460 !testCase.hasStaticWarning); | |
| 1461 return Expectation.PASS; | 1413 return Expectation.PASS; |
| 1462 } | 1414 } |
| 1463 | 1415 |
| 1464 void parseAnalyzerOutput(List<String> outErrors, List<String> outWarnings) { | 1416 void parseAnalyzerOutput(List<String> outErrors, List<String> outWarnings) { |
| 1465 // Parse a line delimited by the | character using \ as an escape charager | 1417 // Parse a line delimited by the | character using \ as an escape charager |
| 1466 // like: FOO|BAR|FOO\|BAR|FOO\\BAZ as 4 fields: FOO BAR FOO|BAR FOO\BAZ | 1418 // like: FOO|BAR|FOO\|BAR|FOO\\BAZ as 4 fields: FOO BAR FOO|BAR FOO\BAZ |
| 1467 List<String> splitMachineError(String line) { | 1419 List<String> splitMachineError(String line) { |
| 1468 StringBuffer field = new StringBuffer(); | 1420 StringBuffer field = new StringBuffer(); |
| 1469 List<String> result = []; | 1421 List<String> result = []; |
| 1470 bool escaped = false; | 1422 bool escaped = false; |
| 1471 for (var i = 0 ; i < line.length; i++) { | 1423 for (var i = 0; i < line.length; i++) { |
| 1472 var c = line[i]; | 1424 var c = line[i]; |
| 1473 if (!escaped && c == '\\') { | 1425 if (!escaped && c == '\\') { |
| 1474 escaped = true; | 1426 escaped = true; |
| 1475 continue; | 1427 continue; |
| 1476 } | 1428 } |
| 1477 escaped = false; | 1429 escaped = false; |
| 1478 if (c == '|') { | 1430 if (c == '|') { |
| 1479 result.add(field.toString()); | 1431 result.add(field.toString()); |
| 1480 field = new StringBuffer(); | 1432 field = new StringBuffer(); |
| 1481 continue; | 1433 continue; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1496 } else if (fields[ERROR_LEVEL] == 'WARNING') { | 1448 } else if (fields[ERROR_LEVEL] == 'WARNING') { |
| 1497 outWarnings.add(fields[FORMATTED_ERROR]); | 1449 outWarnings.add(fields[FORMATTED_ERROR]); |
| 1498 } | 1450 } |
| 1499 // OK to Skip error output that doesn't match the machine format | 1451 // OK to Skip error output that doesn't match the machine format |
| 1500 } | 1452 } |
| 1501 } | 1453 } |
| 1502 } | 1454 } |
| 1503 } | 1455 } |
| 1504 | 1456 |
| 1505 class VmCommandOutputImpl extends CommandOutputImpl | 1457 class VmCommandOutputImpl extends CommandOutputImpl |
| 1506 with UnittestSuiteMessagesMixin { | 1458 with UnittestSuiteMessagesMixin { |
| 1507 static const DART_VM_EXITCODE_COMPILE_TIME_ERROR = 254; | 1459 static const DART_VM_EXITCODE_COMPILE_TIME_ERROR = 254; |
| 1508 static const DART_VM_EXITCODE_UNCAUGHT_EXCEPTION = 255; | 1460 static const DART_VM_EXITCODE_UNCAUGHT_EXCEPTION = 255; |
| 1509 | 1461 |
| 1510 VmCommandOutputImpl(Command command, int exitCode, bool timedOut, | 1462 VmCommandOutputImpl(Command command, int exitCode, bool timedOut, |
| 1511 List<int> stdout, List<int> stderr, Duration time, | 1463 List<int> stdout, List<int> stderr, Duration time, int pid) |
| 1512 int pid) | |
| 1513 : super(command, exitCode, timedOut, stdout, stderr, time, false, pid); | 1464 : super(command, exitCode, timedOut, stdout, stderr, time, false, pid); |
| 1514 | 1465 |
| 1515 Expectation result(TestCase testCase) { | 1466 Expectation result(TestCase testCase) { |
| 1516 // Handle crashes and timeouts first | 1467 // Handle crashes and timeouts first |
| 1517 if (hasCrashed) return Expectation.CRASH; | 1468 if (hasCrashed) return Expectation.CRASH; |
| 1518 if (hasTimedOut) return Expectation.TIMEOUT; | 1469 if (hasTimedOut) return Expectation.TIMEOUT; |
| 1519 | 1470 |
| 1520 // Multitests are handled specially | 1471 // Multitests are handled specially |
| 1521 if (testCase.expectCompileError) { | 1472 if (testCase.expectCompileError) { |
| 1522 if (exitCode == DART_VM_EXITCODE_COMPILE_TIME_ERROR) { | 1473 if (exitCode == DART_VM_EXITCODE_COMPILE_TIME_ERROR) { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1546 outcome = Expectation.PASS; | 1497 outcome = Expectation.PASS; |
| 1547 } | 1498 } |
| 1548 outcome = _negateOutcomeIfIncompleteAsyncTest(outcome, decodeUtf8(stdout)); | 1499 outcome = _negateOutcomeIfIncompleteAsyncTest(outcome, decodeUtf8(stdout)); |
| 1549 return _negateOutcomeIfNegativeTest(outcome, testCase.isNegative); | 1500 return _negateOutcomeIfNegativeTest(outcome, testCase.isNegative); |
| 1550 } | 1501 } |
| 1551 } | 1502 } |
| 1552 | 1503 |
| 1553 class CompilationCommandOutputImpl extends CommandOutputImpl { | 1504 class CompilationCommandOutputImpl extends CommandOutputImpl { |
| 1554 static const DART2JS_EXITCODE_CRASH = 253; | 1505 static const DART2JS_EXITCODE_CRASH = 253; |
| 1555 | 1506 |
| 1556 CompilationCommandOutputImpl(Command command, int exitCode, bool timedOut, | 1507 CompilationCommandOutputImpl( |
| 1557 List<int> stdout, List<int> stderr, Duration time, | 1508 Command command, |
| 1509 int exitCode, |
| 1510 bool timedOut, |
| 1511 List<int> stdout, |
| 1512 List<int> stderr, |
| 1513 Duration time, |
| 1558 bool compilationSkipped) | 1514 bool compilationSkipped) |
| 1559 : super(command, exitCode, timedOut, stdout, stderr, time, | 1515 : super(command, exitCode, timedOut, stdout, stderr, time, |
| 1560 compilationSkipped, 0); | 1516 compilationSkipped, 0); |
| 1561 | 1517 |
| 1562 Expectation result(TestCase testCase) { | 1518 Expectation result(TestCase testCase) { |
| 1563 // Handle general crash/timeout detection. | 1519 // Handle general crash/timeout detection. |
| 1564 if (hasCrashed) return Expectation.CRASH; | 1520 if (hasCrashed) return Expectation.CRASH; |
| 1565 if (hasTimedOut) return Expectation.TIMEOUT; | 1521 if (hasTimedOut) return Expectation.TIMEOUT; |
| 1566 | 1522 |
| 1567 // Handle dart2js specific crash detection | 1523 // Handle dart2js specific crash detection |
| 1568 if (exitCode == DART2JS_EXITCODE_CRASH || | 1524 if (exitCode == DART2JS_EXITCODE_CRASH || |
| 1569 exitCode == VmCommandOutputImpl.DART_VM_EXITCODE_COMPILE_TIME_ERROR || | 1525 exitCode == VmCommandOutputImpl.DART_VM_EXITCODE_COMPILE_TIME_ERROR || |
| 1570 exitCode == VmCommandOutputImpl.DART_VM_EXITCODE_UNCAUGHT_EXCEPTION) { | 1526 exitCode == VmCommandOutputImpl.DART_VM_EXITCODE_UNCAUGHT_EXCEPTION) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1589 return Expectation.COMPILETIME_ERROR; | 1545 return Expectation.COMPILETIME_ERROR; |
| 1590 } | 1546 } |
| 1591 | 1547 |
| 1592 Expectation outcome = | 1548 Expectation outcome = |
| 1593 exitCode == 0 ? Expectation.PASS : Expectation.COMPILETIME_ERROR; | 1549 exitCode == 0 ? Expectation.PASS : Expectation.COMPILETIME_ERROR; |
| 1594 return _negateOutcomeIfNegativeTest(outcome, testCase.isNegative); | 1550 return _negateOutcomeIfNegativeTest(outcome, testCase.isNegative); |
| 1595 } | 1551 } |
| 1596 } | 1552 } |
| 1597 | 1553 |
| 1598 class JsCommandlineOutputImpl extends CommandOutputImpl | 1554 class JsCommandlineOutputImpl extends CommandOutputImpl |
| 1599 with UnittestSuiteMessagesMixin { | 1555 with UnittestSuiteMessagesMixin { |
| 1600 JsCommandlineOutputImpl(Command command, int exitCode, bool timedOut, | 1556 JsCommandlineOutputImpl(Command command, int exitCode, bool timedOut, |
| 1601 List<int> stdout, List<int> stderr, Duration time) | 1557 List<int> stdout, List<int> stderr, Duration time) |
| 1602 : super(command, exitCode, timedOut, stdout, stderr, time, false, 0); | 1558 : super(command, exitCode, timedOut, stdout, stderr, time, false, 0); |
| 1603 | 1559 |
| 1604 Expectation result(TestCase testCase) { | 1560 Expectation result(TestCase testCase) { |
| 1605 // Handle crashes and timeouts first | 1561 // Handle crashes and timeouts first |
| 1606 if (hasCrashed) return Expectation.CRASH; | 1562 if (hasCrashed) return Expectation.CRASH; |
| 1607 if (hasTimedOut) return Expectation.TIMEOUT; | 1563 if (hasTimedOut) return Expectation.TIMEOUT; |
| 1608 | 1564 |
| 1609 if (testCase.hasRuntimeError) { | 1565 if (testCase.hasRuntimeError) { |
| 1610 if (exitCode != 0) return Expectation.PASS; | 1566 if (exitCode != 0) return Expectation.PASS; |
| 1611 return Expectation.MISSING_RUNTIME_ERROR; | 1567 return Expectation.MISSING_RUNTIME_ERROR; |
| 1612 } | 1568 } |
| 1613 | 1569 |
| 1614 var outcome = exitCode == 0 ? Expectation.PASS : Expectation.RUNTIME_ERROR; | 1570 var outcome = exitCode == 0 ? Expectation.PASS : Expectation.RUNTIME_ERROR; |
| 1615 outcome = _negateOutcomeIfIncompleteAsyncTest(outcome, decodeUtf8(stdout)); | 1571 outcome = _negateOutcomeIfIncompleteAsyncTest(outcome, decodeUtf8(stdout)); |
| 1616 return _negateOutcomeIfNegativeTest(outcome, testCase.isNegative); | 1572 return _negateOutcomeIfNegativeTest(outcome, testCase.isNegative); |
| 1617 } | 1573 } |
| 1618 } | 1574 } |
| 1619 | 1575 |
| 1620 class PubCommandOutputImpl extends CommandOutputImpl { | 1576 class PubCommandOutputImpl extends CommandOutputImpl { |
| 1621 PubCommandOutputImpl(PubCommand command, int exitCode, bool timedOut, | 1577 PubCommandOutputImpl(PubCommand command, int exitCode, bool timedOut, |
| 1622 List<int> stdout, List<int> stderr, Duration time) | 1578 List<int> stdout, List<int> stderr, Duration time) |
| 1623 : super(command, exitCode, timedOut, stdout, stderr, time, false, 0); | 1579 : super(command, exitCode, timedOut, stdout, stderr, time, false, 0); |
| 1624 | 1580 |
| 1625 Expectation result(TestCase testCase) { | 1581 Expectation result(TestCase testCase) { |
| 1626 // Handle crashes and timeouts first | 1582 // Handle crashes and timeouts first |
| 1627 if (hasCrashed) return Expectation.CRASH; | 1583 if (hasCrashed) return Expectation.CRASH; |
| 1628 if (hasTimedOut) return Expectation.TIMEOUT; | 1584 if (hasTimedOut) return Expectation.TIMEOUT; |
| 1629 | 1585 |
| 1630 if (exitCode == 0) { | 1586 if (exitCode == 0) { |
| 1631 return Expectation.PASS; | 1587 return Expectation.PASS; |
| 1632 } else if ((command as PubCommand).command == 'get') { | 1588 } else if ((command as PubCommand).command == 'get') { |
| 1633 return Expectation.PUB_GET_ERROR; | 1589 return Expectation.PUB_GET_ERROR; |
| 1634 } else { | 1590 } else { |
| 1635 return Expectation.FAIL; | 1591 return Expectation.FAIL; |
| 1636 } | 1592 } |
| 1637 } | 1593 } |
| 1638 } | 1594 } |
| 1639 | 1595 |
| 1640 class ScriptCommandOutputImpl extends CommandOutputImpl { | 1596 class ScriptCommandOutputImpl extends CommandOutputImpl { |
| 1641 final Expectation _result; | 1597 final Expectation _result; |
| 1642 | 1598 |
| 1643 ScriptCommandOutputImpl(ScriptCommand command, this._result, | 1599 ScriptCommandOutputImpl(ScriptCommand command, this._result, |
| 1644 String scriptExecutionInformation, Duration time) | 1600 String scriptExecutionInformation, Duration time) |
| 1645 : super(command, 0, false, [], [], time, false, 0) { | 1601 : super(command, 0, false, [], [], time, false, 0) { |
| 1646 var lines = scriptExecutionInformation.split("\n"); | 1602 var lines = scriptExecutionInformation.split("\n"); |
| 1647 diagnostics.addAll(lines); | 1603 diagnostics.addAll(lines); |
| 1648 } | 1604 } |
| 1649 | 1605 |
| 1650 Expectation result(TestCase testCase) => _result; | 1606 Expectation result(TestCase testCase) => _result; |
| 1651 | 1607 |
| 1652 bool get canRunDependendCommands => _result == Expectation.PASS; | 1608 bool get canRunDependendCommands => _result == Expectation.PASS; |
| 1653 | 1609 |
| 1654 bool get successful => _result == Expectation.PASS; | 1610 bool get successful => _result == Expectation.PASS; |
| 1655 | |
| 1656 } | 1611 } |
| 1657 | 1612 |
| 1658 CommandOutput createCommandOutput(Command command, | 1613 CommandOutput createCommandOutput(Command command, int exitCode, bool timedOut, |
| 1659 int exitCode, | 1614 List<int> stdout, List<int> stderr, Duration time, bool compilationSkipped, |
| 1660 bool timedOut, | 1615 [int pid = 0]) { |
| 1661 List<int> stdout, | |
| 1662 List<int> stderr, | |
| 1663 Duration time, | |
| 1664 bool compilationSkipped, | |
| 1665 [int pid = 0]) { | |
| 1666 if (command is ContentShellCommand) { | 1616 if (command is ContentShellCommand) { |
| 1667 return new BrowserCommandOutputImpl( | 1617 return new BrowserCommandOutputImpl( |
| 1668 command, exitCode, timedOut, stdout, stderr, | 1618 command, exitCode, timedOut, stdout, stderr, time, compilationSkipped); |
| 1669 time, compilationSkipped); | |
| 1670 } else if (command is BrowserTestCommand) { | 1619 } else if (command is BrowserTestCommand) { |
| 1671 return new HTMLBrowserCommandOutputImpl( | 1620 return new HTMLBrowserCommandOutputImpl( |
| 1672 command, exitCode, timedOut, stdout, stderr, | 1621 command, exitCode, timedOut, stdout, stderr, time, compilationSkipped); |
| 1673 time, compilationSkipped); | |
| 1674 } else if (command is AnalysisCommand) { | 1622 } else if (command is AnalysisCommand) { |
| 1675 return new AnalysisCommandOutputImpl( | 1623 return new AnalysisCommandOutputImpl( |
| 1676 command, exitCode, timedOut, stdout, stderr, | 1624 command, exitCode, timedOut, stdout, stderr, time, compilationSkipped); |
| 1677 time, compilationSkipped); | |
| 1678 } else if (command is VmCommand) { | 1625 } else if (command is VmCommand) { |
| 1679 return new VmCommandOutputImpl( | 1626 return new VmCommandOutputImpl( |
| 1680 command, exitCode, timedOut, stdout, stderr, time, pid); | 1627 command, exitCode, timedOut, stdout, stderr, time, pid); |
| 1681 } else if (command is CompilationCommand) { | 1628 } else if (command is CompilationCommand) { |
| 1682 if (command.displayName == 'precompiler' || | 1629 if (command.displayName == 'precompiler' || |
| 1683 command.displayName == 'dart2snapshot') { | 1630 command.displayName == 'dart2snapshot') { |
| 1684 return new VmCommandOutputImpl( | 1631 return new VmCommandOutputImpl( |
| 1685 command, exitCode, timedOut, stdout, stderr, time, pid); | 1632 command, exitCode, timedOut, stdout, stderr, time, pid); |
| 1686 } | 1633 } |
| 1687 return new CompilationCommandOutputImpl( | 1634 return new CompilationCommandOutputImpl( |
| 1688 command, exitCode, timedOut, stdout, stderr, time, compilationSkipped); | 1635 command, exitCode, timedOut, stdout, stderr, time, compilationSkipped); |
| 1689 } else if (command is JSCommandlineCommand) { | 1636 } else if (command is JSCommandlineCommand) { |
| 1690 return new JsCommandlineOutputImpl( | 1637 return new JsCommandlineOutputImpl( |
| 1691 command, exitCode, timedOut, stdout, stderr, time); | 1638 command, exitCode, timedOut, stdout, stderr, time); |
| 1692 } else if (command is PubCommand) { | 1639 } else if (command is PubCommand) { |
| 1693 return new PubCommandOutputImpl( | 1640 return new PubCommandOutputImpl( |
| 1694 command, exitCode, timedOut, stdout, stderr, time); | 1641 command, exitCode, timedOut, stdout, stderr, time); |
| 1695 } | 1642 } |
| 1696 | 1643 |
| 1697 return new CommandOutputImpl( | 1644 return new CommandOutputImpl(command, exitCode, timedOut, stdout, stderr, |
| 1698 command, exitCode, timedOut, stdout, stderr, | |
| 1699 time, compilationSkipped, pid); | 1645 time, compilationSkipped, pid); |
| 1700 } | 1646 } |
| 1701 | 1647 |
| 1702 | |
| 1703 /** | 1648 /** |
| 1704 * An OutputLog records the output from a test, but truncates it if | 1649 * An OutputLog records the output from a test, but truncates it if |
| 1705 * it is longer than MAX_HEAD characters, and just keeps the head and | 1650 * it is longer than MAX_HEAD characters, and just keeps the head and |
| 1706 * the last TAIL_LENGTH characters of the output. | 1651 * the last TAIL_LENGTH characters of the output. |
| 1707 */ | 1652 */ |
| 1708 class OutputLog { | 1653 class OutputLog { |
| 1709 static const int MAX_HEAD = 100 * 1024; | 1654 static const int MAX_HEAD = 100 * 1024; |
| 1710 static const int TAIL_LENGTH = 10 * 1024; | 1655 static const int TAIL_LENGTH = 10 * 1024; |
| 1711 List<int> head = <int>[]; | 1656 List<int> head = <int>[]; |
| 1712 List<int> tail; | 1657 List<int> tail; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1727 } | 1672 } |
| 1728 } else { | 1673 } else { |
| 1729 tail.addAll(data); | 1674 tail.addAll(data); |
| 1730 } | 1675 } |
| 1731 if (tail != null && tail.length > 2 * TAIL_LENGTH) { | 1676 if (tail != null && tail.length > 2 * TAIL_LENGTH) { |
| 1732 tail = _truncatedTail(); | 1677 tail = _truncatedTail(); |
| 1733 dataDropped = true; | 1678 dataDropped = true; |
| 1734 } | 1679 } |
| 1735 } | 1680 } |
| 1736 | 1681 |
| 1737 List<int> _truncatedTail() => | 1682 List<int> _truncatedTail() => tail.length > TAIL_LENGTH |
| 1738 tail.length > TAIL_LENGTH ? | 1683 ? tail.sublist(tail.length - TAIL_LENGTH) |
| 1739 tail.sublist(tail.length - TAIL_LENGTH) : | 1684 : tail; |
| 1740 tail; | |
| 1741 | 1685 |
| 1742 List<int> toList() { | 1686 List<int> toList() { |
| 1743 if (complete == null) { | 1687 if (complete == null) { |
| 1744 complete = head; | 1688 complete = head; |
| 1745 if (dataDropped) { | 1689 if (dataDropped) { |
| 1746 complete.addAll(""" | 1690 complete.addAll(""" |
| 1747 | 1691 |
| 1748 ***************************************************************************** | 1692 ***************************************************************************** |
| 1749 | 1693 |
| 1750 Data removed due to excessive length | 1694 Data removed due to excessive length |
| 1751 | 1695 |
| 1752 ***************************************************************************** | 1696 ***************************************************************************** |
| 1753 | 1697 |
| 1754 """.codeUnits); | 1698 """ |
| 1699 .codeUnits); |
| 1755 complete.addAll(_truncatedTail()); | 1700 complete.addAll(_truncatedTail()); |
| 1756 } else if (tail != null) { | 1701 } else if (tail != null) { |
| 1757 complete.addAll(tail); | 1702 complete.addAll(tail); |
| 1758 } | 1703 } |
| 1759 head = null; | 1704 head = null; |
| 1760 tail = null; | 1705 tail = null; |
| 1761 } | 1706 } |
| 1762 return complete; | 1707 return complete; |
| 1763 } | 1708 } |
| 1764 } | 1709 } |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1794 return completer.future; | 1739 return completer.future; |
| 1795 } | 1740 } |
| 1796 | 1741 |
| 1797 void _runCommand() { | 1742 void _runCommand() { |
| 1798 command.outputIsUpToDate.then((bool isUpToDate) { | 1743 command.outputIsUpToDate.then((bool isUpToDate) { |
| 1799 if (isUpToDate) { | 1744 if (isUpToDate) { |
| 1800 compilationSkipped = true; | 1745 compilationSkipped = true; |
| 1801 _commandComplete(0); | 1746 _commandComplete(0); |
| 1802 } else { | 1747 } else { |
| 1803 var processEnvironment = _createProcessEnvironment(); | 1748 var processEnvironment = _createProcessEnvironment(); |
| 1804 Future processFuture = | 1749 Future processFuture = io.Process.start( |
| 1805 io.Process.start(command.executable, | 1750 command.executable, command.arguments, |
| 1806 command.arguments, | 1751 environment: processEnvironment, |
| 1807 environment: processEnvironment, | 1752 workingDirectory: command.workingDirectory); |
| 1808 workingDirectory: command.workingDirectory); | |
| 1809 processFuture.then((io.Process process) { | 1753 processFuture.then((io.Process process) { |
| 1810 StreamSubscription stdoutSubscription = | 1754 StreamSubscription stdoutSubscription = |
| 1811 _drainStream(process.stdout, stdout); | 1755 _drainStream(process.stdout, stdout); |
| 1812 StreamSubscription stderrSubscription = | 1756 StreamSubscription stderrSubscription = |
| 1813 _drainStream(process.stderr, stderr); | 1757 _drainStream(process.stderr, stderr); |
| 1814 | 1758 |
| 1815 var stdoutCompleter = new Completer(); | 1759 var stdoutCompleter = new Completer(); |
| 1816 var stderrCompleter = new Completer(); | 1760 var stderrCompleter = new Completer(); |
| 1817 | 1761 |
| 1818 bool stdoutDone = false; | 1762 bool stdoutDone = false; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1864 DebugLogger.warning( | 1808 DebugLogger.warning( |
| 1865 "$MAX_STDIO_DELAY_PASSED_MESSAGE (command: $command)"); | 1809 "$MAX_STDIO_DELAY_PASSED_MESSAGE (command: $command)"); |
| 1866 watchdogTimer = null; | 1810 watchdogTimer = null; |
| 1867 stdoutSubscription.cancel(); | 1811 stdoutSubscription.cancel(); |
| 1868 stderrSubscription.cancel(); | 1812 stderrSubscription.cancel(); |
| 1869 closeStdout(); | 1813 closeStdout(); |
| 1870 closeStderr(); | 1814 closeStderr(); |
| 1871 }); | 1815 }); |
| 1872 } | 1816 } |
| 1873 | 1817 |
| 1874 Future.wait([stdoutCompleter.future, | 1818 Future.wait([stdoutCompleter.future, stderrCompleter.future]).then( |
| 1875 stderrCompleter.future]).then((_) { | 1819 (_) { |
| 1876 _commandComplete(exitCode); | 1820 _commandComplete(exitCode); |
| 1877 }); | 1821 }); |
| 1878 }); | 1822 }); |
| 1879 | 1823 |
| 1880 timeoutTimer = new Timer(new Duration(seconds: timeout), | 1824 timeoutTimer = |
| 1881 timeoutHandler); | 1825 new Timer(new Duration(seconds: timeout), timeoutHandler); |
| 1882 }).catchError((e) { | 1826 }).catchError((e) { |
| 1883 // TODO(floitsch): should we try to report the stacktrace? | 1827 // TODO(floitsch): should we try to report the stacktrace? |
| 1884 print("Process error:"); | 1828 print("Process error:"); |
| 1885 print(" Command: $command"); | 1829 print(" Command: $command"); |
| 1886 print(" Error: $e"); | 1830 print(" Error: $e"); |
| 1887 _commandComplete(-1); | 1831 _commandComplete(-1); |
| 1888 return true; | 1832 return true; |
| 1889 }); | 1833 }); |
| 1890 } | 1834 } |
| 1891 }); | 1835 }); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1905 exitCode, | 1849 exitCode, |
| 1906 timedOut, | 1850 timedOut, |
| 1907 stdout.toList(), | 1851 stdout.toList(), |
| 1908 stderr.toList(), | 1852 stderr.toList(), |
| 1909 new DateTime.now().difference(startTime), | 1853 new DateTime.now().difference(startTime), |
| 1910 compilationSkipped, | 1854 compilationSkipped, |
| 1911 pid); | 1855 pid); |
| 1912 return commandOutput; | 1856 return commandOutput; |
| 1913 } | 1857 } |
| 1914 | 1858 |
| 1915 StreamSubscription _drainStream(Stream<List<int>> source, | 1859 StreamSubscription _drainStream( |
| 1916 OutputLog destination) { | 1860 Stream<List<int>> source, OutputLog destination) { |
| 1917 return source.listen(destination.add); | 1861 return source.listen(destination.add); |
| 1918 } | 1862 } |
| 1919 | 1863 |
| 1920 Map<String, String> _createProcessEnvironment() { | 1864 Map<String, String> _createProcessEnvironment() { |
| 1921 var environment = new Map.from(io.Platform.environment); | 1865 var environment = new Map.from(io.Platform.environment); |
| 1922 | 1866 |
| 1923 if (command.environmentOverrides != null) { | 1867 if (command.environmentOverrides != null) { |
| 1924 for (var key in command.environmentOverrides.keys) { | 1868 for (var key in command.environmentOverrides.keys) { |
| 1925 environment[key] = command.environmentOverrides[key]; | 1869 environment[key] = command.environmentOverrides[key]; |
| 1926 } | 1870 } |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1950 bool _currentlyRunning = false; | 1894 bool _currentlyRunning = false; |
| 1951 OutputLog _testStdout; | 1895 OutputLog _testStdout; |
| 1952 OutputLog _testStderr; | 1896 OutputLog _testStderr; |
| 1953 String _status; | 1897 String _status; |
| 1954 DateTime _startTime; | 1898 DateTime _startTime; |
| 1955 Timer _timer; | 1899 Timer _timer; |
| 1956 | 1900 |
| 1957 BatchRunnerProcess(); | 1901 BatchRunnerProcess(); |
| 1958 | 1902 |
| 1959 Future<CommandOutput> runCommand(String runnerType, ProcessCommand command, | 1903 Future<CommandOutput> runCommand(String runnerType, ProcessCommand command, |
| 1960 int timeout, List<String> arguments) { | 1904 int timeout, List<String> arguments) { |
| 1961 assert(_completer == null); | 1905 assert(_completer == null); |
| 1962 assert(!_currentlyRunning); | 1906 assert(!_currentlyRunning); |
| 1963 | 1907 |
| 1964 _completer = new Completer<CommandOutput>(); | 1908 _completer = new Completer<CommandOutput>(); |
| 1965 bool sameRunnerType = _runnerType == runnerType && | 1909 bool sameRunnerType = _runnerType == runnerType && |
| 1966 _dictEquals(_processEnvironmentOverrides, command.environmentOverrides); | 1910 _dictEquals(_processEnvironmentOverrides, command.environmentOverrides); |
| 1967 _runnerType = runnerType; | 1911 _runnerType = runnerType; |
| 1968 _currentlyRunning = true; | 1912 _currentlyRunning = true; |
| 1969 _command = command; | 1913 _command = command; |
| 1970 _arguments = arguments; | 1914 _arguments = arguments; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2004 return terminateCompleter.future; | 1948 return terminateCompleter.future; |
| 2005 } | 1949 } |
| 2006 | 1950 |
| 2007 void doStartTest(Command command, int timeout) { | 1951 void doStartTest(Command command, int timeout) { |
| 2008 _startTime = new DateTime.now(); | 1952 _startTime = new DateTime.now(); |
| 2009 _testStdout = new OutputLog(); | 1953 _testStdout = new OutputLog(); |
| 2010 _testStderr = new OutputLog(); | 1954 _testStderr = new OutputLog(); |
| 2011 _status = null; | 1955 _status = null; |
| 2012 _stdoutCompleter = new Completer(); | 1956 _stdoutCompleter = new Completer(); |
| 2013 _stderrCompleter = new Completer(); | 1957 _stderrCompleter = new Completer(); |
| 2014 _timer = new Timer(new Duration(seconds: timeout), | 1958 _timer = new Timer(new Duration(seconds: timeout), _timeoutHandler); |
| 2015 _timeoutHandler); | |
| 2016 | 1959 |
| 2017 var line = _createArgumentsLine(_arguments, timeout); | 1960 var line = _createArgumentsLine(_arguments, timeout); |
| 2018 _process.stdin.write(line); | 1961 _process.stdin.write(line); |
| 2019 _stdoutSubscription.resume(); | 1962 _stdoutSubscription.resume(); |
| 2020 _stderrSubscription.resume(); | 1963 _stderrSubscription.resume(); |
| 2021 Future.wait([_stdoutCompleter.future, | 1964 Future.wait([_stdoutCompleter.future, _stderrCompleter.future]).then( |
| 2022 _stderrCompleter.future]).then((_) => _reportResult()); | 1965 (_) => _reportResult()); |
| 2023 } | 1966 } |
| 2024 | 1967 |
| 2025 String _createArgumentsLine(List<String> arguments, int timeout) { | 1968 String _createArgumentsLine(List<String> arguments, int timeout) { |
| 2026 return arguments.join(' ') + '\n'; | 1969 return arguments.join(' ') + '\n'; |
| 2027 } | 1970 } |
| 2028 | 1971 |
| 2029 void _reportResult() { | 1972 void _reportResult() { |
| 2030 if (!_currentlyRunning) return; | 1973 if (!_currentlyRunning) return; |
| 2031 // _status == '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}' | 1974 // _status == '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}' |
| 2032 | 1975 |
| 2033 var outcome = _status.split(" ")[2]; | 1976 var outcome = _status.split(" ")[2]; |
| 2034 var exitCode = 0; | 1977 var exitCode = 0; |
| 2035 if (outcome == "CRASH") exitCode = CRASHING_BROWSER_EXITCODE; | 1978 if (outcome == "CRASH") exitCode = CRASHING_BROWSER_EXITCODE; |
| 2036 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1; | 1979 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1; |
| 2037 var output = createCommandOutput(_command, | 1980 var output = createCommandOutput( |
| 2038 exitCode, | 1981 _command, |
| 2039 (outcome == "TIMEOUT"), | 1982 exitCode, |
| 2040 _testStdout.toList(), | 1983 (outcome == "TIMEOUT"), |
| 2041 _testStderr.toList(), | 1984 _testStdout.toList(), |
| 2042 new DateTime.now().difference(_startTime), | 1985 _testStderr.toList(), |
| 2043 false); | 1986 new DateTime.now().difference(_startTime), |
| 1987 false); |
| 2044 assert(_completer != null); | 1988 assert(_completer != null); |
| 2045 _completer.complete(output); | 1989 _completer.complete(output); |
| 2046 _completer = null; | 1990 _completer = null; |
| 2047 _currentlyRunning = false; | 1991 _currentlyRunning = false; |
| 2048 } | 1992 } |
| 2049 | 1993 |
| 2050 ExitCodeEvent makeExitHandler(String status) { | 1994 ExitCodeEvent makeExitHandler(String status) { |
| 2051 void handler(int exitCode) { | 1995 void handler(int exitCode) { |
| 2052 if (_currentlyRunning) { | 1996 if (_currentlyRunning) { |
| 2053 if (_timer != null) _timer.cancel(); | 1997 if (_timer != null) _timer.cancel(); |
| 2054 _status = status; | 1998 _status = status; |
| 2055 _stdoutSubscription.cancel(); | 1999 _stdoutSubscription.cancel(); |
| 2056 _stderrSubscription.cancel(); | 2000 _stderrSubscription.cancel(); |
| 2057 _startProcess(_reportResult); | 2001 _startProcess(_reportResult); |
| 2058 } else { // No active test case running. | 2002 } else { |
| 2003 // No active test case running. |
| 2059 _process = null; | 2004 _process = null; |
| 2060 } | 2005 } |
| 2061 } | 2006 } |
| 2062 return handler; | 2007 return handler; |
| 2063 } | 2008 } |
| 2064 | 2009 |
| 2065 void _timeoutHandler() { | 2010 void _timeoutHandler() { |
| 2066 _processExitHandler = makeExitHandler(">>> TEST TIMEOUT"); | 2011 _processExitHandler = makeExitHandler(">>> TEST TIMEOUT"); |
| 2067 _process.kill(); | 2012 _process.kill(); |
| 2068 } | 2013 } |
| 2069 | 2014 |
| 2070 _startProcess(callback) { | 2015 _startProcess(callback) { |
| 2071 assert(_command is ProcessCommand); | 2016 assert(_command is ProcessCommand); |
| 2072 var executable = _command.executable; | 2017 var executable = _command.executable; |
| 2073 var arguments = ['--batch']; | 2018 var arguments = ['--batch']; |
| 2074 var environment = new Map.from(io.Platform.environment); | 2019 var environment = new Map.from(io.Platform.environment); |
| 2075 if (_processEnvironmentOverrides != null) { | 2020 if (_processEnvironmentOverrides != null) { |
| 2076 for (var key in _processEnvironmentOverrides.keys) { | 2021 for (var key in _processEnvironmentOverrides.keys) { |
| 2077 environment[key] = _processEnvironmentOverrides[key]; | 2022 environment[key] = _processEnvironmentOverrides[key]; |
| 2078 } | 2023 } |
| 2079 } | 2024 } |
| 2080 Future processFuture = io.Process.start(executable, | 2025 Future processFuture = |
| 2081 arguments, | 2026 io.Process.start(executable, arguments, environment: environment); |
| 2082 environment: environment); | |
| 2083 processFuture.then((io.Process p) { | 2027 processFuture.then((io.Process p) { |
| 2084 _process = p; | 2028 _process = p; |
| 2085 | 2029 |
| 2086 var _stdoutStream = | 2030 var _stdoutStream = |
| 2087 _process.stdout | 2031 _process.stdout.transform(UTF8.decoder).transform(new LineSplitter()); |
| 2088 .transform(UTF8.decoder) | |
| 2089 .transform(new LineSplitter()); | |
| 2090 _stdoutSubscription = _stdoutStream.listen((String line) { | 2032 _stdoutSubscription = _stdoutStream.listen((String line) { |
| 2091 if (line.startsWith('>>> TEST')) { | 2033 if (line.startsWith('>>> TEST')) { |
| 2092 _status = line; | 2034 _status = line; |
| 2093 } else if (line.startsWith('>>> BATCH')) { | 2035 } else if (line.startsWith('>>> BATCH')) { |
| 2094 // ignore | 2036 // ignore |
| 2095 } else if (line.startsWith('>>> ')) { | 2037 } else if (line.startsWith('>>> ')) { |
| 2096 throw new Exception("Unexpected command from batch runner: '$line'."); | 2038 throw new Exception("Unexpected command from batch runner: '$line'."); |
| 2097 } else { | 2039 } else { |
| 2098 _testStdout.add(encodeUtf8(line)); | 2040 _testStdout.add(encodeUtf8(line)); |
| 2099 _testStdout.add("\n".codeUnits); | 2041 _testStdout.add("\n".codeUnits); |
| 2100 } | 2042 } |
| 2101 if (_status != null) { | 2043 if (_status != null) { |
| 2102 _stdoutSubscription.pause(); | 2044 _stdoutSubscription.pause(); |
| 2103 _timer.cancel(); | 2045 _timer.cancel(); |
| 2104 _stdoutCompleter.complete(null); | 2046 _stdoutCompleter.complete(null); |
| 2105 } | 2047 } |
| 2106 }); | 2048 }); |
| 2107 _stdoutSubscription.pause(); | 2049 _stdoutSubscription.pause(); |
| 2108 | 2050 |
| 2109 var _stderrStream = | 2051 var _stderrStream = |
| 2110 _process.stderr | 2052 _process.stderr.transform(UTF8.decoder).transform(new LineSplitter()); |
| 2111 .transform(UTF8.decoder) | |
| 2112 .transform(new LineSplitter()); | |
| 2113 _stderrSubscription = _stderrStream.listen((String line) { | 2053 _stderrSubscription = _stderrStream.listen((String line) { |
| 2114 if (line.startsWith('>>> EOF STDERR')) { | 2054 if (line.startsWith('>>> EOF STDERR')) { |
| 2115 _stderrSubscription.pause(); | 2055 _stderrSubscription.pause(); |
| 2116 _stderrCompleter.complete(null); | 2056 _stderrCompleter.complete(null); |
| 2117 } else { | 2057 } else { |
| 2118 _testStderr.add(encodeUtf8(line)); | 2058 _testStderr.add(encodeUtf8(line)); |
| 2119 _testStderr.add("\n".codeUnits); | 2059 _testStderr.add("\n".codeUnits); |
| 2120 } | 2060 } |
| 2121 }); | 2061 }); |
| 2122 _stderrSubscription.pause(); | 2062 _stderrSubscription.pause(); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2149 bool _dictEquals(Map a, Map b) { | 2089 bool _dictEquals(Map a, Map b) { |
| 2150 if (a == null) return b == null; | 2090 if (a == null) return b == null; |
| 2151 if (b == null) return false; | 2091 if (b == null) return false; |
| 2152 for (var key in a.keys) { | 2092 for (var key in a.keys) { |
| 2153 if (a[key] != b[key]) return false; | 2093 if (a[key] != b[key]) return false; |
| 2154 } | 2094 } |
| 2155 return true; | 2095 return true; |
| 2156 } | 2096 } |
| 2157 } | 2097 } |
| 2158 | 2098 |
| 2159 | |
| 2160 /** | 2099 /** |
| 2161 * [TestCaseEnqueuer] takes a list of TestSuites, generates TestCases and | 2100 * [TestCaseEnqueuer] takes a list of TestSuites, generates TestCases and |
| 2162 * builds a dependency graph of all commands in every TestSuite. | 2101 * builds a dependency graph of all commands in every TestSuite. |
| 2163 * | 2102 * |
| 2164 * It will maintain three helper data structures | 2103 * It will maintain three helper data structures |
| 2165 * - command2node: A mapping from a [Command] to a node in the dependency graph | 2104 * - command2node: A mapping from a [Command] to a node in the dependency graph |
| 2166 * - command2testCases: A mapping from [Command] to all TestCases that it is | 2105 * - command2testCases: A mapping from [Command] to all TestCases that it is |
| 2167 * part of. | 2106 * part of. |
| 2168 * - remainingTestCases: A set of TestCases that were enqueued but are not | 2107 * - remainingTestCases: A set of TestCases that were enqueued but are not |
| 2169 * finished | 2108 * finished |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2216 // We're finished with building the dependency graph. | 2155 // We're finished with building the dependency graph. |
| 2217 graph.sealGraph(); | 2156 graph.sealGraph(); |
| 2218 } else { | 2157 } else { |
| 2219 iterator.current.forEachTest(newTest, testCache, enqueueNextSuite); | 2158 iterator.current.forEachTest(newTest, testCache, enqueueNextSuite); |
| 2220 } | 2159 } |
| 2221 } | 2160 } |
| 2222 enqueueNextSuite(); | 2161 enqueueNextSuite(); |
| 2223 } | 2162 } |
| 2224 } | 2163 } |
| 2225 | 2164 |
| 2226 | |
| 2227 /* | 2165 /* |
| 2228 * [CommandEnqueuer] will | 2166 * [CommandEnqueuer] will |
| 2229 * - change node.state to NodeState.Enqueuing as soon as all dependencies have | 2167 * - change node.state to NodeState.Enqueuing as soon as all dependencies have |
| 2230 * a state of NodeState.Successful | 2168 * a state of NodeState.Successful |
| 2231 * - change node.state to NodeState.UnableToRun if one or more dependencies | 2169 * - change node.state to NodeState.UnableToRun if one or more dependencies |
| 2232 * have a state of NodeState.Failed/NodeState.UnableToRun. | 2170 * have a state of NodeState.Failed/NodeState.UnableToRun. |
| 2233 */ | 2171 */ |
| 2234 class CommandEnqueuer { | 2172 class CommandEnqueuer { |
| 2235 static final INIT_STATES = [dgraph.NodeState.Initialized, | 2173 static final INIT_STATES = [ |
| 2236 dgraph.NodeState.Waiting]; | 2174 dgraph.NodeState.Initialized, |
| 2237 static final FINISHED_STATES = [dgraph.NodeState.Successful, | 2175 dgraph.NodeState.Waiting |
| 2238 dgraph.NodeState.Failed, | 2176 ]; |
| 2239 dgraph.NodeState.UnableToRun]; | 2177 static final FINISHED_STATES = [ |
| 2178 dgraph.NodeState.Successful, |
| 2179 dgraph.NodeState.Failed, |
| 2180 dgraph.NodeState.UnableToRun |
| 2181 ]; |
| 2240 final dgraph.Graph _graph; | 2182 final dgraph.Graph _graph; |
| 2241 | 2183 |
| 2242 CommandEnqueuer(this._graph) { | 2184 CommandEnqueuer(this._graph) { |
| 2243 var eventCondition = _graph.events.where; | 2185 var eventCondition = _graph.events.where; |
| 2244 | 2186 |
| 2245 eventCondition((e) => e is dgraph.NodeAddedEvent).listen((event) { | 2187 eventCondition((e) => e is dgraph.NodeAddedEvent).listen((event) { |
| 2246 dgraph.Node node = event.node; | 2188 dgraph.Node node = event.node; |
| 2247 _changeNodeStateIfNecessary(node); | 2189 _changeNodeStateIfNecessary(node); |
| 2248 }); | 2190 }); |
| 2249 | 2191 |
| 2250 eventCondition((e) => e is dgraph.StateChangedEvent).listen((event) { | 2192 eventCondition((e) => e is dgraph.StateChangedEvent).listen((event) { |
| 2251 if ([dgraph.NodeState.Waiting, | 2193 if ([dgraph.NodeState.Waiting, dgraph.NodeState.Processing] |
| 2252 dgraph.NodeState.Processing].contains(event.from)) { | 2194 .contains(event.from)) { |
| 2253 if (FINISHED_STATES.contains(event.to)){ | 2195 if (FINISHED_STATES.contains(event.to)) { |
| 2254 for (var dependendNode in event.node.neededFor) { | 2196 for (var dependendNode in event.node.neededFor) { |
| 2255 _changeNodeStateIfNecessary(dependendNode); | 2197 _changeNodeStateIfNecessary(dependendNode); |
| 2256 } | 2198 } |
| 2257 } | 2199 } |
| 2258 } | 2200 } |
| 2259 }); | 2201 }); |
| 2260 } | 2202 } |
| 2261 | 2203 |
| 2262 // Called when either a new node was added or if one of it's dependencies | 2204 // Called when either a new node was added or if one of it's dependencies |
| 2263 // changed it's state. | 2205 // changed it's state. |
| 2264 void _changeNodeStateIfNecessary(dgraph.Node node) { | 2206 void _changeNodeStateIfNecessary(dgraph.Node node) { |
| 2265 if (INIT_STATES.contains(node.state)) { | 2207 if (INIT_STATES.contains(node.state)) { |
| 2266 bool anyDependenciesUnsuccessful = node.dependencies.any( | 2208 bool anyDependenciesUnsuccessful = node.dependencies.any((dep) => [ |
| 2267 (dep) => [dgraph.NodeState.Failed, | 2209 dgraph.NodeState.Failed, |
| 2268 dgraph.NodeState.UnableToRun].contains(dep.state)); | 2210 dgraph.NodeState.UnableToRun |
| 2211 ].contains(dep.state)); |
| 2269 | 2212 |
| 2270 var newState = dgraph.NodeState.Waiting; | 2213 var newState = dgraph.NodeState.Waiting; |
| 2271 if (anyDependenciesUnsuccessful) { | 2214 if (anyDependenciesUnsuccessful) { |
| 2272 newState = dgraph.NodeState.UnableToRun; | 2215 newState = dgraph.NodeState.UnableToRun; |
| 2273 } else { | 2216 } else { |
| 2274 bool allDependenciesSuccessful = node.dependencies.every( | 2217 bool allDependenciesSuccessful = node.dependencies |
| 2275 (dep) => dep.state == dgraph.NodeState.Successful); | 2218 .every((dep) => dep.state == dgraph.NodeState.Successful); |
| 2276 | 2219 |
| 2277 if (allDependenciesSuccessful) { | 2220 if (allDependenciesSuccessful) { |
| 2278 newState = dgraph.NodeState.Enqueuing; | 2221 newState = dgraph.NodeState.Enqueuing; |
| 2279 } | 2222 } |
| 2280 } | 2223 } |
| 2281 if (node.state != newState) { | 2224 if (node.state != newState) { |
| 2282 _graph.changeState(node, newState); | 2225 _graph.changeState(node, newState); |
| 2283 } | 2226 } |
| 2284 } | 2227 } |
| 2285 } | 2228 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2297 * It provides a [done] future, which will complete once there are no more | 2240 * It provides a [done] future, which will complete once there are no more |
| 2298 * nodes left in the states Initialized/Waiting/Enqueing/Processing | 2241 * nodes left in the states Initialized/Waiting/Enqueing/Processing |
| 2299 * and the [executor] has cleaned up it's resources. | 2242 * and the [executor] has cleaned up it's resources. |
| 2300 */ | 2243 */ |
| 2301 class CommandQueue { | 2244 class CommandQueue { |
| 2302 final dgraph.Graph graph; | 2245 final dgraph.Graph graph; |
| 2303 final CommandExecutor executor; | 2246 final CommandExecutor executor; |
| 2304 final TestCaseEnqueuer enqueuer; | 2247 final TestCaseEnqueuer enqueuer; |
| 2305 | 2248 |
| 2306 final Queue<Command> _runQueue = new Queue<Command>(); | 2249 final Queue<Command> _runQueue = new Queue<Command>(); |
| 2307 final _commandOutputStream = new StreamController<CommandOutput>(sync: true); | 2250 final _commandOutputStream = new StreamController<CommandOutput>(sync: true); |
| 2308 final _completer = new Completer(); | 2251 final _completer = new Completer(); |
| 2309 | 2252 |
| 2310 int _numProcesses = 0; | 2253 int _numProcesses = 0; |
| 2311 int _maxProcesses; | 2254 int _maxProcesses; |
| 2312 int _numBrowserProcesses = 0; | 2255 int _numBrowserProcesses = 0; |
| 2313 int _maxBrowserProcesses; | 2256 int _maxBrowserProcesses; |
| 2314 bool _finishing = false; | 2257 bool _finishing = false; |
| 2315 bool _verbose = false; | 2258 bool _verbose = false; |
| 2316 | 2259 |
| 2317 CommandQueue(this.graph, this.enqueuer, this.executor, | 2260 CommandQueue(this.graph, this.enqueuer, this.executor, this._maxProcesses, |
| 2318 this._maxProcesses, this._maxBrowserProcesses, this._verbose) { | 2261 this._maxBrowserProcesses, this._verbose) { |
| 2319 var eventCondition = graph.events.where; | 2262 var eventCondition = graph.events.where; |
| 2320 eventCondition((event) => event is dgraph.StateChangedEvent) | 2263 eventCondition((event) => event is dgraph.StateChangedEvent) |
| 2321 .listen((event) { | 2264 .listen((event) { |
| 2322 if (event.to == dgraph.NodeState.Enqueuing) { | 2265 if (event.to == dgraph.NodeState.Enqueuing) { |
| 2323 assert(event.from == dgraph.NodeState.Initialized || | 2266 assert(event.from == dgraph.NodeState.Initialized || |
| 2324 event.from == dgraph.NodeState.Waiting); | 2267 event.from == dgraph.NodeState.Waiting); |
| 2325 graph.changeState(event.node, dgraph.NodeState.Processing); | 2268 graph.changeState(event.node, dgraph.NodeState.Processing); |
| 2326 var command = event.node.userData; | 2269 var command = event.node.userData; |
| 2327 if (event.node.dependencies.length > 0) { | 2270 if (event.node.dependencies.length > 0) { |
| 2328 _runQueue.addFirst(command); | 2271 _runQueue.addFirst(command); |
| 2329 } else { | 2272 } else { |
| 2330 _runQueue.add(command); | 2273 _runQueue.add(command); |
| 2331 } | 2274 } |
| 2332 Timer.run(() => _tryRunNextCommand()); | 2275 Timer.run(() => _tryRunNextCommand()); |
| 2333 } | 2276 } |
| 2334 }); | 2277 }); |
| 2335 // We're finished if the graph is sealed and all nodes are in a finished | 2278 // We're finished if the graph is sealed and all nodes are in a finished |
| 2336 // state (Successful, Failed or UnableToRun). | 2279 // state (Successful, Failed or UnableToRun). |
| 2337 // So we're calling '_checkDone()' to check whether that condition is met | 2280 // So we're calling '_checkDone()' to check whether that condition is met |
| 2338 // and we can cleanup. | 2281 // and we can cleanup. |
| 2339 graph.events.listen((dgraph.GraphEvent event) { | 2282 graph.events.listen((dgraph.GraphEvent event) { |
| 2340 if (event is dgraph.GraphSealedEvent) { | 2283 if (event is dgraph.GraphSealedEvent) { |
| 2341 _checkDone(); | 2284 _checkDone(); |
| 2342 } else if (event is dgraph.StateChangedEvent) { | 2285 } else if (event is dgraph.StateChangedEvent) { |
| 2343 if (event.to == dgraph.NodeState.UnableToRun) { | 2286 if (event.to == dgraph.NodeState.UnableToRun) { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2367 } | 2310 } |
| 2368 | 2311 |
| 2369 _numProcesses++; | 2312 _numProcesses++; |
| 2370 if (isBrowserCommand) _numBrowserProcesses++; | 2313 if (isBrowserCommand) _numBrowserProcesses++; |
| 2371 | 2314 |
| 2372 var node = enqueuer.command2node[command]; | 2315 var node = enqueuer.command2node[command]; |
| 2373 Iterable<TestCase> testCases = enqueuer.command2testCases[command]; | 2316 Iterable<TestCase> testCases = enqueuer.command2testCases[command]; |
| 2374 // If a command is part of many TestCases we set the timeout to be | 2317 // If a command is part of many TestCases we set the timeout to be |
| 2375 // the maximum over all [TestCase.timeout]s. At some point, we might | 2318 // the maximum over all [TestCase.timeout]s. At some point, we might |
| 2376 // eliminate [TestCase.timeout] completely and move it to [Command]. | 2319 // eliminate [TestCase.timeout] completely and move it to [Command]. |
| 2377 int timeout = testCases.map((TestCase test) => test.timeout) | 2320 int timeout = |
| 2378 .fold(0, math.max); | 2321 testCases.map((TestCase test) => test.timeout).fold(0, math.max); |
| 2379 | 2322 |
| 2380 if (_verbose) { | 2323 if (_verbose) { |
| 2381 print('Running "${command.displayName}" command: $command'); | 2324 print('Running "${command.displayName}" command: $command'); |
| 2382 } | 2325 } |
| 2383 | 2326 |
| 2384 executor.runCommand(node, command, timeout).then((CommandOutput output) { | 2327 executor.runCommand(node, command, timeout).then((CommandOutput output) { |
| 2385 assert(command == output.command); | 2328 assert(command == output.command); |
| 2386 | 2329 |
| 2387 _commandOutputStream.add(output); | 2330 _commandOutputStream.add(output); |
| 2388 if (output.canRunDependendCommands) { | 2331 if (output.canRunDependendCommands) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2415 _commandOutputStream.close(); | 2358 _commandOutputStream.close(); |
| 2416 }); | 2359 }); |
| 2417 } | 2360 } |
| 2418 } | 2361 } |
| 2419 | 2362 |
| 2420 void dumpState() { | 2363 void dumpState() { |
| 2421 print(""); | 2364 print(""); |
| 2422 print("CommandQueue state:"); | 2365 print("CommandQueue state:"); |
| 2423 print(" Processes: used: $_numProcesses max: $_maxProcesses"); | 2366 print(" Processes: used: $_numProcesses max: $_maxProcesses"); |
| 2424 print(" BrowserProcesses: used: $_numBrowserProcesses " | 2367 print(" BrowserProcesses: used: $_numBrowserProcesses " |
| 2425 "max: $_maxBrowserProcesses"); | 2368 "max: $_maxBrowserProcesses"); |
| 2426 print(" Finishing: $_finishing"); | 2369 print(" Finishing: $_finishing"); |
| 2427 print(" Queue (length = ${_runQueue.length}):"); | 2370 print(" Queue (length = ${_runQueue.length}):"); |
| 2428 for (var command in _runQueue) { | 2371 for (var command in _runQueue) { |
| 2429 print(" $command"); | 2372 print(" $command"); |
| 2430 } | 2373 } |
| 2431 } | 2374 } |
| 2432 } | 2375 } |
| 2433 | 2376 |
| 2434 | |
| 2435 /* | 2377 /* |
| 2436 * [CommandExecutor] is responsible for executing commands. It will make sure | 2378 * [CommandExecutor] is responsible for executing commands. It will make sure |
| 2437 * that the the following two constraints are satisfied | 2379 * that the the following two constraints are satisfied |
| 2438 * - [:numberOfProcessesUsed <= maxProcesses:] | 2380 * - [:numberOfProcessesUsed <= maxProcesses:] |
| 2439 * - [:numberOfBrowserProcessesUsed <= maxBrowserProcesses:] | 2381 * - [:numberOfBrowserProcessesUsed <= maxBrowserProcesses:] |
| 2440 * | 2382 * |
| 2441 * It provides a [runCommand] method which will complete with a | 2383 * It provides a [runCommand] method which will complete with a |
| 2442 * [CommandOutput] object. | 2384 * [CommandOutput] object. |
| 2443 * | 2385 * |
| 2444 * It provides a [cleanup] method to free all the allocated resources. | 2386 * It provides a [cleanup] method to free all the allocated resources. |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2487 return Future.wait([_terminateBatchRunners(), _terminateBrowserRunners()]); | 2429 return Future.wait([_terminateBatchRunners(), _terminateBrowserRunners()]); |
| 2488 } | 2430 } |
| 2489 | 2431 |
| 2490 Future<CommandOutput> runCommand(node, Command command, int timeout) { | 2432 Future<CommandOutput> runCommand(node, Command command, int timeout) { |
| 2491 assert(!_finishing); | 2433 assert(!_finishing); |
| 2492 | 2434 |
| 2493 Future<CommandOutput> runCommand(int retriesLeft) { | 2435 Future<CommandOutput> runCommand(int retriesLeft) { |
| 2494 return _runCommand(command, timeout).then((CommandOutput output) { | 2436 return _runCommand(command, timeout).then((CommandOutput output) { |
| 2495 if (retriesLeft > 0 && shouldRetryCommand(output)) { | 2437 if (retriesLeft > 0 && shouldRetryCommand(output)) { |
| 2496 DebugLogger.warning("Rerunning Command: ($retriesLeft " | 2438 DebugLogger.warning("Rerunning Command: ($retriesLeft " |
| 2497 "attempt(s) remains) [cmd: $command]"); | 2439 "attempt(s) remains) [cmd: $command]"); |
| 2498 return runCommand(retriesLeft - 1); | 2440 return runCommand(retriesLeft - 1); |
| 2499 } else { | 2441 } else { |
| 2500 return new Future.value(output); | 2442 return new Future.value(output); |
| 2501 } | 2443 } |
| 2502 }); | 2444 }); |
| 2503 } | 2445 } |
| 2504 return runCommand(command.maxNumRetries); | 2446 return runCommand(command.maxNumRetries); |
| 2505 } | 2447 } |
| 2506 | 2448 |
| 2507 Future<CommandOutput> _runCommand(Command command, int timeout) { | 2449 Future<CommandOutput> _runCommand(Command command, int timeout) { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2538 if (!runner._currentlyRunning) return runner; | 2480 if (!runner._currentlyRunning) return runner; |
| 2539 } | 2481 } |
| 2540 throw new Exception('Unable to find inactive batch runner.'); | 2482 throw new Exception('Unable to find inactive batch runner.'); |
| 2541 } | 2483 } |
| 2542 | 2484 |
| 2543 Future<CommandOutput> _startBrowserControllerTest( | 2485 Future<CommandOutput> _startBrowserControllerTest( |
| 2544 BrowserTestCommand browserCommand, int timeout) { | 2486 BrowserTestCommand browserCommand, int timeout) { |
| 2545 var completer = new Completer<CommandOutput>(); | 2487 var completer = new Completer<CommandOutput>(); |
| 2546 | 2488 |
| 2547 var callback = (BrowserTestOutput output) { | 2489 var callback = (BrowserTestOutput output) { |
| 2548 completer.complete( | 2490 completer |
| 2549 new BrowserControllerTestOutcome(browserCommand, output)); | 2491 .complete(new BrowserControllerTestOutcome(browserCommand, output)); |
| 2550 }; | 2492 }; |
| 2551 | 2493 |
| 2552 BrowserTest browserTest; | 2494 BrowserTest browserTest; |
| 2553 if (browserCommand is BrowserHtmlTestCommand) { | 2495 if (browserCommand is BrowserHtmlTestCommand) { |
| 2554 browserTest = new HtmlTest(browserCommand.url, callback, timeout, | 2496 browserTest = new HtmlTest(browserCommand.url, callback, timeout, |
| 2555 browserCommand.expectedMessages); | 2497 browserCommand.expectedMessages); |
| 2556 } else { | 2498 } else { |
| 2557 browserTest = new BrowserTest(browserCommand.url, callback, timeout); | 2499 browserTest = new BrowserTest(browserCommand.url, callback, timeout); |
| 2558 } | 2500 } |
| 2559 _getBrowserTestRunner(browserCommand.browser, browserCommand.configuration) | 2501 _getBrowserTestRunner(browserCommand.browser, browserCommand.configuration) |
| 2560 .then((testRunner) { | 2502 .then((testRunner) { |
| 2561 testRunner.enqueueTest(browserTest); | 2503 testRunner.enqueueTest(browserTest); |
| 2562 }); | 2504 }); |
| 2563 | 2505 |
| 2564 return completer.future; | 2506 return completer.future; |
| 2565 } | 2507 } |
| 2566 | 2508 |
| 2567 Future<BrowserTestRunner> _getBrowserTestRunner(String browser, | 2509 Future<BrowserTestRunner> _getBrowserTestRunner( |
| 2568 Map configuration) async { | 2510 String browser, Map configuration) async { |
| 2569 var localIp = globalConfiguration['local_ip']; | 2511 var localIp = globalConfiguration['local_ip']; |
| 2570 if (_browserTestRunners[configuration] == null) { | 2512 if (_browserTestRunners[configuration] == null) { |
| 2571 var testRunner = new BrowserTestRunner( | 2513 var testRunner = new BrowserTestRunner( |
| 2572 configuration, localIp, browser, maxBrowserProcesses); | 2514 configuration, localIp, browser, maxBrowserProcesses); |
| 2573 if (globalConfiguration['verbose']) { | 2515 if (globalConfiguration['verbose']) { |
| 2574 testRunner.logger = DebugLogger.info; | 2516 testRunner.logger = DebugLogger.info; |
| 2575 } | 2517 } |
| 2576 _browserTestRunners[configuration] = testRunner; | 2518 _browserTestRunners[configuration] = testRunner; |
| 2577 await testRunner.start(); | 2519 await testRunner.start(); |
| 2578 } | 2520 } |
| 2579 return _browserTestRunners[configuration]; | 2521 return _browserTestRunners[configuration]; |
| 2580 } | 2522 } |
| 2581 } | 2523 } |
| 2582 | 2524 |
| 2583 class RecordingCommandExecutor implements CommandExecutor { | 2525 class RecordingCommandExecutor implements CommandExecutor { |
| 2584 TestCaseRecorder _recorder; | 2526 TestCaseRecorder _recorder; |
| 2585 | 2527 |
| 2586 RecordingCommandExecutor(Path path) | 2528 RecordingCommandExecutor(Path path) : _recorder = new TestCaseRecorder(path); |
| 2587 : _recorder = new TestCaseRecorder(path); | |
| 2588 | 2529 |
| 2589 Future<CommandOutput> runCommand(node, ProcessCommand command, int timeout) { | 2530 Future<CommandOutput> runCommand(node, ProcessCommand command, int timeout) { |
| 2590 assert(node.dependencies.length == 0); | 2531 assert(node.dependencies.length == 0); |
| 2591 assert(_cleanEnvironmentOverrides(command.environmentOverrides)); | 2532 assert(_cleanEnvironmentOverrides(command.environmentOverrides)); |
| 2592 _recorder.nextCommand(command, timeout); | 2533 _recorder.nextCommand(command, timeout); |
| 2593 // Return dummy CommandOutput | 2534 // Return dummy CommandOutput |
| 2594 var output = | 2535 var output = |
| 2595 createCommandOutput(command, 0, false, [], [], const Duration(), false); | 2536 createCommandOutput(command, 0, false, [], [], const Duration(), false); |
| 2596 return new Future.value(output); | 2537 return new Future.value(output); |
| 2597 } | 2538 } |
| 2598 | 2539 |
| 2599 Future cleanup() { | 2540 Future cleanup() { |
| 2600 _recorder.finish(); | 2541 _recorder.finish(); |
| 2601 return new Future.value(); | 2542 return new Future.value(); |
| 2602 } | 2543 } |
| 2603 | 2544 |
| 2604 // Returns [:true:] if the environment contains only 'DART_CONFIGURATION' | 2545 // Returns [:true:] if the environment contains only 'DART_CONFIGURATION' |
| 2605 bool _cleanEnvironmentOverrides(Map environment) { | 2546 bool _cleanEnvironmentOverrides(Map environment) { |
| 2606 if (environment == null) return true; | 2547 if (environment == null) return true; |
| 2607 return environment.length == 0 || | 2548 return environment.length == 0 || |
| 2608 (environment.length == 1 && | 2549 (environment.length == 1 && |
| 2609 environment.containsKey("DART_CONFIGURATION")); | 2550 environment.containsKey("DART_CONFIGURATION")); |
| 2610 | |
| 2611 } | 2551 } |
| 2612 } | 2552 } |
| 2613 | 2553 |
| 2614 class ReplayingCommandExecutor implements CommandExecutor { | 2554 class ReplayingCommandExecutor implements CommandExecutor { |
| 2615 TestCaseOutputArchive _archive = new TestCaseOutputArchive(); | 2555 TestCaseOutputArchive _archive = new TestCaseOutputArchive(); |
| 2616 | 2556 |
| 2617 ReplayingCommandExecutor(Path path) { | 2557 ReplayingCommandExecutor(Path path) { |
| 2618 _archive.loadFromPath(path); | 2558 _archive.loadFromPath(path); |
| 2619 } | 2559 } |
| 2620 | 2560 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2636 stderr = decodeUtf8(output.stderr).split("\n"); | 2576 stderr = decodeUtf8(output.stderr).split("\n"); |
| 2637 } | 2577 } |
| 2638 } | 2578 } |
| 2639 | 2579 |
| 2640 if (io.Platform.operatingSystem == 'linux') { | 2580 if (io.Platform.operatingSystem == 'linux') { |
| 2641 decodeOutput(); | 2581 decodeOutput(); |
| 2642 // No matter which command we ran: If we get failures due to the | 2582 // No matter which command we ran: If we get failures due to the |
| 2643 // "xvfb-run" issue 7564, try re-running the test. | 2583 // "xvfb-run" issue 7564, try re-running the test. |
| 2644 bool containsFailureMsg(String line) { | 2584 bool containsFailureMsg(String line) { |
| 2645 return line.contains(MESSAGE_CANNOT_OPEN_DISPLAY) || | 2585 return line.contains(MESSAGE_CANNOT_OPEN_DISPLAY) || |
| 2646 line.contains(MESSAGE_FAILED_TO_RUN_COMMAND); | 2586 line.contains(MESSAGE_FAILED_TO_RUN_COMMAND); |
| 2647 } | 2587 } |
| 2648 if (stdout.any(containsFailureMsg) || stderr.any(containsFailureMsg)) { | 2588 if (stdout.any(containsFailureMsg) || stderr.any(containsFailureMsg)) { |
| 2649 return true; | 2589 return true; |
| 2650 } | 2590 } |
| 2651 } | 2591 } |
| 2652 | 2592 |
| 2653 // We currently rerun dartium tests, see issue 14074. | 2593 // We currently rerun dartium tests, see issue 14074. |
| 2654 final command = output.command; | 2594 final command = output.command; |
| 2655 if (command is BrowserTestCommand && | 2595 if (command is BrowserTestCommand && |
| 2656 command.retry && | 2596 command.retry && |
| 2657 command.browser == 'dartium') { | 2597 command.browser == 'dartium') { |
| 2658 return true; | 2598 return true; |
| 2659 } | 2599 } |
| 2660 } | 2600 } |
| 2661 return false; | 2601 return false; |
| 2662 } | 2602 } |
| 2663 | 2603 |
| 2664 /* | 2604 /* |
| 2665 * [TestCaseCompleter] will listen for | 2605 * [TestCaseCompleter] will listen for |
| 2666 * NodeState.Processing -> NodeState.{Successful,Failed} state changes and | 2606 * NodeState.Processing -> NodeState.{Successful,Failed} state changes and |
| 2667 * will complete a TestCase if it is finished. | 2607 * will complete a TestCase if it is finished. |
| 2668 * | 2608 * |
| 2669 * It provides a stream [finishedTestCases], which will stream all TestCases | 2609 * It provides a stream [finishedTestCases], which will stream all TestCases |
| 2670 * once they're finished. After all TestCases are done, the stream will be | 2610 * once they're finished. After all TestCases are done, the stream will be |
| 2671 * closed. | 2611 * closed. |
| 2672 */ | 2612 */ |
| 2673 class TestCaseCompleter { | 2613 class TestCaseCompleter { |
| 2674 static final COMPLETED_STATES = [dgraph.NodeState.Failed, | 2614 static final COMPLETED_STATES = [ |
| 2675 dgraph.NodeState.Successful]; | 2615 dgraph.NodeState.Failed, |
| 2616 dgraph.NodeState.Successful |
| 2617 ]; |
| 2676 final dgraph.Graph graph; | 2618 final dgraph.Graph graph; |
| 2677 final TestCaseEnqueuer enqueuer; | 2619 final TestCaseEnqueuer enqueuer; |
| 2678 final CommandQueue commandQueue; | 2620 final CommandQueue commandQueue; |
| 2679 | 2621 |
| 2680 Map<Command, CommandOutput> _outputs = new Map<Command, CommandOutput>(); | 2622 Map<Command, CommandOutput> _outputs = new Map<Command, CommandOutput>(); |
| 2681 bool _closed = false; | 2623 bool _closed = false; |
| 2682 StreamController<TestCase> _controller = new StreamController<TestCase>(); | 2624 StreamController<TestCase> _controller = new StreamController<TestCase>(); |
| 2683 | 2625 |
| 2684 TestCaseCompleter(this.graph, this.enqueuer, this.commandQueue) { | 2626 TestCaseCompleter(this.graph, this.enqueuer, this.commandQueue) { |
| 2685 var eventCondition = graph.events.where; | 2627 var eventCondition = graph.events.where; |
| 2686 bool finishedRemainingTestCases = false; | 2628 bool finishedRemainingTestCases = false; |
| 2687 | 2629 |
| 2688 // Store all the command outputs -- they will be delivered synchronously | 2630 // Store all the command outputs -- they will be delivered synchronously |
| 2689 // (i.e. before state changes in the graph) | 2631 // (i.e. before state changes in the graph) |
| 2690 commandQueue.completedCommands.listen((CommandOutput output) { | 2632 commandQueue.completedCommands.listen((CommandOutput output) { |
| 2691 _outputs[output.command] = output; | 2633 _outputs[output.command] = output; |
| 2692 }, onDone: () { | 2634 }, onDone: () { |
| 2693 _completeTestCasesIfPossible(new List.from(enqueuer.remainingTestCases)); | 2635 _completeTestCasesIfPossible(new List.from(enqueuer.remainingTestCases)); |
| 2694 finishedRemainingTestCases = true; | 2636 finishedRemainingTestCases = true; |
| 2695 assert(enqueuer.remainingTestCases.isEmpty); | 2637 assert(enqueuer.remainingTestCases.isEmpty); |
| 2696 _checkDone(); | 2638 _checkDone(); |
| 2697 }); | 2639 }); |
| 2698 | 2640 |
| 2699 // Listen for NodeState.Processing -> NodeState.{Successful,Failed} | 2641 // Listen for NodeState.Processing -> NodeState.{Successful,Failed} |
| 2700 // changes. | 2642 // changes. |
| 2701 eventCondition((event) => event is dgraph.StateChangedEvent) | 2643 eventCondition((event) => event is dgraph.StateChangedEvent) |
| 2702 .listen((dgraph.StateChangedEvent event) { | 2644 .listen((dgraph.StateChangedEvent event) { |
| 2703 if (event.from == dgraph.NodeState.Processing && | 2645 if (event.from == dgraph.NodeState.Processing && |
| 2704 !finishedRemainingTestCases ) { | 2646 !finishedRemainingTestCases) { |
| 2705 var command = event.node.userData; | 2647 var command = event.node.userData; |
| 2706 | 2648 |
| 2707 assert(COMPLETED_STATES.contains(event.to)); | 2649 assert(COMPLETED_STATES.contains(event.to)); |
| 2708 assert(_outputs[command] != null); | 2650 assert(_outputs[command] != null); |
| 2709 | 2651 |
| 2710 _completeTestCasesIfPossible(enqueuer.command2testCases[command]); | 2652 _completeTestCasesIfPossible(enqueuer.command2testCases[command]); |
| 2711 _checkDone(); | 2653 _checkDone(); |
| 2712 } | 2654 } |
| 2713 }); | 2655 }); |
| 2714 | 2656 |
| 2715 // Listen also for GraphSealedEvent's. If there is not a single node in the | 2657 // Listen also for GraphSealedEvent's. If there is not a single node in the |
| 2716 // graph, we still want to finish after the graph was sealed. | 2658 // graph, we still want to finish after the graph was sealed. |
| 2717 eventCondition((event) => event is dgraph.GraphSealedEvent) | 2659 eventCondition((event) => event is dgraph.GraphSealedEvent) |
| 2718 .listen((dgraph.GraphSealedEvent event) { | 2660 .listen((dgraph.GraphSealedEvent event) { |
| 2719 if (!_closed && enqueuer.remainingTestCases.isEmpty) { | 2661 if (!_closed && enqueuer.remainingTestCases.isEmpty) { |
| 2720 _controller.close(); | 2662 _controller.close(); |
| 2721 _closed = true; | 2663 _closed = true; |
| 2722 } | 2664 } |
| 2723 }); | 2665 }); |
| 2724 } | 2666 } |
| 2725 | 2667 |
| 2726 Stream<TestCase> get finishedTestCases => _controller.stream; | 2668 Stream<TestCase> get finishedTestCases => _controller.stream; |
| 2727 | 2669 |
| 2728 void _checkDone() { | 2670 void _checkDone() { |
| 2729 if (!_closed && graph.isSealed && enqueuer.remainingTestCases.isEmpty) { | 2671 if (!_closed && graph.isSealed && enqueuer.remainingTestCases.isEmpty) { |
| 2730 _controller.close(); | 2672 _controller.close(); |
| 2731 _closed = true; | 2673 _closed = true; |
| 2732 } | 2674 } |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2756 // Ask the [testCase] if it's done. Note that we assume, that | 2698 // Ask the [testCase] if it's done. Note that we assume, that |
| 2757 // [TestCase.isFinished] will return true if all commands were executed | 2699 // [TestCase.isFinished] will return true if all commands were executed |
| 2758 // or if a previous one failed. | 2700 // or if a previous one failed. |
| 2759 if (testCase.isFinished) { | 2701 if (testCase.isFinished) { |
| 2760 completeTestCase(testCase); | 2702 completeTestCase(testCase); |
| 2761 } | 2703 } |
| 2762 } | 2704 } |
| 2763 } | 2705 } |
| 2764 } | 2706 } |
| 2765 | 2707 |
| 2766 | |
| 2767 class ProcessQueue { | 2708 class ProcessQueue { |
| 2768 Map _globalConfiguration; | 2709 Map _globalConfiguration; |
| 2769 | 2710 |
| 2770 Function _allDone; | 2711 Function _allDone; |
| 2771 final dgraph.Graph _graph = new dgraph.Graph(); | 2712 final dgraph.Graph _graph = new dgraph.Graph(); |
| 2772 List<EventListener> _eventListener; | 2713 List<EventListener> _eventListener; |
| 2773 | 2714 |
| 2774 ProcessQueue(this._globalConfiguration, | 2715 ProcessQueue(this._globalConfiguration, maxProcesses, maxBrowserProcesses, |
| 2775 maxProcesses, | 2716 DateTime startTime, testSuites, this._eventListener, this._allDone, |
| 2776 maxBrowserProcesses, | 2717 [bool verbose = false, |
| 2777 DateTime startTime, | 2718 String recordingOutputFile, |
| 2778 testSuites, | 2719 String recordedInputFile]) { |
| 2779 this._eventListener, | |
| 2780 this._allDone, | |
| 2781 [bool verbose = false, | |
| 2782 String recordingOutputFile, | |
| 2783 String recordedInputFile]) { | |
| 2784 void setupForListing(TestCaseEnqueuer testCaseEnqueuer) { | 2720 void setupForListing(TestCaseEnqueuer testCaseEnqueuer) { |
| 2785 _graph.events.where((event) => event is dgraph.GraphSealedEvent) | 2721 _graph.events |
| 2786 .listen((dgraph.GraphSealedEvent event) { | 2722 .where((event) => event is dgraph.GraphSealedEvent) |
| 2787 var testCases = new List.from(testCaseEnqueuer.remainingTestCases); | 2723 .listen((dgraph.GraphSealedEvent event) { |
| 2788 testCases.sort((a, b) => a.displayName.compareTo(b.displayName)); | 2724 var testCases = new List.from(testCaseEnqueuer.remainingTestCases); |
| 2725 testCases.sort((a, b) => a.displayName.compareTo(b.displayName)); |
| 2789 | 2726 |
| 2790 print("\nGenerating all matching test cases ....\n"); | 2727 print("\nGenerating all matching test cases ....\n"); |
| 2791 | 2728 |
| 2792 for (TestCase testCase in testCases) { | 2729 for (TestCase testCase in testCases) { |
| 2793 eventFinishedTestCase(testCase); | 2730 eventFinishedTestCase(testCase); |
| 2794 print("${testCase.displayName} " | 2731 print("${testCase.displayName} " |
| 2795 "Expectations: ${testCase.expectedOutcomes.join(', ')} " | 2732 "Expectations: ${testCase.expectedOutcomes.join(', ')} " |
| 2796 "Configuration: '${testCase.configurationString}'"); | 2733 "Configuration: '${testCase.configurationString}'"); |
| 2797 } | 2734 } |
| 2798 eventAllTestsKnown(); | 2735 eventAllTestsKnown(); |
| 2799 }); | 2736 }); |
| 2800 } | 2737 } |
| 2801 | 2738 |
| 2802 var testCaseEnqueuer; | 2739 var testCaseEnqueuer; |
| 2803 CommandQueue commandQueue; | 2740 CommandQueue commandQueue; |
| 2804 | 2741 |
| 2805 void setupForRunning(TestCaseEnqueuer testCaseEnqueuer) { | 2742 void setupForRunning(TestCaseEnqueuer testCaseEnqueuer) { |
| 2806 Timer _debugTimer; | 2743 Timer _debugTimer; |
| 2807 // If we haven't seen a single test finishing during a 10 minute period | 2744 // If we haven't seen a single test finishing during a 10 minute period |
| 2808 // something is definitly wrong, so we dump the debugging information. | 2745 // something is definitly wrong, so we dump the debugging information. |
| 2809 final debugTimerDuration = const Duration(minutes: 10); | 2746 final debugTimerDuration = const Duration(minutes: 10); |
| 2810 | 2747 |
| 2811 void cancelDebugTimer() { | 2748 void cancelDebugTimer() { |
| 2812 if (_debugTimer != null) { | 2749 if (_debugTimer != null) { |
| 2813 _debugTimer.cancel(); | 2750 _debugTimer.cancel(); |
| 2814 } | 2751 } |
| 2815 } | 2752 } |
| 2816 | 2753 |
| 2817 void resetDebugTimer() { | 2754 void resetDebugTimer() { |
| 2818 cancelDebugTimer(); | 2755 cancelDebugTimer(); |
| 2819 _debugTimer = new Timer(debugTimerDuration, () { | 2756 _debugTimer = new Timer(debugTimerDuration, () { |
| 2820 print("The debug timer of test.dart expired. Please report this issue" | 2757 print("The debug timer of test.dart expired. Please report this issue" |
| 2821 " to ricow/whesse and provide the following information:"); | 2758 " to ricow/whesse and provide the following information:"); |
| 2822 print(""); | 2759 print(""); |
| 2823 print("Graph is sealed: ${_graph.isSealed}"); | 2760 print("Graph is sealed: ${_graph.isSealed}"); |
| 2824 print(""); | 2761 print(""); |
| 2825 _graph.DumpCounts(); | 2762 _graph.DumpCounts(); |
| 2826 print(""); | 2763 print(""); |
| 2827 var unfinishedNodeStates = [ | 2764 var unfinishedNodeStates = [ |
| 2828 dgraph.NodeState.Initialized, | 2765 dgraph.NodeState.Initialized, |
| 2829 dgraph.NodeState.Waiting, | 2766 dgraph.NodeState.Waiting, |
| 2830 dgraph.NodeState.Enqueuing, | 2767 dgraph.NodeState.Enqueuing, |
| 2831 dgraph.NodeState.Processing]; | 2768 dgraph.NodeState.Processing |
| 2769 ]; |
| 2832 | 2770 |
| 2833 for (var nodeState in unfinishedNodeStates) { | 2771 for (var nodeState in unfinishedNodeStates) { |
| 2834 if (_graph.stateCount(nodeState) > 0) { | 2772 if (_graph.stateCount(nodeState) > 0) { |
| 2835 print("Commands in state '$nodeState':"); | 2773 print("Commands in state '$nodeState':"); |
| 2836 print("================================="); | 2774 print("================================="); |
| 2837 print(""); | 2775 print(""); |
| 2838 for (var node in _graph.nodes) { | 2776 for (var node in _graph.nodes) { |
| 2839 if (node.state == nodeState) { | 2777 if (node.state == nodeState) { |
| 2840 var command = node.userData; | 2778 var command = node.userData; |
| 2841 var testCases = testCaseEnqueuer.command2testCases[command]; | 2779 var testCases = testCaseEnqueuer.command2testCases[command]; |
| 2842 print(" Command: $command"); | 2780 print(" Command: $command"); |
| 2843 for (var testCase in testCases) { | 2781 for (var testCase in testCases) { |
| 2844 print(" Enqueued by: ${testCase.configurationString} " | 2782 print(" Enqueued by: ${testCase.configurationString} " |
| 2845 "-- ${testCase.displayName}"); | 2783 "-- ${testCase.displayName}"); |
| 2846 } | 2784 } |
| 2847 print(""); | 2785 print(""); |
| 2848 } | 2786 } |
| 2849 } | 2787 } |
| 2850 print(""); | 2788 print(""); |
| 2851 print(""); | 2789 print(""); |
| 2852 } | 2790 } |
| 2853 } | 2791 } |
| 2854 | 2792 |
| 2855 if (commandQueue != null) { | 2793 if (commandQueue != null) { |
| 2856 commandQueue.dumpState(); | 2794 commandQueue.dumpState(); |
| 2857 } | 2795 } |
| 2858 }); | 2796 }); |
| 2859 } | 2797 } |
| 2860 | 2798 |
| 2861 bool recording = recordingOutputFile != null; | 2799 bool recording = recordingOutputFile != null; |
| 2862 bool replaying = recordedInputFile != null; | 2800 bool replaying = recordedInputFile != null; |
| 2863 | 2801 |
| 2864 // When the graph building is finished, notify event listeners. | 2802 // When the graph building is finished, notify event listeners. |
| 2865 _graph.events | 2803 _graph.events |
| 2866 .where((event) => event is dgraph.GraphSealedEvent).listen((event) { | 2804 .where((event) => event is dgraph.GraphSealedEvent) |
| 2867 eventAllTestsKnown(); | 2805 .listen((event) { |
| 2868 }); | 2806 eventAllTestsKnown(); |
| 2807 }); |
| 2869 | 2808 |
| 2870 // Queue commands as they become "runnable" | 2809 // Queue commands as they become "runnable" |
| 2871 var commandEnqueuer = new CommandEnqueuer(_graph); | 2810 var commandEnqueuer = new CommandEnqueuer(_graph); |
| 2872 | 2811 |
| 2873 // CommandExecutor will execute commands | 2812 // CommandExecutor will execute commands |
| 2874 var executor; | 2813 var executor; |
| 2875 if (recording) { | 2814 if (recording) { |
| 2876 executor = new RecordingCommandExecutor(new Path(recordingOutputFile)); | 2815 executor = new RecordingCommandExecutor(new Path(recordingOutputFile)); |
| 2877 } else if (replaying) { | 2816 } else if (replaying) { |
| 2878 executor = new ReplayingCommandExecutor(new Path(recordedInputFile)); | 2817 executor = new ReplayingCommandExecutor(new Path(recordedInputFile)); |
| 2879 } else { | 2818 } else { |
| 2880 executor = new CommandExecutorImpl( | 2819 executor = new CommandExecutorImpl( |
| 2881 _globalConfiguration, maxProcesses, maxBrowserProcesses); | 2820 _globalConfiguration, maxProcesses, maxBrowserProcesses); |
| 2882 } | 2821 } |
| 2883 | 2822 |
| 2884 // Run "runnable commands" using [executor] subject to | 2823 // Run "runnable commands" using [executor] subject to |
| 2885 // maxProcesses/maxBrowserProcesses constraint | 2824 // maxProcesses/maxBrowserProcesses constraint |
| 2886 commandQueue = new CommandQueue( | 2825 commandQueue = new CommandQueue(_graph, testCaseEnqueuer, executor, |
| 2887 _graph, testCaseEnqueuer, executor, maxProcesses, maxBrowserProcesses, | 2826 maxProcesses, maxBrowserProcesses, verbose); |
| 2888 verbose); | |
| 2889 | 2827 |
| 2890 // Finish test cases when all commands were run (or some failed) | 2828 // Finish test cases when all commands were run (or some failed) |
| 2891 var testCaseCompleter = | 2829 var testCaseCompleter = |
| 2892 new TestCaseCompleter(_graph, testCaseEnqueuer, commandQueue); | 2830 new TestCaseCompleter(_graph, testCaseEnqueuer, commandQueue); |
| 2893 testCaseCompleter.finishedTestCases.listen( | 2831 testCaseCompleter.finishedTestCases.listen((TestCase finishedTestCase) { |
| 2894 (TestCase finishedTestCase) { | 2832 resetDebugTimer(); |
| 2895 resetDebugTimer(); | |
| 2896 | 2833 |
| 2897 // If we're recording, we don't report any TestCases to listeners. | 2834 // If we're recording, we don't report any TestCases to listeners. |
| 2898 if (!recording) { | 2835 if (!recording) { |
| 2899 eventFinishedTestCase(finishedTestCase); | 2836 eventFinishedTestCase(finishedTestCase); |
| 2900 } | 2837 } |
| 2901 }, | 2838 }, onDone: () { |
| 2902 onDone: () { | 2839 // Wait until the commandQueue/execturo is done (it may need to stop |
| 2903 // Wait until the commandQueue/execturo is done (it may need to stop | 2840 // batch runners, browser controllers, ....) |
| 2904 // batch runners, browser controllers, ....) | 2841 commandQueue.done.then((_) { |
| 2905 commandQueue.done.then((_) { | 2842 cancelDebugTimer(); |
| 2906 cancelDebugTimer(); | 2843 eventAllTestsDone(); |
| 2907 eventAllTestsDone(); | 2844 }); |
| 2908 }); | 2845 }); |
| 2909 }); | |
| 2910 | 2846 |
| 2911 resetDebugTimer(); | 2847 resetDebugTimer(); |
| 2912 } | 2848 } |
| 2913 | 2849 |
| 2914 // Build up the dependency graph | 2850 // Build up the dependency graph |
| 2915 testCaseEnqueuer = new TestCaseEnqueuer(_graph, (TestCase newTestCase) { | 2851 testCaseEnqueuer = new TestCaseEnqueuer(_graph, (TestCase newTestCase) { |
| 2916 eventTestAdded(newTestCase); | 2852 eventTestAdded(newTestCase); |
| 2917 }); | 2853 }); |
| 2918 | 2854 |
| 2919 // Either list or run the tests | 2855 // Either list or run the tests |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2950 } | 2886 } |
| 2951 } | 2887 } |
| 2952 | 2888 |
| 2953 void eventAllTestsDone() { | 2889 void eventAllTestsDone() { |
| 2954 for (var listener in _eventListener) { | 2890 for (var listener in _eventListener) { |
| 2955 listener.allDone(); | 2891 listener.allDone(); |
| 2956 } | 2892 } |
| 2957 _allDone(); | 2893 _allDone(); |
| 2958 } | 2894 } |
| 2959 } | 2895 } |
| OLD | NEW |