Index: tools/testing/dart/test_runner.dart |
=================================================================== |
--- tools/testing/dart/test_runner.dart (revision 4831) |
+++ tools/testing/dart/test_runner.dart (working copy) |
@@ -128,6 +128,8 @@ |
List<String> get batchTestArguments() => commands.last().arguments; |
void completed() { completedHandler(this); } |
+ |
+ bool get usesWebDriver() => configuration['component'] == 'webdriver'; |
} |
@@ -286,8 +288,8 @@ |
for (var line in testCase.output.stdout) print(line); |
} |
if (allowRetries != null && allowRetries |
- && testCase.configuration['component'] == 'webdriver' && |
- testCase.output.unexpectedOutput && testCase.numRetries > 0) { |
+ && testCase.usesWebDriver && testCase.output.unexpectedOutput |
+ && testCase.numRetries > 0) { |
// Selenium tests can be flaky. Try rerunning. |
testCase.output.requestRetry = true; |
} |
@@ -321,8 +323,8 @@ |
} else { |
stderr.add('test.dart: Compilion finished $suffix\n'); |
stdout.add('test.dart: Compilion finished $suffix\n'); |
- if (currentStep == totalSteps - 1 |
- && testCase.configuration['component'] == 'webdriver') { |
+ if (currentStep == totalSteps - 1 && testCase.usesWebDriver && |
+ !testCase.configuration['noBatch']) { |
// Note: processQueue will always be non-null for component == webdriver |
// (It is only null for component == vm) |
processQueue._getBatchRunner(testCase).startTest(testCase); |
@@ -400,7 +402,7 @@ |
BatchRunnerProcess(TestCase testCase) { |
_executable = testCase.commands.last().executable; |
_batchArguments = testCase.batchRunnerArguments; |
- _isWebDriver = testCase.configuration['component'] == 'webdriver'; |
+ _isWebDriver = testCase.usesWebDriver; |
} |
bool get active() => _currentTest != null; |
@@ -605,7 +607,14 @@ |
* String indicating the browser used to run the tests. Empty if no browser |
* used. |
*/ |
- String browserUsed; |
+ String browserUsed = ''; |
+ /** |
+ * Process running the selenium server .jar (only used for Safari and Opera |
+ * tests.) |
+ */ |
+ Process _seleniumServer = null; |
+ /** True if we are in the process of starting the server. */ |
+ bool _startingServer = false; |
ProcessQueue(int this._maxProcesses, |
String progress, |
@@ -622,7 +631,6 @@ |
_batchProcesses = new Map<String, List<BatchRunnerProcess>>(), |
_testCache = new Map<String, List<TestInformation>>() { |
if (!_enqueueMoreWork(this)) _progress.allDone(); |
- browserUsed = ''; |
} |
/** |
@@ -698,6 +706,9 @@ |
void _cleanupAndMarkDone() { |
if (browserUsed != '') { |
killZombieBrowsers(); |
+ if (_isSeleniumAvailable) { |
+ _seleniumServer.kill(); |
+ } |
} else { |
_progress.allDone(); |
} |
@@ -736,16 +747,92 @@ |
} |
} |
} |
+ |
+ /** |
+ * True if we are using a browser + platform combination that needs the |
+ * Selenium server jar. |
+ */ |
+ bool get _needsSelenium() => new Platform().operatingSystem() == 'macos' && |
+ browserUsed == 'safari'; |
+ /** True if the Selenium Server is ready to be used. */ |
+ bool get _isSeleniumAvailable() => _seleniumServer != null; |
+ |
+ /** Start the Selenium Server jar, if appropriate for this platform. */ |
+ void _ensureSeleniumServerRunning() { |
+ if (!_isSeleniumAvailable && _startingServer == false) { |
+ _startingServer = true; |
+ _startSeleniumServer(); |
+ } |
+ } |
+ |
void _runTest(TestCase test) { |
- if (test.configuration['component'] == 'webdriver') { |
+ if (test.usesWebDriver) { |
browserUsed = test.configuration['browser']; |
+ if (_needsSelenium) _ensureSeleniumServerRunning(); |
} |
_progress.testAdded(); |
_tests.add(test); |
_tryRunTest(); |
} |
+ /** |
+ * Monitor the output of the Selenium server, to know when we are ready to |
+ * begin running tests. |
+ * source: Output(Stream) from the Java server. |
+ */ |
+ Function makeSeleniumServerHandler(StringInputStream source) { |
+ return () { |
+ if (source.closed) return; // TODO(whesse): Remove when bug is fixed. |
+ var line = source.readLine(); |
+ while (null != line) { |
+ if (const RegExp(@".*Started.*Server.*").hasMatch(line) || |
+ const RegExp(@"Exception.*Selenium is already running.*").hasMatch( |
+ line)) { |
+ for (int i = 0; i < _maxProcesses; i++) { |
+ // Restart all the processes that have been waiting/stopped for |
+ // the server to start up. If we just call this once we end up |
+ // with a single-"threaded" run. |
+ _tryRunTest(); |
+ } |
+ } |
+ line = source.readLine(); |
+ } |
+ }; |
+ } |
+ |
+ /** |
+ * For browser tests using Safari or Opera, we need to use the Selenium 1.0 |
+ * Java server. |
+ */ |
+ void _startSeleniumServer() { |
+ // Get the absolute path to the Selenium jar. |
+ String filePath = new Options().script; |
+ String pathSep = new Platform().pathSeparator(); |
+ int index = filePath.lastIndexOf(pathSep); |
+ filePath = filePath.substring(0, index) + '${pathSep}testing${pathSep}'; |
+ var dir = new Directory(filePath); |
+ dir.onFile = (String file) { |
+ if (const RegExp(@"selenium-server-standalone-.*\.jar").hasMatch(file) |
+ && _seleniumServer == null) { |
+ _seleniumServer = new Process.start('java', ['-jar', file]); |
+ // Heads up: there seems to an obscure data race of some form in |
+ // the VM between launching the server process and launching the test |
+ // tasks that disappears when you read IO (which is convenient, since |
+ // that is our condition for knowing that the server is ready). |
+ StringInputStream stdoutStringStream = |
+ new StringInputStream(_seleniumServer.stdout); |
+ StringInputStream stderrStringStream = |
+ new StringInputStream(_seleniumServer.stderr); |
+ stdoutStringStream.onLine = |
+ makeSeleniumServerHandler(stdoutStringStream); |
+ stderrStringStream.onLine = |
+ makeSeleniumServerHandler(stderrStringStream); |
+ } |
+ }; |
+ dir.list(); |
+ } |
+ |
void _terminateBatchRunners() { |
for (var runners in _batchProcesses.getValues()) { |
for (var runner in runners) { |
@@ -785,6 +872,12 @@ |
tab + Strings.join(test.commands.last().arguments, tab)); |
return; |
} |
+ if (test.usesWebDriver && _needsSelenium && !_isSeleniumAvailable) { |
+ // The server is not ready to run Selenium tests. Put them back in the |
+ // queue. |
+ _tests.addFirst(test); |
+ return; |
+ } |
_progress.start(test); |
Function oldCallback = test.completedHandler; |
Function wrapper = (TestCase test_arg) { |