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

Unified Diff: utils/testrunner/testrunner.dart

Issue 10977069: New testrunner that runs the test pipleine in an isolate. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 3 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 side-by-side diff with in-line comments
Download patch
Index: utils/testrunner/testrunner.dart
===================================================================
--- utils/testrunner/testrunner.dart (revision 12980)
+++ utils/testrunner/testrunner.dart (working copy)
@@ -62,6 +62,11 @@
*
* Layout file (re)generation can be done using `--regenerate`. This will
* create or update the layout files (and implicitly pass the tests).
+ *
+ * The wrapping and execution of test files is handled by test_pipeline.dart,
+ * which is run in an isolate. The `--pipeline` argument can be used to
+ * specify a different script for running a test file pipeline, allowing
+ * customization of the pipeline.
*/
// TODO - layout tests that use PNGs rather than DRT text render dumps.
@@ -71,17 +76,7 @@
#import('dart:math');
#import('../../pkg/args/lib/args.dart');
-#source('client_server_task.dart');
-#source('configuration.dart');
-#source('dart_wrap_task.dart');
-#source('dart2js_task.dart');
-#source('delete_task.dart');
-#source('html_wrap_task.dart');
-#source('macros.dart');
#source('options.dart');
-#source('pipeline_runner.dart');
-#source('pipeline_task.dart');
-#source('run_process_task.dart');
#source('utils.dart');
/** The set of [PipelineRunner]s to execute. */
@@ -102,16 +97,13 @@
/** The stream to use for low-value messages, like verbose output. */
OutputStream _logStream;
-/** The full set of options. */
-Configuration config;
-
/**
* The user can specify output streams on the command line, using 'none',
* 'stdout', 'stderr', or a file path; [getStream] will take such a name
* and return an appropriate [OutputStream].
*/
OutputStream getStream(String name) {
- if (name == 'none') {
+ if (name == null || name == 'none') {
return null;
}
if (name == 'stdout') {
@@ -124,86 +116,13 @@
}
/**
- * Generate a templated list of commands that should be executed for each test
- * file. Each command is an instance of a [PipelineTask].
- * The commands can make use of a number of metatokens that will be
- * expanded before execution (see the [Meta] class for details).
- */
-List getPipelineTemplate(String runtime, bool checkedMode, bool keepTests) {
- var pipeline = new List();
- var pathSep = Platform.pathSeparator;
- Directory tempDir = new Directory(config.tempDir);
-
- if (!tempDir.existsSync()) {
- tempDir.createSync();
- }
-
- // Templates for the generated files that are used to run the wrapped test.
- var basePath =
- '${config.tempDir}$pathSep${Macros.flattenedDirectory}_'
- '${Macros.filenameNoExtension}';
- var tempDartFile = '${basePath}.dart';
- var tempJsFile = '${basePath}.js';
- var tempHTMLFile = '${basePath}.html';
- var tempCSSFile = '${basePath}.css';
-
- // Add step for wrapping in Dart scaffold.
- pipeline.add(new DartWrapTask(Macros.fullFilePath, tempDartFile));
-
- // Add the compiler step, unless we are running native Dart.
- if (runtime == 'drt-js') {
- if (checkedMode) {
- pipeline.add(new Dart2jsTask.checked(tempDartFile, tempJsFile));
- } else {
- pipeline.add(new Dart2jsTask(tempDartFile, tempJsFile));
- }
- }
-
- // Add step for wrapping in HTML, if we are running in DRT.
- if (runtime != 'vm') {
- // The user can have pre-existing HTML and CSS files for the test in the
- // same directory and using the same name. The paths to these are matched
- // by these two templates.
- var HTMLFile =
- '${Macros.directory}$pathSep${Macros.filenameNoExtension}.html';
- var CSSFile =
- '${Macros.directory}$pathSep${Macros.filenameNoExtension}.css';
- pipeline.add(new HtmlWrapTask(Macros.fullFilePath,
- HTMLFile, tempHTMLFile, CSSFile, tempCSSFile));
- }
-
- // Add the execution step.
- var command;
- var flags;
- var task;
- if (runtime == 'vm' || config.layoutPixel || config.layoutText) {
- command = config.dartPath;
- if (checkedMode) {
- flags = ['--enable_asserts', '--enable_type_checks', tempDartFile];
- } else {
- flags = [tempDartFile];
- }
- } else {
- command = config.drtPath;
- flags = ['--no-timeout', tempHTMLFile];
- }
- if (config.runServer) {
- task = new RunClientServerTask(command, flags, config.timeout);
- } else {
- task = new RunProcessTask(command, flags, config.timeout);
- }
- pipeline.add(task);
- return pipeline;
-}
-
-/**
* Given a [List] of [testFiles], either print the list or create
* and execute pipelines for the files.
*/
-void processTests(List pipelineTemplate, List testFiles) {
- _outStream = getStream(config.outputStream);
- _logStream = getStream(config.logStream);
- if (config.listFiles) {
+void processTests(Map config, List testFiles) {
+ _outStream = getStream(config['out']);
+ _logStream = getStream(config['log']);
+ if (config['list-files']) {
if (_outStream != null) {
for (var i = 0; i < testFiles.length; i++) {
_outStream.writeString(testFiles[i]);
@@ -211,58 +130,52 @@
}
}
} else {
- // Create execution pipelines for each test file from the pipeline
- // template and the concrete test file path, and then kick
- // off execution of the first batch.
- _tasks = new List();
- for (var i = 0; i < testFiles.length; i++) {
- _tasks.add(new PipelineRunner(pipelineTemplate, testFiles[i],
- config.verbose, completeHandler));
- }
-
- _maxTasks = min(config.maxTasks, testFiles.length);
+ _maxTasks = min(config['tasks'], testFiles.length);
_numTasks = 0;
_nextTask = 0;
- spawnTasks();
+ spawnTasks(config, testFiles);
}
}
/** Execute as many tasks as possible up to the maxTasks limit. */
-void spawnTasks() {
- while (_numTasks < _maxTasks && _nextTask < _tasks.length) {
+void spawnTasks(Map config, List testFiles) {
+ var verbose = config['verbose'];
+ while (_numTasks < _maxTasks && _nextTask < testFiles.length) {
++_numTasks;
- _tasks[_nextTask++].execute();
+ var testfile = testFiles[_nextTask++];
+ config['testfile'] = testfile;
+ ReceivePort port = new ReceivePort();
+ port.receive((msg, _) {
+ port.close();
+ List stdout = msg[0];
+ List stderr = msg[1];
+ List log = msg[2];
+ int exitCode = msg[3];
+ writelog(stdout, _outStream, _logStream, verbose);
+ writelog(stderr, _outStream, _logStream, true);
+ writelog(log, _outStream, _logStream, verbose);
+ --_numTasks;
+ if (exitCode == 0 || !config['stopOnFailure']) {
+ spawnTasks(config, testFiles);
+ }
+ if (_numTasks == 0) {
+ // No outstanding tasks; we're all done.
+ // We could later print a summary report here.
+ }
+ });
+ SendPort s = spawnUri(config['pipeline']);
+ s.send(config, port.toSendPort());
}
}
/**
- * Handle the completion of a task. Kick off more tasks if we
- * have them.
- */
-void completeHandler(String testFile,
- int exitCode,
- List _stdout,
- List _stderr) {
- writelog(_stdout, _outStream, _logStream);
- writelog(_stderr, _outStream, _logStream);
- --_numTasks;
- if (exitCode == 0 || !config.stopOnFailure) {
- spawnTasks();
- }
- if (_numTasks == 0) {
- // No outstanding tasks; we're all done.
- // We could later print a summary report here.
- }
-}
-
-/**
* Our tests are configured so that critical messages have a '###' prefix.
* [writeLog] takes the output from a pipeline execution and writes it to
* our output streams. It will strip the '###' if necessary on critical
* messages; other messages will only be written if verbose output was
* specified.
*/
-void writelog(List messages, OutputStream out, OutputStream log) {
+void writelog(List messages, OutputStream out, OutputStream log, bool verbose) {
for (var i = 0; i < messages.length; i++) {
var msg = messages[i];
if (msg.startsWith('###')) {
@@ -270,7 +183,7 @@
out.writeString(msg.substring(3));
out.writeString('\n');
}
- } else if (config.verbose) {
+ } else if (verbose) {
if (log != null) {
log.writeString(msg);
log.writeString('\n');
@@ -279,6 +192,44 @@
}
}
+sanitizeConfig(Map config, ArgParser parser) {
+ config['layout'] = config['layout-text'] || config['layout-pixel'];
+
+ // TODO - check if next three are actually used.
+ config['runInBrowser'] = (config['runtime'] != 'vm');
+ config['verbose'] = (config['log'] != 'none' && !config['list-groups']);
+ config['filtering'] = (config['include'].length > 0 ||
+ config['exclude'].length > 0);
+
+ config['timeout'] = int.parse(config['timeout']);
+ config['tasks'] = int.parse(config['tasks']);
+
+ config['keep-files'] = (config['keep-files'] &&
+ !(config['list-groups'] || config['list-tests']));
+
+ var dartsdk = config['dartsdk'];
+ var pathSep = Platform.pathSeparator;
+
+ if (dartsdk != null) {
+ if (parser.getDefault('dart2js') == config['dart2js']) {
+ config['dart2js'] =
+ '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}dart2js';
+ }
+ if (parser.getDefault('dart') == config['dart']) {
+ config['dart'] = '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}dart';
+ }
+ if (parser.getDefault('drt') == config['drt']) {
+ config['drt'] = '$dartsdk${pathSep}chromium${pathSep}DumpRenderTree';
+ }
+ }
+
+ config['unittest'] = makePathAbsolute(config['unittest']);
+ config['drt'] = makePathAbsolute(config['drt']);
+ config['dart'] = makePathAbsolute(config['dart']);
+ config['dart2js'] = makePathAbsolute(config['dart2js']);
+ config['runnerDir'] = runnerDirectory;
+}
+
main() {
var optionsParser = getOptionParser();
var options = loadConfiguration(optionsParser);
@@ -288,21 +239,35 @@
} else if (options['list-all-options']) {
printOptions(optionsParser, options, true, stdout);
} else {
- config = new Configuration(optionsParser, options);
- // Build the command templates needed for test compile and execute.
- var pipelineTemplate = getPipelineTemplate(config.runtime,
- config.checkedMode,
- config.keepTests);
- if (pipelineTemplate != null) {
- // Build the list of tests and then execute them.
- List dirs = options.rest;
- if (dirs.length == 0) {
- dirs.add('.'); // Use current working directory as default.
+ var config = new Map();
+ for (var option in options.options) {
+ config[option] = options[option];
+ }
+ var rest = [];
+ // Process the remmaining command line args. If they look like
+ // options then split them up and add them to the map; they may be for
+ // custom pipelines.
+ for (var other in options.rest) {
+ var idx;
+ if (other.startsWith('--') && (idx = other.indexOf('=')) > 0) {
+ var optName = other.substring(2, idx);
+ var optValue = other.substring(idx+1);
+ config[optName] = optValue;
+ } else {
+ rest.add(other);
}
- buildFileList(dirs,
- new RegExp(options['test-file-pattern']), options['recurse'],
- (f) => processTests(pipelineTemplate, f));
}
+
+ sanitizeConfig(config, optionsParser);
+
+ // Build the list of tests and then execute them.
+ List dirs = rest;
+ if (dirs.length == 0) {
+ dirs.add('.'); // Use current working directory as default.
+ }
+ buildFileList(dirs,
+ new RegExp(options['test-file-pattern']), options['recurse'],
+ (f) => processTests(config, f));
}
}
}

Powered by Google App Engine
This is Rietveld 408576698