mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 12:24:24 +00:00
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:
parent
891916ae98
commit
c4c4b7f08c
10 changed files with 103 additions and 171 deletions
|
@ -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, (_) {});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -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();});
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
48
tools/testing/dart/http_server.dart
Normal file
48
tools/testing/dart/http_server.dart
Normal 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();
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue