package net.jsunit; import net.jsunit.configuration.Configuration; import net.jsunit.configuration.ServerType; import net.jsunit.logging.BrowserResultRepository; import net.jsunit.logging.FileBrowserResultRepository; import net.jsunit.model.Browser; import net.jsunit.model.BrowserResult; import net.jsunit.utility.StringUtility; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class JsUnitStandardServer extends AbstractJsUnitServer implements BrowserTestRunner { private List<BrowserResult> results = new ArrayList<BrowserResult>(); private List<TestRunListener> browserTestRunListeners = new ArrayList<TestRunListener>(); private ProcessStarter processStarter = new DefaultProcessStarter(); private LaunchTestRunCommand launchTestRunCommand; private TimeoutChecker timeoutChecker; private Process browserProcess; private long timeLastResultReceived; private BrowserResultRepository browserResultRepository; public JsUnitStandardServer(Configuration configuration, boolean temporary) { this(configuration, new FileBrowserResultRepository(configuration.getLogsDirectory()), temporary); } public JsUnitStandardServer(Configuration configuration, BrowserResultRepository browserResultRepository, boolean temporary) { super(configuration, temporary ? ServerType.STANDARD_TEMPORARY : ServerType.STANDARD); this.browserResultRepository = browserResultRepository; addBrowserTestRunListener(new BrowserResultLogWriter(browserResultRepository)); ServerRegistry.registerServer(this); } public static void main(String args[]) { try { JsUnitStandardServer server = new JsUnitStandardServer(Configuration.resolve(args), false); server.start(); } catch (Throwable t) { t.printStackTrace(); } } protected List<String> servletNames() { return Arrays.asList(new String[]{ "acceptor", "config", "displayer", "index", "latestversion", "runner" }); } public void accept(BrowserResult result) { long timeReceived = System.currentTimeMillis(); if (launchTestRunCommand == null) return; Browser submittingBrowser = launchTestRunCommand.getBrowser(); endBrowser(); result.setBrowser(submittingBrowser); killTimeoutChecker(); BrowserResult existingResultWithSameId = findResultWithId(result.getId(), submittingBrowser); for (TestRunListener listener : browserTestRunListeners) listener.browserTestRunFinished(submittingBrowser, result); if (existingResultWithSameId != null) results.remove(existingResultWithSameId); results.add(result); timeLastResultReceived = timeReceived; } private void killTimeoutChecker() { if (timeoutChecker != null) { timeoutChecker.die(); timeoutChecker = null; } } public List<BrowserResult> getResults() { return results; } public void clearResults() { results.clear(); } public BrowserResult findResultWithId(String id, int browserId) throws InvalidBrowserIdException { Browser browser = configuration.getBrowserById(browserId); if (browser == null) throw new InvalidBrowserIdException(browserId); return findResultWithId(id, browser); } private BrowserResult findResultWithId(String id, Browser browser) { BrowserResult result = findResultWithIdInResultList(id, browser); if (result == null) result = browserResultRepository.retrieve(id, browser); return result; } private BrowserResult findResultWithIdInResultList(String id, Browser browser) { for (BrowserResult result : getResults()) { if (result.hasId(id) && result.isForBrowser(browser)) return result; } return null; } public BrowserResult lastResult() { List results = getResults(); return results.isEmpty() ? null : (BrowserResult) results.get(results.size() - 1); } public int resultsCount() { return getResults().size(); } public String toString() { return "JsUnit Server"; } public List<Browser> getBrowsers() { return configuration.getBrowsers(); } public boolean hasReceivedResultSince(long launchTime) { return timeLastResultReceived >= launchTime; } public void addBrowserTestRunListener(TestRunListener listener) { browserTestRunListeners.add(listener); } public List<TestRunListener> getBrowserTestRunListeners() { return browserTestRunListeners; } private void endBrowser() { if (browserProcess != null && configuration.shouldCloseBrowsersAfterTestRuns()) { if (launchTestRunCommand.getBrowserKillCommand() != null) { try { processStarter.execute(new String[]{launchTestRunCommand.getBrowserKillCommand()}); } catch (IOException e) { e.printStackTrace(); } } else { browserProcess.destroy(); try { browserProcess.waitFor(); } catch (InterruptedException e) { e.printStackTrace(); } waitUntilProcessHasExitValue(browserProcess); } } browserProcess = null; launchTestRunCommand = null; killTimeoutChecker(); } private void waitUntilProcessHasExitValue(Process browserProcess) { while (true) { try { if (browserProcess != null) browserProcess.exitValue(); return; } catch (IllegalThreadStateException e) { } } } public long launchBrowserTestRun(BrowserLaunchSpecification launchSpec) { waitUntilLastReceivedTimeHasPassed(); long launchTime = System.currentTimeMillis(); launchTestRunCommand = new LaunchTestRunCommand(launchSpec, configuration); Browser browser = launchTestRunCommand.getBrowser(); String browserFileName = browser.getFileName(); try { logStatus("Launching " + browserFileName + " on " + launchTestRunCommand.getTestURL()); for (TestRunListener listener : browserTestRunListeners) listener.browserTestRunStarted(browser); this.browserProcess = processStarter.execute(launchTestRunCommand.generateArray()); startTimeoutChecker(launchTime); } catch (Throwable throwable) { handleCrashWhileLaunching(throwable); } return launchTime; } private void handleCrashWhileLaunching(Throwable throwable) { Browser browser = launchTestRunCommand.getBrowser(); logStatus("Browser " + browser.getFileName() + " failed to launch: " + StringUtility.stackTraceAsString(throwable)); BrowserResult failedToLaunchBrowserResult = new BrowserResult(); failedToLaunchBrowserResult.setFailedToLaunch(); failedToLaunchBrowserResult.setBrowser(browser); failedToLaunchBrowserResult.setServerSideException(throwable); accept(failedToLaunchBrowserResult); } private void waitUntilLastReceivedTimeHasPassed() { while (System.currentTimeMillis() == timeLastResultReceived) try { Thread.sleep(1); } catch (InterruptedException e) { } } private void startTimeoutChecker(long launchTime) { timeoutChecker = new TimeoutChecker(browserProcess, launchTestRunCommand.getBrowser(), launchTime, this); timeoutChecker.start(); } void setProcessStarter(ProcessStarter starter) { this.processStarter = starter; } public void startTestRun() { for (TestRunListener listener : browserTestRunListeners) { listener.testRunStarted(); while (!listener.isReady()) try { Thread.sleep(100); } catch (InterruptedException e) { } } } public void finishTestRun() { for (TestRunListener listener : browserTestRunListeners) listener.testRunFinished(); testRunCount ++; } public Process getBrowserProcess() { return browserProcess; } public void dispose() { super.dispose(); endBrowser(); } protected String xworkXmlName() { return "xwork.xml"; } public int timeoutSeconds() { return configuration.getTimeoutSeconds(); } public boolean isAwaitingBrowserSubmission() { return launchTestRunCommand != null; } }