Add in-process http server to the dart test scripts.

Removed support for extra commands. Change pkg/intl test to use
builtin http server.

Fixed regression in test runner so the test script terminates when
passing in an unknown selector.

BUG=

Review URL: https://codereview.chromium.org//11035027

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@13217 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
ager@google.com 2012-10-04 10:43:48 +00:00
parent 891916ae98
commit c4c4b7f08c
10 changed files with 103 additions and 171 deletions

View file

@ -7,15 +7,6 @@
* to a server.
*/
// TODO(alanknight): It would be nice if there were a more general facility
// than this and it could be replaced, possibly the things Graham is working on.
// The following magical comments will cause the test code run via test.py
// to add an extra command starting up a web server that will serve the
// files we are looking for. "dart" will be replaced by the current dart
// VM, and in arguments, $dartDir will be replaced by the current Dart
// root directory.
// ExtraCommand=dart
// ExtraCommandArgs=$dartDir/pkg/intl/test/start_web_server.dart
#library('date_time_format_http_request_test');
#import('../lib/intl.dart');
@ -24,7 +15,7 @@
#import('dart:html');
#import('../../../pkg/unittest/unittest.dart');
var url = "http://localhost:8000/dates/";
var url = "http://localhost:9876/pkg/intl/lib/src/data/dates/";
main() {
// Initialize one locale just so we know what the list is.
@ -45,4 +36,4 @@ void shutDown() {
// The tiny web server knows to use this request as a cue to terminate.
var source = '${url}terminate';
var request = new HttpRequest.get(source, (_) {});
}
}

View file

@ -1,26 +0,0 @@
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/**
* This file starts a trivial HTTP server to serve locale data files. We start
* it as a separate process, then terminate so that the test can continue to
* run. See web_server.dart for more information.
*/
#import("dart:io");
#import("dart:isolate");
main() {
var thisDir = new File(new Options().script).directorySync();
var serverPath = "${thisDir.path}/web_server.dart";
// TODO(alanknight): This uses nohup and & to stop the child process from
// stopping when we exit. This won't work on Windows.
var p = Process.start(
"nohup",
[new Options().executable, serverPath, "&"]);
p.onExit = (p) => print("Exited abnormally with exit code: $p");
// Give the other process a moment to fully start, and give us a meaningful
// exit code if there's an abnormal exit, before we finish.
new Timer(1000, (t) => exit(0));
}

View file

@ -1,55 +0,0 @@
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/**
* This file runs a trivial HTTP server to serve locale data files from the
* intl/lib/src/data directory. The code is primarily copied from the dart:io
* example at http://www.dartlang.org/articles/io/
*/
#import('dart:io');
#import('dart:isolate');
var server = new HttpServer();
_send404(HttpResponse response) {
response.statusCode = HttpStatus.NOT_FOUND;
response.outputStream.close();
}
startServer(String basePath) {
server.listen('127.0.0.1', 8000);
server.defaultRequestHandler = (HttpRequest request, HttpResponse response) {
var path = request.path;
if (path == '/terminate') {
server.close();
return;
}
final File file = new File('${basePath}${path}');
file.exists().then((bool found) {
if (found) {
// Set the CORS header to allow us to issue requests to localhost when
// the HTML was opened from a file.
response.headers.set("Access-Control-Allow-Origin", "*");
file.fullPath().then((String fullPath) {
file.openInputStream().pipe(response.outputStream);
});
} else {
_send404(response);
}
});
};
}
main() {
// Compute base path for the request based on the location of the
// script and then start the server.
File script = new File(new Options().script);
script.directory().then((Directory d) {
startServer('${d.path}/../lib/src/data');
});
// After 60 seconds, if we haven't already been told to terminate, shut down
// the server, at which point the program exits.
new Timer(60000, (t) {server.close();});
}

View file

@ -26,17 +26,12 @@ intl/test/find_default_locale_standalone_test: Skip
intl/test/find_default_locale_browser_test: Skip
intl/test/date_time_format_http_request_test: Skip
# Skip http request tests on Windows until we are able to spawn
# the http server there.
[ $system == windows]
intl/test/date_time_format_http_request_test: Skip
# Skip http request tests on Dartium while resolving an odd
# error there that causes the tests to timeout.
[ $runtime == dartium || $runtime == drt ]
intl/test/date_time_format_http_request_test: Skip
# Skip intl_message tests that use mirrors on dart2js until it's been
# Skip intl_message tests that use mirrors on dart2js until it's been
# implemented there.
[ $compiler == dart2js ]
intl/test/intl_message_test: Skip

View file

@ -14,6 +14,7 @@
#import("testing/dart/test_runner.dart");
#import("testing/dart/test_options.dart");
#import("testing/dart/test_suite.dart");
#import("testing/dart/http_server.dart");
#import("../tests/co19/test_config.dart");
#import("../runtime/tests/vm/test_config.dart");
@ -66,10 +67,8 @@ main() {
}
var configurationIterator = configurations.iterator();
bool enqueueConfiguration(ProcessQueue queue) {
if (!configurationIterator.hasNext()) {
return false;
}
void enqueueConfiguration(ProcessQueue queue) {
if (!configurationIterator.hasNext()) return;
var conf = configurationIterator.next();
if (selectors.containsKey('co19')) {
@ -88,16 +87,21 @@ main() {
new StandardTestSuite.forDirectory(conf, testSuiteDir));
}
}
return true;
}
// Start global http server that serves the entire dart repo.
// The http server is available on localhost:9876 for any
// test that needs to load resources from the repo over http.
startHttpServer('127.0.0.1', 9876);
// Start process queue.
var queue = new ProcessQueue(maxProcesses,
progressIndicator,
startTime,
printTiming,
enqueueConfiguration,
verbose,
listTests);
new ProcessQueue(
maxProcesses,
progressIndicator,
startTime,
printTiming,
enqueueConfiguration,
() => terminateHttpServer(),
verbose,
listTests);
}

View file

@ -29,6 +29,7 @@
#import("testing/dart/test_options.dart");
#import("testing/dart/test_suite.dart");
#import("testing/dart/test_progress.dart");
#import("testing/dart/http_server.dart");
#import("../compiler/tests/dartc/test_config.dart");
#import("../runtime/tests/vm/test_config.dart");
@ -97,10 +98,8 @@ main() {
}
var configurationIterator = configurations.iterator();
bool enqueueConfiguration(ProcessQueue queue) {
if (!configurationIterator.hasNext()) {
return false;
}
void enqueueConfiguration(ProcessQueue queue) {
if (!configurationIterator.hasNext()) return;
var conf = configurationIterator.next();
for (String key in selectors.getKeys()) {
@ -123,16 +122,21 @@ main() {
new StandardTestSuite.forDirectory(conf, testSuiteDir));
}
}
return true;
}
// Start global http server that serves the entire dart repo.
// The http server is available on localhost:9876 for any
// test that needs to load resources from the repo over http.
startHttpServer('127.0.0.1', 9876);
// Start process queue.
var queue = new ProcessQueue(maxProcesses,
progressIndicator,
startTime,
printTiming,
enqueueConfiguration,
verbose,
listTests);
new ProcessQueue(
maxProcesses,
progressIndicator,
startTime,
printTiming,
enqueueConfiguration,
() => terminateHttpServer(),
verbose,
listTests);
}

View file

@ -0,0 +1,48 @@
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#library('http_server');
#import('dart:io');
#import('test_suite.dart'); // For TestUtils.
HttpServer _httpServer;
startHttpServer(String host, int port) {
var basePath = TestUtils.dartDir();
_httpServer = new HttpServer();
_httpServer.onError = (e) {
// Consider errors in the builtin http server fatal.
// Intead of just throwing the exception we print
// a message that makes it clearer what happened.
print('Test http server error: $e');
exit(1);
};
_httpServer.defaultRequestHandler = (request, resp) {
var requestPath = new Path(request.path).canonicalize();
if (!requestPath.isAbsolute) {
resp.statusCode = HttpStatus.NOT_FOUND;
resp.outputStream.close();
} else {
var path = basePath;
requestPath.segments().forEach((s) => path = path.append(s));
var file = new File(path.toNativePath());
file.exists().then((exists) {
if (exists) {
// Allow loading from localhost in browsers.
resp.headers.set("Access-Control-Allow-Origin", "*");
file.openInputStream().pipe(resp.outputStream);
} else {
resp.statusCode = HttpStatus.NOT_FOUND;
resp.outputStream.close();
}
});
}
};
_httpServer.listen(host, port);
}
terminateHttpServer() {
_httpServer.close();
}

View file

@ -220,7 +220,7 @@ class SilentProgressIndicator extends ProgressIndicator {
}
}
class CompactIndicator extends ProgressIndicator {
abstract class CompactIndicator extends ProgressIndicator {
CompactIndicator(Date startTime, bool printTiming)
: super(startTime, printTiming);
@ -250,7 +250,7 @@ class CompactIndicator extends ProgressIndicator {
void _printStartProgress(TestCase test) => _printProgress();
void _printDoneProgress(TestCase test) => _printProgress();
abstract void _printProgress();
void _printProgress();
}

View file

@ -22,7 +22,7 @@ const int SLOW_TIMEOUT_MULTIPLIER = 4;
typedef void TestCaseEvent(TestCase testCase);
typedef void ExitCodeEvent(int exitCode);
typedef bool EnqueMoreWork(ProcessQueue queue);
typedef bool EnqueueMoreWork(ProcessQueue queue);
/** A command executed as a step in a test case. */
class Command {
@ -953,7 +953,8 @@ class ProcessQueue {
int _MAX_FAILED_NO_RETRY = 4;
bool _verbose;
bool _listTests;
EnqueMoreWork _enqueueMoreWork;
Function _allDone;
EnqueueMoreWork _enqueueMoreWork;
Queue<TestCase> _tests;
ProgressIndicator _progress;
@ -988,6 +989,7 @@ class ProcessQueue {
Date startTime,
bool printTiming,
this._enqueueMoreWork,
this._allDone,
[bool verbose = false,
bool listTests = false])
: _verbose = verbose,
@ -998,7 +1000,7 @@ class ProcessQueue {
printTiming),
_batchProcesses = new Map<String, List<BatchRunnerProcess>>(),
_testCache = new Map<String, List<TestInformation>>() {
if (!_enqueueMoreWork(this)) _progress.allDone();
_checkDone();
}
/**
@ -1019,8 +1021,11 @@ class ProcessQueue {
* and notify our progress indicator that we are done.
*/
void _cleanupAndMarkDone() {
// _progress.allDone() exits the process, so we have to call the
// _allDone callback before.
_allDone();
if (browserUsed != '' && _seleniumServer != null) {
_seleniumServer.kill();
_seleniumServer.kill();
} else {
_progress.allDone();
}
@ -1029,7 +1034,11 @@ class ProcessQueue {
void _checkDone() {
// When there are no more active test listers ask for more work
// from process queue users.
if (_activeTestListers == 0 && !_enqueueMoreWork(this)) {
if (_activeTestListers == 0) {
_enqueueMoreWork(this);
}
// If there is still no work, we are done.
if (_activeTestListers == 0) {
_progress.allTestsKnown();
if (_tests.isEmpty() && _numProcesses == 0) {
_terminateBatchRunners();

View file

@ -445,20 +445,9 @@ class StandardTestSuite implements TestSuite {
List<List<String>> vmOptionsList = getVmOptions(info.optionsFromFile);
Expect.isFalse(vmOptionsList.isEmpty(), "empty vmOptionsList");
// Check for an "ExtraCommand" comment from the file, and generate
// a command for it, if needed.
var optionsFromFile = info.optionsFromFile;
var commands = [];
var command = optionsFromFile['extraCommand'];
var args = optionsFromFile['extraCommandArgs'];
addExtraCommand(command, args, commands);
List _append(list1,list2) => []..addAll(list1)..addAll(list2);
for (var vmOptions in vmOptionsList) {
doTest(new TestCase('$suiteName/$testName',
_append(commands,
makeCommands(info, vmOptions, commonArguments)),
makeCommands(info, vmOptions, commonArguments),
configuration,
completeHandler,
expectations,
@ -523,18 +512,6 @@ class StandardTestSuite implements TestSuite {
}
}
void addExtraCommand(String command, List<String> arguments, List commands) {
if (command == null) return;
// As a special case, a command of "dart" should run with the
// dart VM that we are testing.
if (command == 'dart') {
command = TestUtils.vmFileName(configuration);
}
arguments =
arguments.map((arg)=>arg.replaceAll(r"$dartDir", dartDir.toString()));
commands.add(new Command(command, arguments));
}
CreateTest makeTestCaseCreator(Map optionsFromFile) {
return (Path filePath,
bool hasCompileError,
@ -713,10 +690,6 @@ class StandardTestSuite implements TestSuite {
}
}
var extraCommand = optionsFromFile['extraCommand'];
var extraArgs = optionsFromFile['extraCommandArgs'];
addExtraCommand(extraCommand, extraArgs, commands);
// Construct the command that executes the browser test
List<String> args;
if (runtime == 'ie' || runtime == 'ff' || runtime == 'chrome' ||
@ -995,10 +968,6 @@ class StandardTestSuite implements TestSuite {
const RegExp(r"^#library\(", multiLine: true);
RegExp sourceOrImportRegExp =
const RegExp(r"^#(source|import|resource)\(", multiLine: true);
RegExp extraCommandRegExp =
const RegExp(r"// ExtraCommand=(.*)", multiLine: true);
RegExp extraArgsRegExp =
const RegExp(r"// ExtraCommandArgs=(.*)", multiLine: true);
// Read the entire file into a byte buffer and transform it to a
// String. This will treat the file as ascii but the only parts
@ -1035,11 +1004,6 @@ class StandardTestSuite implements TestSuite {
dartOptions = match[1].split(' ').filter((e) => e != '');
}
var match = extraCommandRegExp.firstMatch(contents);
var extraCommand = (match != null) ? match.group(1) : null;
match = extraArgsRegExp.firstMatch(contents);
var extraCommandArgs = (match != null) ? match.group(1).split(' ') : [];
matches = staticCleanRegExp.allMatches(contents);
for (var match in matches) {
if (isStaticClean) {
@ -1084,9 +1048,7 @@ class StandardTestSuite implements TestSuite {
"isLibraryDefinition": isLibraryDefinition,
"containsSourceOrImport": containsSourceOrImport,
"numStaticTypeAnnotations": numStaticTypeAnnotations,
"numCompileTimeAnnotations": numCompileTimeAnnotations,
"extraCommand": extraCommand,
"extraCommandArgs": extraCommandArgs};
"numCompileTimeAnnotations": numCompileTimeAnnotations };
}
List<List<String>> getVmOptions(Map optionsFromFile) {