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

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

Issue 9479034: Update test.dart for detection output of machine formatted errors (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Update test.dart for detection output of machine formatted errors Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /** 5 /**
6 * Classes and methods for executing tests. 6 * Classes and methods for executing tests.
7 * 7 *
8 * This module includes: 8 * This module includes:
9 * - Managing parallel execution of tests, including timeout checks. 9 * - Managing parallel execution of tests, including timeout checks.
10 * - Evaluating the output of each test as pass/fail/crash/timeout. 10 * - Evaluating the output of each test as pass/fail/crash/timeout.
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
155 arguments.getRange(1, arguments.length - 1); 155 arguments.getRange(1, arguments.length - 1);
156 } 156 }
157 157
158 158
159 /** 159 /**
160 * TestOutput records the output of a completed test: the process's exit code, 160 * TestOutput records the output of a completed test: the process's exit code,
161 * the standard output and standard error, whether the process timed out, and 161 * the standard output and standard error, whether the process timed out, and
162 * the time the process took to run. It also contains a pointer to the 162 * the time the process took to run. It also contains a pointer to the
163 * [TestCase] this is the output of. 163 * [TestCase] this is the output of.
164 */ 164 */
165 class TestOutput { 165
166 // TODO(zundel): should be abstract?
167 class TestOutput {
168
Bill Hesse 2012/02/28 14:06:38 Could this be an interface? Do interfaces have fa
zundel 2012/02/28 14:12:09 you can put a constructor and provide a default im
169 TestOutput() {
170 }
Bill Hesse 2012/02/28 14:06:38 Is the split between TestOutput and TestOutputImpl
zundel 2012/02/28 14:12:09 On 2012/02/28 14:06:38, Bill Hesse wrote: > Is the
171
Bill Hesse 2012/02/28 14:06:38 I think the factory should just be called TestOutp
zundel 2012/02/28 14:12:09 I agree, BUT it turns out that there is an implici
zundel 2012/02/28 14:22:35 I meant factory constructor. Like this: class Fo
172 factory TestOutput.fromCase (testCase, exitCode, timedOut, stdout, stderr,
173 time) {
174 if (testCase is BrowserTestCase) {
175 return new BrowserTestOutputImpl(testCase, exitCode, timedOut,
176 stdout, stderr, time);
177 } else if (testCase.configuration['component'] == 'dartc') {
178 return new AnalysisTestOutputImpl(testCase, exitCode, timedOut,
179 stdout, stderr, time);
180 }
181 return new TestOutputImpl(testCase, exitCode, timedOut,
182 stdout, stderr, time);
183 }
184
185 abstract String get result();
186
187 abstract bool get unexpectedOutput();
188
189 abstract bool get hasCrashed();
190
191 abstract bool get hasTimedOut();
192
193 abstract bool get didFail();
194
195 List<String> get errors() { return []; }
196
197 List<String> get staticWarnings() { return []; }
198
199 List<String> get warnings() { return []; }
200 }
201
202 class TestOutputImpl extends TestOutput {
166 TestCase testCase; 203 TestCase testCase;
167 int exitCode; 204 int exitCode;
168 bool timedOut; 205 bool timedOut;
169 bool failed = false; 206 bool failed = false;
170 List<String> stdout; 207 List<String> stdout;
171 List<String> stderr; 208 List<String> stderr;
172 Duration time; 209 Duration time;
210
173 /** 211 /**
174 * Set to true if we encounter a condition in the output that indicates we 212 * Set to true if we encounter a condition in the output that indicates we
175 * need to rerun this test. 213 * need to rerun this test.
176 */ 214 */
177 bool requestRetry; 215 bool requestRetry;
178 216
179 TestOutput(this.testCase, this.exitCode, this.timedOut, this.stdout, 217 TestOutputImpl(this.testCase, this.exitCode, this.timedOut, this.stdout,
180 this.stderr, this.time) { 218 this.stderr, this.time) {
181 testCase.output = this; 219 testCase.output = this;
182 requestRetry = false; 220 requestRetry = false;
183 } 221 }
184 222
185 String get result() => 223 String get result() =>
186 hasCrashed ? CRASH : (hasTimedOut ? TIMEOUT : (hasFailed ? FAIL : PASS)); 224 hasCrashed ? CRASH : (hasTimedOut ? TIMEOUT : (hasFailed ? FAIL : PASS));
187 225
188 bool get unexpectedOutput() => !testCase.expectedOutcomes.contains(result); 226 bool get unexpectedOutput() => !testCase.expectedOutcomes.contains(result);
189 227
190 bool get hasCrashed() { 228 bool get hasCrashed() {
191 if (new Platform().operatingSystem() == 'windows') { 229 if (new Platform().operatingSystem() == 'windows') {
192 // The VM uses std::abort to terminate on asserts. 230 // The VM uses std::abort to terminate on asserts.
193 // std::abort terminates with exit code 3 on Windows. 231 // std::abort terminates with exit code 3 on Windows.
194 if (exitCode == 3) { 232 if (exitCode == 3) {
195 return !timedOut; 233 return !timedOut;
196 } 234 }
197 return (!timedOut && (exitCode < 0) && ((0x3FFFFF00 & exitCode) == 0)); 235 return (!timedOut && (exitCode < 0) && ((0x3FFFFF00 & exitCode) == 0));
198 } 236 }
199 // The Java dartc runner exits with code 253 in case of unhandled 237 // The Java dartc runner exits with code 253 in case of unhandled
200 // exceptions. 238 // exceptions.
201 return (!timedOut && ((exitCode < 0) || (exitCode == 253))); 239 return (!timedOut && ((exitCode < 0) || (exitCode == 253)));
202 } 240 }
203 241
204 bool get hasTimedOut() => timedOut; 242 bool get hasTimedOut() => timedOut;
205 243
206 bool get didFail() { 244 bool get didFail() {
207 if (testCase is !BrowserTestCase) return (exitCode != 0 && !hasCrashed); 245 return (exitCode != 0 && !hasCrashed);
246 }
247
248 // Reverse result of a negative test.
249 bool get hasFailed() => (testCase.isNegative ? !didFail : didFail);
250 }
208 251
252 class BrowserTestOutputImpl extends TestOutputImpl {
Bill Hesse 2012/02/28 14:06:38 This is good. A step towards a final refactoring,
253 BrowserTestOutputImpl(testCase, exitCode, timedOut, stdout, stderr, time) :
254 super(testCase, exitCode, timedOut, stdout, stderr, time);
255
256 bool get didFail() {
209 // Browser case: 257 // Browser case:
210 // If the browser test failed, it may have been because DumpRenderTree 258 // If the browser test failed, it may have been because DumpRenderTree
211 // and the virtual framebuffer X server didn't hook up, or DRT crashed with 259 // and the virtual framebuffer X server didn't hook up, or DRT crashed with
212 // a core dump. Sometimes DRT crashes after it has set the stdout to PASS, 260 // a core dump. Sometimes DRT crashes after it has set the stdout to PASS,
213 // so we have to do this check first. 261 // so we have to do this check first.
214 for (String line in stderr) { 262 for (String line in stderr) {
215 if (line.contains('Gtk-WARNING **: cannot open display: :99') || 263 if (line.contains('Gtk-WARNING **: cannot open display: :99') ||
216 line.contains('Failed to run command. return code=1')) { 264 line.contains('Failed to run command. return code=1')) {
217 // If we get the X server error, or DRT crashes with a core dump, retry 265 // If we get the X server error, or DRT crashes with a core dump, retry
218 // the test. 266 // the test.
219 requestRetry = true; 267 requestRetry = true;
220 return true; 268 return true;
221 } 269 }
222 } 270 }
223 271
224 // Browser tests fail unless stdout contains 272 // Browser tests fail unless stdout contains
225 // 'Content-Type: text/plain\nPASS'. 273 // 'Content-Type: text/plain\nPASS'.
226 String previous_line = ''; 274 String previous_line = '';
227 for (String line in stdout) { 275 for (String line in stdout) {
228 if (line == 'PASS' && previous_line == 'Content-Type: text/plain') { 276 if (line == 'PASS' && previous_line == 'Content-Type: text/plain') {
229 return (exitCode != 0 && !hasCrashed); 277 return (exitCode != 0 && !hasCrashed);
230 } 278 }
231 previous_line = line; 279 previous_line = line;
232 } 280 }
233
234 return true; 281 return true;
235 } 282 }
283 }
236 284
237 // Reverse result of a negative test. 285 class AnalysisTestOutputImpl extends TestOutputImpl {
238 bool get hasFailed() => (testCase.isNegative ? !didFail : didFail); 286 final errors;
287 final warnings;
288 final staticWarnings;
289
290 AnalysisTestOutputImpl(testCase, exitCode, timedOut, stdout, stderr, time) :
291 super(testCase, exitCode, timedOut, stdout, stderr, time),
292 errors = new Map<int, String>(),
293 warnings = new Map<int, String>(),
294 staticWarnings = new Map<int, String>() {
295
296 // read the returned list of errors and stuff them away.
297 for (String line in stderr) {
298 if (line.length == 0) continue;
299 List<String> fields = splitMachineError(line);
300 switch(fields[0]) {
301 case "ERROR":
302 errors[fields[4]] = fields;
303 break;
304 case "WARNING":
305 if (fields[1] == "STATIC_TYPE") {
306 staticWarnings[fields[4]] = fields;
307 } else {
308 warnings[fields[4]] = fields;
309 }
310 break;
311 }
Bill Hesse 2012/02/28 14:06:38 Do you want a default case here, or an assert?
zundel 2012/02/28 14:12:09 There is some output to stderr that needs to be ig
312 }
313 }
314
315 bool get didFail() {
316 if (hasCrashed) return false;
317
318 if (this.testCase.commandLine.contains('--fatal-type-errors')) {
319 if (staticWarnings.length != 0) {
320 return true;
321 }
322 } else if (errors.length != 0) {
323 return true;
324 }
325
326 // TODO(zundel): more sophisticated analysis
327
328 return false;
329 //return exitCode != 0;
330 }
331
332 // Parse a line delimited by the | character using \ as an escape charager
333 // like: FOO|BAR|FOO\|BAR|FOO\\BAZ as 4 fields: FOO BAR FOO|BAR FOO\BAZ
334 List<String> splitMachineError(String line) {
335 StringBuffer field = new StringBuffer();
336 List<String> result = [];
337 bool escaped = false;
338 for (var i = 0 ; i < line.length; i++) {
339 var c = line[i];
340 if (!escaped && c == '\\') {
341 escaped = true;
342 continue;
343 }
344 escaped = false;
345 if (c == '|') {
346 result.add(field.toString());
347 field.clear();
348 continue;
349 }
350 field.add(c);
351 }
352 result.add(field.toString());
353 return result;
354 }
239 } 355 }
240 356
241 /** 357 /**
242 * A RunningProcess actually runs a test, getting the command lines from 358 * A RunningProcess actually runs a test, getting the command lines from
243 * its [TestCase], starting the test process (and first, a compilation 359 * its [TestCase], starting the test process (and first, a compilation
244 * process if the TestCase is a [BrowserTestCase]), creating a timeout 360 * process if the TestCase is a [BrowserTestCase]), creating a timeout
245 * timer, and recording the results in a new [TestOutput] object, which it 361 * timer, and recording the results in a new [TestOutput] object, which it
246 * attaches to the TestCase. The lifetime of the RunningProcess is limited 362 * attaches to the TestCase. The lifetime of the RunningProcess is limited
247 * to the time it takes to start the process, run the process, and record 363 * to the time it takes to start the process, run the process, and record
248 * the result; there are no pointers to it, so it should be available to 364 * the result; there are no pointers to it, so it should be available to
249 * be garbage collected as soon as it is done. 365 * be garbage collected as soon as it is done.
250 */ 366 */
251 class RunningProcess { 367 class RunningProcess {
252 ProcessQueue processQueue; 368 ProcessQueue processQueue;
253 Process process; 369 Process process;
254 TestCase testCase; 370 TestCase testCase;
255 bool timedOut = false; 371 bool timedOut = false;
256 Date startTime; 372 Date startTime;
257 Timer timeoutTimer; 373 Timer timeoutTimer;
258 List<String> stdout; 374 List<String> stdout;
259 List<String> stderr; 375 List<String> stderr;
260 List<Function> handlers; 376 List<Function> handlers;
261 bool allowRetries = false; 377 bool allowRetries = false;
262 378
263 RunningProcess(TestCase this.testCase, 379 RunningProcess(TestCase this.testCase,
264 [this.allowRetries, this.processQueue]); 380 [this.allowRetries, this.processQueue]);
265 381
266 void exitHandler(int exitCode) { 382 void exitHandler(int exitCode) {
267 new TestOutput(testCase, exitCode, timedOut, stdout, 383 new TestOutput.fromCase(testCase, exitCode, timedOut, stdout,
268 stderr, new Date.now().difference(startTime)); 384 stderr, new Date.now().difference(startTime));
269 process.close(); 385 process.close();
270 timeoutTimer.cancel(); 386 timeoutTimer.cancel();
271 if (testCase.output.unexpectedOutput && testCase.configuration['verbose']) { 387 if (testCase.output.unexpectedOutput && testCase.configuration['verbose']) {
272 print(testCase.displayName); 388 print(testCase.displayName);
273 for (var line in testCase.output.stderr) print(line); 389 for (var line in testCase.output.stderr) print(line);
274 for (var line in testCase.output.stdout) print(line); 390 for (var line in testCase.output.stdout) print(line);
275 } 391 }
276 if (allowRetries != null && allowRetries 392 if (allowRetries != null && allowRetries
277 && testCase.configuration['component'] == 'webdriver' && 393 && testCase.configuration['component'] == 'webdriver' &&
278 testCase.output.unexpectedOutput && testCase.numRetries > 0) { 394 testCase.output.unexpectedOutput && testCase.numRetries > 0) {
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 565
450 int _reportResult(String output) { 566 int _reportResult(String output) {
451 var test = _currentTest; 567 var test = _currentTest;
452 _currentTest = null; 568 _currentTest = null;
453 569
454 // output = '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}' 570 // output = '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}'
455 var outcome = output.split(" ")[2]; 571 var outcome = output.split(" ")[2];
456 var exitCode = 0; 572 var exitCode = 0;
457 if (outcome == "CRASH") exitCode = -10; 573 if (outcome == "CRASH") exitCode = -10;
458 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1; 574 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1;
459 new TestOutput(test, exitCode, outcome == "TIMEOUT", _testStdout, 575 new TestOutput.fromCase(test, exitCode, outcome == "TIMEOUT", _testStdout,
460 _testStderr, new Date.now().difference(_startTime)); 576 _testStderr, new Date.now().difference(_startTime));
461 test.completed(); 577 test.completed();
462 } 578 }
463 579
464 Function _readOutput(StringInputStream stream, List<String> buffer) { 580 Function _readOutput(StringInputStream stream, List<String> buffer) {
465 return () { 581 return () {
466 var status; 582 var status;
467 var line = stream.readLine(); 583 var line = stream.readLine();
468 // Drain the input stream to get the error output. 584 // Drain the input stream to get the error output.
469 while (line != null) { 585 while (line != null) {
470 if (line.startsWith('>>> TEST')) { 586 if (line.startsWith('>>> TEST')) {
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after
757 // the developer doesn't waste his or her time trying to fix a bunch of 873 // the developer doesn't waste his or her time trying to fix a bunch of
758 // tests that appear to be broken but were actually just flakes that 874 // tests that appear to be broken but were actually just flakes that
759 // didn't get retried because there had already been one failure. 875 // didn't get retried because there had already been one failure.
760 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; 876 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests;
761 new RunningProcess(test, allowRetry, this).start(); 877 new RunningProcess(test, allowRetry, this).start();
762 } 878 }
763 _numProcesses++; 879 _numProcesses++;
764 } 880 }
765 } 881 }
766 } 882 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698