blob: 654226bd097970bad0a43e68721a2f30debcdb9f [file] [log] [blame]
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.junit;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import java.util.HashSet;
import java.util.Set;
/**
* Runs in Production Mode via browsers managed as an external process. This
* feature is experimental and is not officially supported.
*/
class RunStyleExternalBrowser extends RunStyle {
private static class ExternalBrowser {
String browserPath;
Process process;
public ExternalBrowser(String browserPath) {
this.browserPath = browserPath;
}
public String getPath() {
return browserPath;
}
public Process getProcess() {
return process;
}
public void setProcess(Process process) {
this.process = process;
}
}
/**
* Registered as a shutdown hook to make sure that any browsers that were not
* finished are killed.
*/
private class ShutdownCb extends Thread {
@Override
public void run() {
for (ExternalBrowser browser : externalBrowsers) {
if (browser.getProcess() != null) {
try {
browser.getProcess().exitValue();
} catch (IllegalThreadStateException e) {
// The process is still active. Kill it.
browser.getProcess().destroy();
}
}
}
}
}
private ExternalBrowser[] externalBrowsers;
/**
* @param shell the containing shell
*/
public RunStyleExternalBrowser(JUnitShell shell) {
super(shell);
}
@Override
public String[] getInterruptedHosts() {
// Make sure all browsers are still running
Set<String> toRet = null;
for (ExternalBrowser browser : externalBrowsers) {
try {
browser.getProcess().exitValue();
// The host exited, so return its path.
if (toRet == null) {
toRet = new HashSet<String>();
}
toRet.add(browser.getPath());
} catch (IllegalThreadStateException e) {
// The process is still active, keep looking.
}
}
return toRet == null ? null : toRet.toArray(new String[toRet.size()]);
}
@Override
public int initialize(String args) {
if (args == null || args.length() == 0) {
getLogger().log(
TreeLogger.ERROR,
"ExternalBrowser runstyle requires an "
+ "argument listing one or more executables of external browsers to "
+ "launch");
return -1;
}
String browsers[] = args.split(",");
synchronized (this) {
this.externalBrowsers = new ExternalBrowser[browsers.length];
for (int i = 0; i < browsers.length; ++i) {
externalBrowsers[i] = new ExternalBrowser(browsers[i]);
}
}
Runtime.getRuntime().addShutdownHook(new ShutdownCb());
return browsers.length;
}
@Override
public synchronized void launchModule(String moduleName)
throws UnableToCompleteException {
String commandArray[] = new String[2];
// construct the URL for the browser to hit
commandArray[1] = shell.getModuleUrl(moduleName);
Process child = null;
for (ExternalBrowser browser : externalBrowsers) {
try {
commandArray[0] = browser.getPath();
child = Runtime.getRuntime().exec(commandArray);
if (child == null) {
getLogger().log(TreeLogger.ERROR,
"Problem exec()'ing " + commandArray[0]);
throw new UnableToCompleteException();
}
} catch (Exception e) {
getLogger().log(TreeLogger.ERROR,
"Error launching external browser at " + browser.getPath(), e);
throw new UnableToCompleteException();
}
browser.setProcess(child);
}
}
}