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

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

Issue 9347023: Add dartdoc comments to Dart testing infrastructure. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments. Created 8 years, 10 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
« no previous file with comments | « no previous file | tools/testing/dart/test_suite.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #library("test_runner");
6
7 #import("dart:io");
8 #import("status_file_parser.dart");
9 #import("test_progress.dart");
10 #import("test_suite.dart");
11
12 /** 5 /**
13 * Classes and methods for executing tests. 6 * Classes and methods for executing tests.
14 * 7 *
15 * This module includes: 8 * This module includes:
16 * - Managing parallel execution of tests, including timeout checks. 9 * - Managing parallel execution of tests, including timeout checks.
17 * - Evaluating the output of each test as pass/fail/crash/timeout. 10 * - Evaluating the output of each test as pass/fail/crash/timeout.
18 */ 11 */
12 #library("test_runner");
13
14 #import("dart:io");
15 #import("status_file_parser.dart");
16 #import("test_progress.dart");
17 #import("test_suite.dart");
19 18
20 final int NO_TIMEOUT = 0; 19 final int NO_TIMEOUT = 0;
21 20
22 21 /**
22 * TestCase contains all the information needed to run a test and evaluate
23 * its output. Running a test involves starting a separate process, with
24 * the executable and arguments given by the TestCase, and recording its
25 * stdout and stderr output streams, and its exit code. TestCase only
26 * contains static information about the test; actually running the test is
27 * performed by [ProcessQueue] using a [RunningProcess] object.
28 *
29 * The output information is stored in a [TestOutput] instance contained
30 * in the TestCase. The TestOutput instance is responsible for evaluating
31 * if the test has passed, failed, crashed, or timed out, and the TestCase
32 * has information about what the expected result of the test should be.
33 *
34 * The TestCase has a callback function, [completedHandler], that is run when
35 * the test is completed.
36 */
23 class TestCase { 37 class TestCase {
24 String executablePath; 38 String executablePath;
25 List<String> arguments; 39 List<String> arguments;
26 Map configuration; 40 Map configuration;
27 String commandLine; 41 String commandLine;
28 String displayName; 42 String displayName;
29 TestOutput output; 43 TestOutput output;
30 bool isNegative; 44 bool isNegative;
31 Set<String> expectedOutcomes; 45 Set<String> expectedOutcomes;
32 Function completedHandler; 46 Function completedHandler;
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
82 final mode = configuration['mode']; 96 final mode = configuration['mode'];
83 final arch = configuration['arch']; 97 final arch = configuration['arch'];
84 return "$component ${mode}_$arch"; 98 return "$component ${mode}_$arch";
85 } 99 }
86 100
87 void completed() { completedHandler(this); } 101 void completed() { completedHandler(this); }
88 } 102 }
89 103
90 104
91 /** 105 /**
92 * BrowserTestCase has an extra compilation command that is run by 106 * BrowserTestCase has an extra compilation command that is run in a separate
93 * RunningProcess.start(), and it checks conditions on the test output 107 * process, before the regular test is run as in the base class [TestCase].
94 * in TestOutput.didFail(). 108 * If the compilation command fails, then the rest of the test is not run.
95 */ 109 */
96 class BrowserTestCase extends TestCase { 110 class BrowserTestCase extends TestCase {
111 /**
112 * The executable that is run in a new process in the compilation phase.
113 */
97 String compilerPath; 114 String compilerPath;
115 /**
116 * The arguments for the compilation command.
117 */
98 List<String> compilerArguments; 118 List<String> compilerArguments;
99 /** 119 /**
100 * Indicates if this test is a rerun, to compensate for flaky browser tests. 120 * Indicates if this test is a rerun, to compensate for flaky browser tests.
101 */ 121 */
102 bool isRerun; 122 bool isRerun;
103 123
104 BrowserTestCase(displayName, 124 BrowserTestCase(displayName,
105 this.compilerPath, 125 this.compilerPath,
106 this.compilerArguments, 126 this.compilerArguments,
107 executablePath, 127 executablePath,
108 arguments, 128 arguments,
109 configuration, 129 configuration,
110 completedHandler, 130 completedHandler,
111 expectedOutcomes, 131 expectedOutcomes,
112 [isNegative = false]) : super(displayName, 132 [isNegative = false]) : super(displayName,
113 executablePath, 133 executablePath,
114 arguments, 134 arguments,
115 configuration, 135 configuration,
116 completedHandler, 136 completedHandler,
117 expectedOutcomes, 137 expectedOutcomes,
118 isNegative) { 138 isNegative) {
119 if (compilerPath != null) { 139 if (compilerPath != null) {
120 commandLine = 'execution command: $commandLine'; 140 commandLine = 'execution command: $commandLine';
121 String compilationCommand = 141 String compilationCommand =
122 '$compilerPath ${Strings.join(compilerArguments, " ")}'; 142 '$compilerPath ${Strings.join(compilerArguments, " ")}';
123 commandLine = 'compilation command: $compilationCommand\n$commandLine'; 143 commandLine = 'compilation command: $compilationCommand\n$commandLine';
124 } 144 }
125 isRerun = false; 145 isRerun = false;
126 } 146 }
127 } 147 }
128 148
129 149
150 /**
151 * TestOutput records the output of a completed test: the process's exit code,
152 * the standard output and standard error, whether the process timed out, and
153 * the time the process took to run. It also contains a pointer to the
154 * [TestCase] this is the output of.
155 */
130 class TestOutput { 156 class TestOutput {
131 // The TestCase this is the output from.
132 TestCase testCase; 157 TestCase testCase;
133 int exitCode; 158 int exitCode;
134 bool timedOut; 159 bool timedOut;
135 bool failed = false; 160 bool failed = false;
136 List<String> stdout; 161 List<String> stdout;
137 List<String> stderr; 162 List<String> stderr;
138 Duration time; 163 Duration time;
139 164
140 TestOutput(this.testCase, this.exitCode, this.timedOut, this.stdout, 165 TestOutput(this.testCase, this.exitCode, this.timedOut, this.stdout,
141 this.stderr, this.time) { 166 this.stderr, this.time) {
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 return testCase.isNegative; 211 return testCase.isNegative;
187 } 212 }
188 } 213 }
189 return true; 214 return true;
190 } 215 }
191 216
192 // Reverse result of a negative test. 217 // Reverse result of a negative test.
193 bool get hasFailed() => (testCase.isNegative ? !didFail : didFail); 218 bool get hasFailed() => (testCase.isNegative ? !didFail : didFail);
194 } 219 }
195 220
196 221 /**
222 * A RunningProcess actually runs a test, getting the command lines from
223 * its [TestCase], starting the test process (and first, a compilation
224 * process if the TestCase is a [BrowserTestCase]), creating a timeout
225 * timer, and recording the results in a new [TestOutput] object, which it
226 * attaches to the TestCase. The lifetime of the RunningProcess is limited
227 * to the time it takes to start the process, run the process, and record
228 * the result; there are no pointers to it, so it should be available to
229 * be garbage collected as soon as it is done.
230 */
197 class RunningProcess { 231 class RunningProcess {
198 Process process; 232 Process process;
199 TestCase testCase; 233 TestCase testCase;
200 bool timedOut = false; 234 bool timedOut = false;
201 Date startTime; 235 Date startTime;
202 Timer timeoutTimer; 236 Timer timeoutTimer;
203 List<String> stdout; 237 List<String> stdout;
204 List<String> stderr; 238 List<String> stderr;
205 List<Function> handlers; 239 List<Function> handlers;
206 240
207 RunningProcess(this.testCase); 241 RunningProcess(TestCase this.testCase);
208 242
209 void exitHandler(int exitCode) { 243 void exitHandler(int exitCode) {
210 new TestOutput(testCase, exitCode, timedOut, stdout, 244 new TestOutput(testCase, exitCode, timedOut, stdout,
211 stderr, new Date.now().difference(startTime)); 245 stderr, new Date.now().difference(startTime));
212 process.close(); 246 process.close();
213 timeoutTimer.cancel(); 247 timeoutTimer.cancel();
214 if (testCase.output.unexpectedOutput && testCase.configuration['verbose']) { 248 if (testCase.output.unexpectedOutput && testCase.configuration['verbose']) {
215 print(testCase.output.stdout); 249 print(testCase.output.stdout);
216 print(testCase.output.stderr); 250 print(testCase.output.stderr);
217 } 251 }
218 if (testCase is BrowserTestCase && testCase.output.unexpectedOutput && 252 if (testCase is BrowserTestCase && testCase.output.unexpectedOutput &&
219 !testCase.isRerun) { 253 !testCase.isRerun) {
220 // Selenium tests can be flaky. Try rerunning. 254 // Selenium tests can be flaky. Try rerunning.
221 testCase.isRerun = true; 255 testCase.isRerun = true;
222 this.timedOut = false; 256 this.timedOut = false;
223 this.start(); 257 this.start();
224 } else { 258 } else {
225 testCase.completed(); 259 testCase.completed();
226 } 260 }
227 } 261 }
228 262
229 void compilerExitHandler(int exitCode) { 263 void compilerExitHandler(int exitCode) {
230 if (exitCode != 0) { 264 if (exitCode != 0) {
231 stderr.add('test.dart: Compilation step failed (exit code $exitCode)\n'); 265 stderr.add('test.dart: Compilation step failed (exit code $exitCode)\n');
232 exitHandler(exitCode); 266 exitHandler(exitCode);
233 } else { 267 } else {
234 process.close(); 268 process.close();
235 stderr.add('test.dart: Compilation finished, starting execution\n'); 269 stderr.add('test.dart: Compilation finished, starting execution\n');
236 stdout.add('test.dart: Compilation finished, starting execution\n'); 270 stdout.add('test.dart: Compilation finished, starting execution\n');
237 runCommand(testCase.executablePath, testCase.arguments, exitHandler); 271 runCommand(testCase.executablePath, testCase.arguments, exitHandler);
238 } 272 }
239 } 273 }
240 274
241 Function makeReadHandler(StringInputStream source, List<String> destination) { 275 Function makeReadHandler(StringInputStream source, List<String> destination) {
242 return () { 276 return () {
243 if (source.closed) return; // TODO(whesse): Remove when bug is fixed. 277 if (source.closed) return; // TODO(whesse): Remove when bug is fixed.
244 var line = source.readLine(); 278 var line = source.readLine();
245 while (null != line) { 279 while (null != line) {
246 destination.add(line); 280 destination.add(line);
247 line = source.readLine(); 281 line = source.readLine();
248 } 282 }
249 }; 283 };
250 } 284 }
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 bool get active() => _currentTest != null; 344 bool get active() => _currentTest != null;
311 345
312 void startTest(TestCase testCase) { 346 void startTest(TestCase testCase) {
313 _currentTest = testCase; 347 _currentTest = testCase;
314 if (_process === null) { 348 if (_process === null) {
315 // Start process if not yet started. 349 // Start process if not yet started.
316 _executable = testCase.executablePath; 350 _executable = testCase.executablePath;
317 _startProcess(() { 351 _startProcess(() {
318 doStartTest(testCase); 352 doStartTest(testCase);
319 }); 353 });
320 } else if (testCase.executablePath != _executable) { 354 } else if (testCase.executablePath != _executable) {
321 // Restart this runner with the right executable for this test 355 // Restart this runner with the right executable for this test
322 // if needed. 356 // if needed.
323 _executable = testCase.executablePath; 357 _executable = testCase.executablePath;
324 _process.exitHandler = (exitCode) { 358 _process.exitHandler = (exitCode) {
325 _process.close(); 359 _process.close();
326 _startProcess(() { 360 _startProcess(() {
327 doStartTest(testCase); 361 doStartTest(testCase);
328 }); 362 });
329 }; 363 };
330 _process.kill(); 364 _process.kill();
331 } else { 365 } else {
332 doStartTest(testCase); 366 doStartTest(testCase);
333 } 367 }
334 } 368 }
335 369
336 void terminate() { 370 void terminate() {
337 if (_process !== null) { 371 if (_process !== null) {
338 _process.exitHandler = (exitCode) { 372 _process.exitHandler = (exitCode) {
339 _process.close(); 373 _process.close();
340 }; 374 };
341 _process.kill(); 375 _process.kill();
342 } 376 }
343 } 377 }
344 378
345 void doStartTest(TestCase testCase) { 379 void doStartTest(TestCase testCase) {
346 _startTime = new Date.now(); 380 _startTime = new Date.now();
347 _testStdout = new List<String>(); 381 _testStdout = new List<String>();
348 _testStderr = new List<String>(); 382 _testStderr = new List<String>();
349 _stdoutStream.lineHandler = _readOutput(_stdoutStream, _testStdout); 383 _stdoutStream.lineHandler = _readOutput(_stdoutStream, _testStdout);
350 _stderrStream.lineHandler = _readOutput(_stderrStream, _testStderr); 384 _stderrStream.lineHandler = _readOutput(_stderrStream, _testStderr);
351 _timer = new Timer(_timeoutHandler(testCase), testCase.timeout * 1000); 385 _timer = new Timer(_timeoutHandler(testCase), testCase.timeout * 1000);
352 _process.stdin.write(_createArgumentsLine(testCase.arguments).charCodes()); 386 _process.stdin.write(_createArgumentsLine(testCase.arguments).charCodes());
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
403 _startProcess(() { 437 _startProcess(() {
404 _reportResult(">>> TEST CRASH"); 438 _reportResult(">>> TEST CRASH");
405 }); 439 });
406 } 440 }
407 441
408 Function _timeoutHandler(TestCase test) { 442 Function _timeoutHandler(TestCase test) {
409 return (ignore) { 443 return (ignore) {
410 _process.exitHandler = (exitCode) { 444 _process.exitHandler = (exitCode) {
411 _process.close(); 445 _process.close();
412 _startProcess(() { 446 _startProcess(() {
413 _reportResult(">>> TEST TIMEOUT"); 447 _reportResult(">>> TEST TIMEOUT");
414 }); 448 });
415 }; 449 };
416 _process.kill(); 450 _process.kill();
417 }; 451 };
418 } 452 }
419 453
420 void _startProcess(then) { 454 void _startProcess(then) {
421 _process = new Process.start(_executable, ['-batch']); 455 _process = new Process.start(_executable, ['-batch']);
422 _stdoutStream = new StringInputStream(_process.stdout); 456 _stdoutStream = new StringInputStream(_process.stdout);
423 _stderrStream = new StringInputStream(_process.stderr); 457 _stderrStream = new StringInputStream(_process.stderr);
424 _testStdout = new List<String>(); 458 _testStdout = new List<String>();
425 _testStderr = new List<String>(); 459 _testStderr = new List<String>();
426 _stdoutStream.lineHandler = _readOutput(_stdoutStream, _testStdout); 460 _stdoutStream.lineHandler = _readOutput(_stdoutStream, _testStdout);
427 _stderrStream.lineHandler = _readOutput(_stderrStream, _testStderr); 461 _stderrStream.lineHandler = _readOutput(_stderrStream, _testStderr);
428 _process.exitHandler = _exitHandler; 462 _process.exitHandler = _exitHandler;
429 _process.startHandler = then; 463 _process.startHandler = then;
430 } 464 }
431 } 465 }
432 466
433 467
468 /**
469 * ProcessQueue is the master control class, responsible for running all
470 * the tests in all the TestSuites that have been registered. It includes
471 * a rate-limited queue to run a limited number of tests in parallel,
472 * a ProgressIndicator which prints output when tests are started and
473 * and completed, and a summary report when all tests are completed,
474 * and counters to determine when all of the tests in all of the test suites
475 * have completed.
476 *
477 * Because multiple configurations may be run on each test suite, the
478 * ProcessQueue contains a cache in which a test suite may record information
479 * about its list of tests, and may retrieve that information when it is called
480 * upon to enqueue its tests again.
481 */
434 class ProcessQueue { 482 class ProcessQueue {
435 int _numProcesses = 0; 483 int _numProcesses = 0;
436 int _activeTestListers = 0; 484 int _activeTestListers = 0;
437 int _maxProcesses; 485 int _maxProcesses;
438 bool _verbose; 486 bool _verbose;
439 bool _listTests; 487 bool _listTests;
440 bool _keepGeneratedTests; 488 bool _keepGeneratedTests;
441 Function _enqueueMoreWork; 489 Function _enqueueMoreWork;
442 Queue<TestCase> _tests; 490 Queue<TestCase> _tests;
443 ProgressIndicator _progress; 491 ProgressIndicator _progress;
444 String _temporaryDirectory; 492 String _temporaryDirectory;
445 // For dartc batch processing we keep a list of batch processes. 493 // For dartc batch processing we keep a list of batch processes.
446 List<DartcBatchRunnerProcess> _batchProcesses; 494 List<DartcBatchRunnerProcess> _batchProcesses;
495
447 // Cache information about test cases per test suite. For multiple 496 // Cache information about test cases per test suite. For multiple
448 // configurations there is no need to repeatedly search the file 497 // configurations there is no need to repeatedly search the file
449 // system, generate tests, and search test files for options. 498 // system, generate tests, and search test files for options.
450 Map<String, List<TestInformation>> _testCache; 499 Map<String, List<TestInformation>> _testCache;
451 500
452 ProcessQueue(int this._maxProcesses, 501 ProcessQueue(int this._maxProcesses,
453 String progress, 502 String progress,
454 Date startTime, 503 Date startTime,
455 bool printTiming, 504 bool printTiming,
456 Function this._enqueueMoreWork, 505 Function this._enqueueMoreWork,
457 [bool this._verbose = false, 506 [bool this._verbose = false,
458 bool this._listTests = false, 507 bool this._listTests = false,
459 bool this._keepGeneratedTests = false]) 508 bool this._keepGeneratedTests = false])
460 : _tests = new Queue<TestCase>(), 509 : _tests = new Queue<TestCase>(),
461 _progress = new ProgressIndicator.fromName(progress, 510 _progress = new ProgressIndicator.fromName(progress,
462 startTime, 511 startTime,
463 printTiming), 512 printTiming),
464 _batchProcesses = new List<DartcBatchRunnerProcess>(), 513 _batchProcesses = new List<DartcBatchRunnerProcess>(),
465 _testCache = new Map<String, List<TestInformation>>() { 514 _testCache = new Map<String, List<TestInformation>>() {
466 if (!_enqueueMoreWork(this)) _progress.allDone(); 515 if (!_enqueueMoreWork(this)) _progress.allDone();
467 } 516 }
468 517
518 /**
519 * Registers a TestSuite so that all of its tests will be run.
520 */
469 void addTestSuite(TestSuite testSuite) { 521 void addTestSuite(TestSuite testSuite) {
470 _activeTestListers++; 522 _activeTestListers++;
471 testSuite.forEachTest(_runTest, _testCache, globalTemporaryDirectory, 523 testSuite.forEachTest(_runTest, _testCache, globalTemporaryDirectory,
472 _testListerDone); 524 _testListerDone);
473 } 525 }
474 526
475 void _testListerDone() { 527 void _testListerDone() {
476 _activeTestListers--; 528 _activeTestListers--;
477 _checkDone(); 529 _checkDone();
478 } 530 }
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
577 test.displayName != 'dartc/junit_tests') { 629 test.displayName != 'dartc/junit_tests') {
578 _ensureDartcBatchRunnersStarted(test.executablePath); 630 _ensureDartcBatchRunnersStarted(test.executablePath);
579 _getDartcBatchRunnerProcess().startTest(test); 631 _getDartcBatchRunnerProcess().startTest(test);
580 } else { 632 } else {
581 new RunningProcess(test).start(); 633 new RunningProcess(test).start();
582 } 634 }
583 _numProcesses++; 635 _numProcesses++;
584 } 636 }
585 } 637 }
586 } 638 }
OLDNEW
« no previous file with comments | « no previous file | tools/testing/dart/test_suite.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698