Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: tools/testing/dart/test_runner.dart

Issue 1859973002: Autoformat tools/testing/dart (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Format whole directory Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/testing/dart/test_progress.dart ('k') | tools/testing/dart/test_suite.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « tools/testing/dart/test_progress.dart ('k') | tools/testing/dart/test_suite.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698