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