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

Unified Diff: utils/testrunner/testrunner.dart

Issue 14247033: Updated testrunner: (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « utils/testrunner/standard_test_runner.dart ('k') | utils/testrunner/utils.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: utils/testrunner/testrunner.dart
===================================================================
--- utils/testrunner/testrunner.dart (revision 21957)
+++ utils/testrunner/testrunner.dart (working copy)
@@ -10,7 +10,7 @@
* of the removed features are:
*
* - No support for test.status files. The assumption is that tests are
- * expected to pass.
+ * expected to pass. Status file support will be added in the future.
* - A restricted set of runtimes. The assumption here is that the Dart
* libraries deal with platform dependencies, and so the primary
* SKUs that a user of this app would be concerned with would be
@@ -43,7 +43,7 @@
* vm - run native Dart in the VM; i.e. using $DARTSDK/dart-sdk/bin/dart.
* drt-dart - run native Dart in DumpRenderTree, the headless version of
* Dartium, which is located in $DARTSDK/chromium/DumpRenderTree, if
- * you intsalled the SDK that is bundled with the editor, or available
+ * you installed the SDK that is bundled with the editor, or available
* from http://gsdview.appspot.com/dartium-archive/continuous/
* otherwise.
*
@@ -67,10 +67,27 @@
* 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.
+ *
+ * Wrapper files are created for tests in the tmp directory, which can be
+ * overridden with --tempdir. These files are not removed after the tests
+ * are complete, primarily to reduce the amount of times pub must be
+ * executed. You can use --clean-files to force file cleanup. The temp
+ * directories will have pubspec.yaml files auto-generated unless the
+ * original test file directories have such files; in that case the existing
+ * files will be copied. Whenever a new pubspec file is copied or
+ * created pub will be run (but not otherwise - so if you want to do
+ * the equivelent of pub update you should use --clean-files and the rerun
+ * the tests).
+ *
+ * TODO(gram): if the user has a pubspec.yaml file, we should inspect the
+ * pubspec.lock file and give useful errors:
+ * - if the lock file doesn't exit, then run pub install
+ * - if it exists and it doesn't have the required packages (unittest or
+ * browser), ask the user to add them and run pub install again.
*/
-// TODO - layout tests that use PNGs rather than DRT text render dumps.
library testrunner;
+import 'dart:async';
import 'dart:io';
import 'dart:isolate';
import 'dart:math';
@@ -91,18 +108,24 @@
/** The index of the next pipeline runner to execute. */
int _nextTask;
-/** The stream to use for high-value messages, like test results. */
-OutputStream _outStream;
+/** The sink to use for high-value messages, like test results. */
+IOSink _outSink;
-/** The stream to use for low-value messages, like verbose output. */
-OutputStream _logStream;
+/** The sink to use for low-value messages, like verbose output. */
+IOSink _logSink;
/**
+ * The last temp test directory we accessed; we use this to know if we
+ * need to check the pub configuration.
+ */
+String _testDir;
+
+/**
* 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].
+ * 'stdout', 'stderr', or a file path; [getSink] will take such a name
+ * and return an appropriate [IOSink].
*/
-OutputStream getStream(String name) {
+IOSink getSink(String name) {
if (name == null || name == 'none') {
return null;
}
@@ -112,7 +135,8 @@
if (name == 'stderr') {
return stderr;
}
- return new File(name).openOutputStream(FileMode.WRITE);
+ var f = new File(name);
+ return f.openWrite();
}
/**
@@ -120,13 +144,13 @@
* and execute pipelines for the files.
*/
void processTests(Map config, List testFiles) {
- _outStream = getStream(config['out']);
- _logStream = getStream(config['log']);
+ _outSink = getSink(config['out']);
+ _logSink = getSink(config['log']);
if (config['list-files']) {
- if (_outStream != null) {
+ if (_outSink != null) {
for (var i = 0; i < testFiles.length; i++) {
- _outStream.writeString(testFiles[i]);
- _outStream.writeString('\n');
+ _outSink.write(testFiles[i]);
+ _outSink.write('\n');
}
}
} else {
@@ -137,6 +161,69 @@
}
}
+/**
+ * Create or update a pubspec for the target test directory. We use the
+ * source directory pubspec if available; otherwise we create a minimal one.
+ * We return a Future if we are running pub install, or null otherwise.
+ */
+Future doPubConfig(Path sourcePath, String sourceDir,
+ Path targetPath, String targetDir,
+ String pub, String runtime) {
+ // Make sure the target directory exists.
+ var d = new Directory(targetDir);
+ if (!d.existsSync()) {
+ d.createSync(recursive: true);
+ }
+
+ // If the source has no pubspec, but the dest does, leave
+ // things as they are. If neither do, create one in dest.
+
+ var sourcePubSpecName = new Path(sourceDir).append("pubspec.yaml").
+ toNativePath();
+ var targetPubSpecName = new Path(targetDir).append("pubspec.yaml").
+ toNativePath();
+ var sourcePubSpec = new File(sourcePubSpecName);
+ var targetPubSpec = new File(targetPubSpecName);
+
+ if (!sourcePubSpec.existsSync()) {
+ if (targetPubSpec.existsSync()) {
+ return null;
+ } else {
+ // Create one.
+ if (runtime == 'vm') {
+ writeFile(targetPubSpecName,
+ "name: testrunner\ndependencies:\n unittest: any\n");
+ } else {
+ writeFile(targetPubSpecName,
+ "name: testrunner\ndependencies:\n unittest: any\n browser: any\n");
+ }
+ }
+ } else {
+ if (targetPubSpec.existsSync()) {
+ // If there is a source one, and it is older than the target,
+ // leave the target as is.
+ if (sourcePubSpec.lastModifiedSync().millisecondsSinceEpoch <
+ targetPubSpec.lastModifiedSync().millisecondsSinceEpoch) {
+ return null;
+ }
+ }
+ // Source exists and is newer than target or there is no target;
+ // copy the source to the target. If there is a pubspec.lock file,
+ // copy that too.
+ var s = sourcePubSpec.readAsStringSync();
+ targetPubSpec.writeAsStringSync(s);
+ var sourcePubLock = new File(sourcePubSpecName.replaceAll(".yaml", ".lock"));
+ if (sourcePubLock.existsSync()) {
+ var targetPubLock =
+ new File(targetPubSpecName.replaceAll(".yaml", ".lock"));
+ s = sourcePubLock.readAsStringSync();
+ targetPubLock.writeAsStringSync(s);
+ }
+ }
+ // A new target pubspec was created so run pub install.
+ return _processHelper(pub, [ 'install' ], workingDir: targetDir);
+}
+
/** Execute as many tasks as possible up to the maxTasks limit. */
void spawnTasks(Map config, List testFiles) {
var verbose = config['verbose'];
@@ -154,12 +241,12 @@
List stderr = msg[1];
List log = msg[2];
int exitCode = msg[3];
- writelog(stdout, _outStream, _logStream, verbose, skipNonVerbose);
- writelog(stderr, _outStream, _logStream, true, skipNonVerbose);
- writelog(log, _outStream, _logStream, verbose, skipNonVerbose);
+ writelog(stdout, _outSink, _logSink, verbose, skipNonVerbose);
+ writelog(stderr, _outSink, _logSink, true, skipNonVerbose);
+ writelog(log, _outSink, _logSink, verbose, skipNonVerbose);
port.close();
--_numTasks;
- if (exitCode == 0 || !config['stopOnFailure']) {
+ if (exitCode == 0 || !config['stop-on-failure']) {
spawnTasks(config, testFiles);
}
if (_numTasks == 0) {
@@ -168,74 +255,129 @@
}
});
SendPort s = spawnUri(config['pipeline']);
- s.send(config, port.toSendPort());
+
+ // Get the names of the source and target test files and containing
+ // directories.
+ var testPath = new Path(testfile);
+ var sourcePath = testPath.directoryPath;
+ var sourceDir = sourcePath.toNativePath();
+
+ var targetPath = new Path(config["tempdir"]);
+ var normalizedTarget = testPath.directoryPath.toNativePath()
+ .replaceAll(Platform.pathSeparator, '_')
+ .replaceAll(':', '_');
+ targetPath = targetPath.append("${normalizedTarget}_${config['runtime']}");
+ var targetDir = targetPath.toNativePath();
+
+ config['targetDir'] = targetDir;
+ // If this is a new target dir, we need to redo the pub check.
+ var f = null;
+ if (targetDir != _testDir) {
+ f = doPubConfig(sourcePath, sourceDir, targetPath, targetDir,
+ config['pub'], config['runtime']);
+ _testDir = targetDir;
+ }
+ if (f == null) {
+ s.send(config, port.toSendPort());
+ } else {
+ f.then((_) {
+ s.send(config, port.toSendPort());
+ });
+ break; // Don't do any more until pub is done.
+ }
}
}
/**
* 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
+ * [writelog] takes the output from a pipeline execution and writes it to
+ * our output sinks. 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, IOSink out, IOSink log,
bool includeVerbose, bool skipNonVerbose) {
for (var i = 0; i < messages.length; i++) {
var msg = messages[i];
if (msg.startsWith('###')) {
if (!skipNonVerbose && out != null) {
- out.writeString(msg.substring(3));
- out.writeString('\n');
+ out.write(msg.substring(3));
+ out.write('\n');
}
} else if (msg.startsWith('CONSOLE MESSAGE:')) {
if (!skipNonVerbose && out != null) {
int idx = msg.indexOf('###');
if (idx > 0) {
- out.writeString(msg.substring(idx + 3));
- out.writeString('\n');
+ out.write(msg.substring(idx + 3));
+ out.write('\n');
}
}
} else if (includeVerbose && log != null) {
- log.writeString(msg);
- log.writeString('\n');
+ log.write(msg);
+ log.write('\n');
}
}
}
-sanitizeConfig(Map config, ArgParser parser) {
+normalizeFilter(List filter) {
+ // We want the filter to be a quoted string or list of quoted
+ // strings.
+ for (var i = 0; i < filter.length; i++) {
+ var f = filter[i];
+ if (f[0] != "'" && f[0] != '"') {
+ filter[i] = "'$f'"; // TODO(gram): Quote embedded quotes.
+ }
+ }
+ return filter;
+}
+
+void 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']);
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 (dartsdk == null) {
+ var opt = new Options();
+ var runner = opt.executable;
+ var idx = runner.indexOf('dart-sdk');
+ if (idx < 0) {
+ print("Please use --dartsdk option or run using the dart executable "
+ "from the Dart SDK");
+ exit(0);
}
- 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';
- }
+ dartsdk = runner.substring(0, idx);
}
+ if (Platform.operatingSystem == 'macos') {
+ config['dart2js'] =
+ '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}dart2js';
+ config['dart'] = '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}dart';
+ config['pub'] = '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}pub';
+ config['drt'] =
+ '$dartsdk/chromium/DumpRenderTree.app/Contents/MacOS/DumpRenderTree';
+ } else if (Platform.operatingSystem == 'linux') {
+ config['dart2js'] =
+ '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}dart2js';
+ config['dart'] = '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}dart';
+ config['pub'] = '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}pub';
+ config['drt'] = '$dartsdk${pathSep}chromium${pathSep}DumpRenderTree';
+ } else {
+ config['dart2js'] =
+ '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}dart2js.bat';
+ config['dart'] = '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}dart.exe';
+ config['pub'] = '$dartsdk${pathSep}dart-sdk${pathSep}bin${pathSep}pub.bat';
+ config['drt'] = '$dartsdk${pathSep}chromium${pathSep}DumpRenderTree.exe';
+ }
- config['unittest'] = makePathAbsolute(config['unittest']);
- config['drt'] = makePathAbsolute(config['drt']);
- config['dart'] = makePathAbsolute(config['dart']);
- config['dart2js'] = makePathAbsolute(config['dart2js']);
+ for (var prog in [ 'drt', 'dart', 'pub', 'dart2js' ]) {
+ config[prog] = makePathAbsolute(config[prog]);
+ }
config['runnerDir'] = runnerDirectory;
+ config['include'] = normalizeFilter(config['include']);
+ config['exclude'] = normalizeFilter(config['exclude']);
}
main() {
@@ -245,7 +387,7 @@
if (options['list-options']) {
printOptions(optionsParser, options, false, stdout);
} else if (options['list-all-options']) {
- printOptions(optionsParser, options, true, stdout);
+ printOptions(optionsParser, options, true, stdout);
} else {
var config = new Map();
for (var option in options.options) {
@@ -273,9 +415,10 @@
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));
+ var f = buildFileList(dirs,
+ new RegExp(config['test-file-pattern']), config['recurse']);
+ if (config['sort']) f.sort();
+ processTests(config, f);
}
}
}
« no previous file with comments | « utils/testrunner/standard_test_runner.dart ('k') | utils/testrunner/utils.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698