diff --git a/.gitignore b/.gitignore index db4c51c8e4f43..d213b728b864c 100644 --- a/.gitignore +++ b/.gitignore @@ -57,4 +57,5 @@ rb/.yardoc .tm_properties maven/*/src maven/*/target - +java/client/build/ +java/server/build/ diff --git a/java/client/src/org/openqa/selenium/remote/ErrorCodes.java b/java/client/src/org/openqa/selenium/remote/ErrorCodes.java index f3d2cb53adf95..21e7e05339f9e 100644 --- a/java/client/src/org/openqa/selenium/remote/ErrorCodes.java +++ b/java/client/src/org/openqa/selenium/remote/ErrorCodes.java @@ -56,6 +56,7 @@ public class ErrorCodes { public static final int INVALID_XPATH_SELECTOR = 51; public static final int INVALID_XPATH_SELECTOR_RETURN_TYPER = 52; // The following error codes are derived straight from HTTP return codes. + public static final int GONE = 404; public static final int METHOD_NOT_ALLOWED = 405; /** diff --git a/java/client/src/org/openqa/selenium/remote/RemoteWebDriver.java b/java/client/src/org/openqa/selenium/remote/RemoteWebDriver.java index 5e7a305daadc6..0edca2d904e2d 100644 --- a/java/client/src/org/openqa/selenium/remote/RemoteWebDriver.java +++ b/java/client/src/org/openqa/selenium/remote/RemoteWebDriver.java @@ -442,7 +442,7 @@ protected Response execute(String driverCommand, Map parameters) { response.setValue(value); log(sessionId, command.getName(), command, When.AFTER); } catch (SessionTerminatedException e){ - throw new UnreachableBrowserException("Session was terminated by hanging browser detection", e); + throw e; } catch (Exception e) { log(sessionId, command.getName(), command, When.EXCEPTION); String errorMessage = "Error communicating with the remote browser. " + diff --git a/java/client/src/org/openqa/selenium/remote/SessionTerminatedException.java b/java/client/src/org/openqa/selenium/remote/SessionTerminatedException.java index cd6446da40a12..90ac581b77d4d 100644 --- a/java/client/src/org/openqa/selenium/remote/SessionTerminatedException.java +++ b/java/client/src/org/openqa/selenium/remote/SessionTerminatedException.java @@ -15,11 +15,16 @@ */ package org.openqa.selenium.remote; +import org.openqa.selenium.WebDriverException; + import java.io.IOException; /** * Indicates that the session was terminated by the server */ -public class SessionTerminatedException extends IOException { +public class SessionTerminatedException extends WebDriverException { + + public SessionTerminatedException() { + } } diff --git a/java/server/src/org/openqa/grid/common/RegistrationRequest.java b/java/server/src/org/openqa/grid/common/RegistrationRequest.java index 6fc138637463d..b8c8bbd5abdef 100644 --- a/java/server/src/org/openqa/grid/common/RegistrationRequest.java +++ b/java/server/src/org/openqa/grid/common/RegistrationRequest.java @@ -17,17 +17,7 @@ package org.openqa.grid.common; -import java.io.UnsupportedEncodingException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLDecoder; -import java.security.InvalidParameterException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.logging.Logger; +import com.google.common.collect.Maps; import org.json.JSONArray; import org.json.JSONException; @@ -40,7 +30,17 @@ import org.openqa.selenium.server.RemoteControlConfiguration; import org.openqa.selenium.server.cli.RemoteControlLauncher; -import com.google.common.collect.Maps; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLDecoder; +import java.security.InvalidParameterException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; /** * helper to register to the grid. Using JSON to exchange the object between the node and grid. @@ -74,7 +74,9 @@ public class RegistrationRequest { public static final String REGISTER_CYCLE = "registerCycle"; public static final String PROXY_CLASS = CapabilityType.PROXY; public static final String CLEAN_UP_CYCLE = "cleanUpCycle"; + // Client timeout public static final String TIME_OUT = "timeout"; + public static final String BROWSER_TIME_OUT = "browserTimeout"; // TODO delete to keep only HUB_HOSt and HUB_PORT public static final String REMOTE_HOST = "remoteHost"; @@ -457,6 +459,9 @@ private void loadFromCommandLine(String[] args) { if (helper.isParamPresent("-timeout")) { configuration.put(TIME_OUT, Integer.parseInt(helper.getParamValue("-timeout"))); } + if (helper.isParamPresent("-browserTimeout")) { + configuration.put(BROWSER_TIME_OUT, Integer.parseInt(helper.getParamValue("-browserTimeout"))); + } if (helper.isParamPresent("-maxSession")) { configuration.put(MAX_SESSION, Integer.parseInt(helper.getParamValue("-maxSession"))); } diff --git a/java/server/src/org/openqa/grid/common/defaults/DefaultHub.json b/java/server/src/org/openqa/grid/common/defaults/DefaultHub.json index 987aee3304bdd..4d77a8946a3d8 100644 --- a/java/server/src/org/openqa/grid/common/defaults/DefaultHub.json +++ b/java/server/src/org/openqa/grid/common/defaults/DefaultHub.json @@ -10,5 +10,6 @@ "cleanUpCycle": 5000, "timeout": 300000, + "browserTimeout": 0, "maxSession": 5 } \ No newline at end of file diff --git a/java/server/src/org/openqa/grid/common/defaults/GridParameters.properties b/java/server/src/org/openqa/grid/common/defaults/GridParameters.properties index 73e42c6486ddc..069a5261671ed 100644 --- a/java/server/src/org/openqa/grid/common/defaults/GridParameters.properties +++ b/java/server/src/org/openqa/grid/common/defaults/GridParameters.properties @@ -20,6 +20,7 @@ hubConfig = (hub) a JSON file following grid2 format. # config that will be inherited by the proxy and used for the node management. cleanupCycle = (node) in ms. How often a proxy will check for timed out thread. nodeTimeout = (node) the timeout in seconds before the hub automatically ends a test that hasn't had aby activity than XX sec.The browser will be released for another test to use.This typically takes care of the client crashes. +browserTimeout= (hub/node) The timeout in seconds a browser can hang hub = (node) : the url that will be used to post the registration request. proxy = (node) the class that will be used to represent the node. By default org.openqa.grid.selenium.proxy.SeleniumRemoteProxy ( selenium1 / RC ) org.openqa.grid.selenium.proxy.WebDriverRemoteProxy ( selenium2 / webdriver ) maxSession = (node) max number of tests that can run at the same time on the node, independently of the browser used. diff --git a/java/server/src/org/openqa/grid/internal/SessionTerminationReason.java b/java/server/src/org/openqa/grid/internal/SessionTerminationReason.java index 80915cbe76468..d774b9ee67ff6 100644 --- a/java/server/src/org/openqa/grid/internal/SessionTerminationReason.java +++ b/java/server/src/org/openqa/grid/internal/SessionTerminationReason.java @@ -19,6 +19,7 @@ public enum SessionTerminationReason { TIMEOUT, + BROWSER_TIMEOUT, ORPHAN, CLIENT_STOPPED_SESSION, CLIENT_GONE, diff --git a/java/server/src/org/openqa/grid/internal/TestSession.java b/java/server/src/org/openqa/grid/internal/TestSession.java index 59528db6f9a83..e3ee2861ca9e7 100644 --- a/java/server/src/org/openqa/grid/internal/TestSession.java +++ b/java/server/src/org/openqa/grid/internal/TestSession.java @@ -87,7 +87,8 @@ public String getInternalKey() { /** * Creates a test session on the specified testSlot. */ - public TestSession(TestSlot slot, Map requestedCapabilities, TimeSource timeSource) { + public TestSession(TestSlot slot, Map requestedCapabilities, + TimeSource timeSource) { internalKey = UUID.randomUUID().toString(); this.slot = slot; this.requestedCapabilities = requestedCapabilities; @@ -143,8 +144,8 @@ public boolean isOrphaned() { // seen any new // commands during that time frame. return slot.getProtocol().isSelenium() - && elapsedSinceCreation > MAX_IDLE_TIME_BEFORE_CONSIDERED_ORPHANED - && sessionCreatedAt == lastActivity; + && elapsedSinceCreation > MAX_IDLE_TIME_BEFORE_CONSIDERED_ORPHANED + && sessionCreatedAt == lastActivity; } /** @@ -180,7 +181,7 @@ public boolean equals(Object obj) { @Override public String toString() { return externalKey != null ? "ext. key " + externalKey : internalKey - + " (int. key, remote not contacted yet.)"; + + " (int. key, remote not contacted yet.)"; } @@ -191,14 +192,15 @@ private HttpClient getClient() { /** * forwards the request to the node. */ - public String forward(SeleniumBasedRequest request, HttpServletResponse response, boolean newSessionRequest) + public String forward(SeleniumBasedRequest request, HttpServletResponse response, + boolean newSessionRequest) throws IOException { String res = null; String currentThreadName = Thread.currentThread().getName(); setThreadDisplayName(); forwardingRequest = true; - + try { if (slot.getProxy() instanceof CommandListener) { ((CommandListener) slot.getProxy()).beforeCommand(this, request, response); @@ -212,25 +214,32 @@ public String forward(SeleniumBasedRequest request, HttpServletResponse response lastActivity = timeSource.currentTimeInMillis(); - response.setStatus(proxyResponse.getStatusLine().getStatusCode()); + final int statusCode = proxyResponse.getStatusLine().getStatusCode(); + response.setStatus(statusCode); processResponseHeaders(request, response, slot.getRemoteURL(), proxyResponse); - if (proxyResponse.getStatusLine().getStatusCode() != 500) { + if (statusCode != HttpServletResponse.SC_INTERNAL_SERVER_ERROR && + statusCode != HttpServletResponse.SC_NOT_FOUND) { + System.out.println("regular"); updateHubIfNewWebDriverSession(request, proxyResponse); - } else if (newSessionRequest) { + } + if (newSessionRequest && statusCode == HttpServletResponse.SC_INTERNAL_SERVER_ERROR) { removeIncompleteNewSessionRequest(); } + if (statusCode == HttpServletResponse.SC_NOT_FOUND) { + removeSessionBrowserTimeout(); + } - HttpEntity responseBody = proxyResponse.getEntity(); + HttpEntity responseBody = proxyResponse.getEntity(); byte[] contentBeingForwarded = null; if (responseBody != null) { try { InputStream in = responseBody.getContent(); - + if (request.getRequestType() == RequestType.START_SESSION && request instanceof LegacySeleniumRequest) { res = getResponseUtf8Content(in); - + updateHubNewSeleniumSession(res); in = new ByteArrayInputStream(res.getBytes("UTF-8")); @@ -246,7 +255,7 @@ public String forward(SeleniumBasedRequest request, HttpServletResponse response } if (slot.getProxy() instanceof CommandListener) { - SeleniumBasedResponse wrappedResponse = new SeleniumBasedResponse(response); + SeleniumBasedResponse wrappedResponse = new SeleniumBasedResponse(response); wrappedResponse.setForwardedContent(contentBeingForwarded); ((CommandListener) slot.getProxy()).afterCommand(this, request, wrappedResponse); } @@ -259,18 +268,22 @@ public String forward(SeleniumBasedRequest request, HttpServletResponse response } } - private void setThreadDisplayName() { - DateFormat dfmt=DateFormat.getTimeInstance(); - String name = "Forwarding " + this + " to " + slot.getRemoteURL() + " at " + - dfmt.format(Calendar.getInstance().getTime()); - Thread.currentThread().setName(name); - } + private void setThreadDisplayName() { + DateFormat dfmt = DateFormat.getTimeInstance(); + String name = "Forwarding " + this + " to " + slot.getRemoteURL() + " at " + + dfmt.format(Calendar.getInstance().getTime()); + Thread.currentThread().setName(name); + } - private void removeIncompleteNewSessionRequest() { + private void removeIncompleteNewSessionRequest() { RemoteProxy proxy = slot.getProxy(); proxy.getRegistry().terminate(this, SessionTerminationReason.CREATIONFAILED); } + private void removeSessionBrowserTimeout() { + RemoteProxy proxy = slot.getProxy(); + proxy.getRegistry().terminate(this, SessionTerminationReason.BROWSER_TIMEOUT); + } private void updateHubNewSeleniumSession(String content) { ExternalSessionKey key = ExternalSessionKey.fromResponseBody(content); @@ -278,7 +291,7 @@ private void updateHubNewSeleniumSession(String content) { } private void updateHubIfNewWebDriverSession(SeleniumBasedRequest request, - HttpResponse proxyResponse) { + HttpResponse proxyResponse) { if (request.getRequestType() == RequestType.START_SESSION && request instanceof WebDriverRequest) { Header h = proxyResponse.getFirstHeader("Location"); @@ -292,7 +305,7 @@ private void updateHubIfNewWebDriverSession(SeleniumBasedRequest request, } private HttpResponse sendRequestToNode(HttpRequest proxyRequest) throws ClientProtocolException, - IOException { + IOException { HttpClient client = getClient(); URL remoteURL = slot.getRemoteURL(); HttpHost host = new HttpHost(remoteURL.getHost(), remoteURL.getPort()); @@ -300,7 +313,8 @@ private HttpResponse sendRequestToNode(HttpRequest proxyRequest) throws ClientPr return client.execute(host, proxyRequest); } - private HttpRequest prepareProxyRequest(HttpServletRequest request/*, ForwardConfiguration config*/) + private HttpRequest prepareProxyRequest(HttpServletRequest request +/*, ForwardConfiguration config*/) throws IOException { URL remoteURL = slot.getRemoteURL(); @@ -308,7 +322,7 @@ private HttpRequest prepareProxyRequest(HttpServletRequest request/*, ForwardCon String path = request.getRequestURI(); if (!path.startsWith(pathSpec)) { throw new IllegalStateException("Expected path " + path + " to start with pathSpec " - + pathSpec); + + pathSpec); } String end = path.substring(pathSpec.length()); String ok = remoteURL + end; @@ -320,7 +334,7 @@ private HttpRequest prepareProxyRequest(HttpServletRequest request/*, ForwardCon } HttpRequest proxyRequest; - + if (body != null) { BasicHttpEntityEnclosingRequest r = new BasicHttpEntityEnclosingRequest(request.getMethod(), uri); @@ -330,7 +344,7 @@ private HttpRequest prepareProxyRequest(HttpServletRequest request/*, ForwardCon proxyRequest = new BasicHttpRequest(request.getMethod(), uri); } - for (Enumeration e = request.getHeaderNames(); e.hasMoreElements();) { + for (Enumeration e = request.getHeaderNames(); e.hasMoreElements(); ) { String headerName = (String) e.nextElement(); if ("Content-Length".equalsIgnoreCase(headerName)) { @@ -399,7 +413,8 @@ private String getResponseUtf8Content(InputStream in) { } private void processResponseHeaders(HttpServletRequest request, HttpServletResponse response, - URL remoteURL, HttpResponse proxyResponse) throws MalformedURLException { + URL remoteURL, HttpResponse proxyResponse) + throws MalformedURLException { String pathSpec = request.getServletPath() + request.getContextPath(); for (Header header : proxyResponse.getAllHeaders()) { String name = header.getName(); @@ -466,7 +481,8 @@ public boolean sendDeleteSessionRequest() { case Selenium: request = new BasicHttpRequest("POST", remoteURL.toExternalForm() - + "/?cmd=testComplete&sessionId=" + getExternalKey().getKey()); + + "/?cmd=testComplete&sessionId=" + getExternalKey() + .getKey()); break; case WebDriver: String uri = remoteURL.toString() + "/session/" + externalKey; diff --git a/java/server/src/org/openqa/grid/internal/utils/GridHubConfiguration.java b/java/server/src/org/openqa/grid/internal/utils/GridHubConfiguration.java index 63bd3ae81b9d9..b1494c5ecd1c5 100644 --- a/java/server/src/org/openqa/grid/internal/utils/GridHubConfiguration.java +++ b/java/server/src/org/openqa/grid/internal/utils/GridHubConfiguration.java @@ -1,5 +1,20 @@ package org.openqa.grid.internal.utils; - +/* +Copyright 2011 WebDriver committers +Copyright 2011 Software Freedom Conservancy + +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. +*/ import org.json.JSONArray; import org.json.JSONObject; import org.openqa.grid.common.CommandLineOptionHelper; @@ -21,12 +36,13 @@ import java.util.List; import java.util.Map; import java.util.logging.Logger; +import static org.openqa.grid.internal.utils.ServerJsonValues.*; public class GridHubConfiguration { private static final Logger log = Logger.getLogger(GridHubConfiguration.class.getName()); - /** + /** * The hub needs to know its hostname in order to write the proper Location header for the request * being forwarded. Usually this can be guessed correctly, but in case it cannot it can be passed * via this config param. @@ -44,13 +60,6 @@ public class GridHubConfiguration { */ private int cleanupCycle; - /** - * how long can a session be idle before being considered timed out. Working together with cleanup - * cycle. Worst case scenario, a session can be idle for timout + cleanup cycle before the timeout - * is detected - */ - private int timeout; - /** * how long a new session request can stay in the queue without being assigned before being * rejected. -1 = forever. @@ -160,8 +169,11 @@ public void loadFromCommandLine(String[] args) { if (helper.isParamPresent("-cleanUpCycle")) { cleanupCycle = Integer.parseInt(helper.getParamValue("-cleanUpCycle")); } - if (helper.isParamPresent("-timeout")) { - timeout = Integer.parseInt(helper.getParamValue("-timeout")); + if (helper.isParamPresent(CLIENT_TIMEOUT.getKey())) { + setTimeout(Integer.parseInt(helper.getParamValue(CLIENT_TIMEOUT.getKey()))); + } + if (helper.isParamPresent(BROWSER_TIMEOUT.getKey())) { + setBrowserTimeout(Integer.parseInt(helper.getParamValue(BROWSER_TIMEOUT.getKey()))); } if (helper.isParamPresent("-newSessionWaitTimeout")) { newSessionWaitTimeout = Integer.parseInt(helper.getParamValue("-newSessionWaitTimeout")); @@ -273,7 +285,10 @@ public void loadFromJSON(String resource) { cleanupCycle = o.getInt(RegistrationRequest.CLEAN_UP_CYCLE); } if (o.has(RegistrationRequest.TIME_OUT) && !o.isNull(RegistrationRequest.TIME_OUT)) { - timeout = o.getInt(RegistrationRequest.TIME_OUT); + setTimeout(o.getInt(RegistrationRequest.TIME_OUT)); + } + if (o.has(RegistrationRequest.BROWSER_TIME_OUT) && !o.isNull(RegistrationRequest.BROWSER_TIME_OUT)) { + setBrowserTimeout(o.getInt(RegistrationRequest.BROWSER_TIME_OUT)); } if (o.has("newSessionWaitTimeout") && !o.isNull("newSessionWaitTimeout")) { newSessionWaitTimeout = o.getInt("newSessionWaitTimeout"); @@ -331,7 +346,17 @@ public int getCleanupCycle() { } public int getTimeout() { - return timeout; + final Integer timeout = get(CLIENT_TIMEOUT); + return timeout != null ? timeout : 0; + } + + public int getBrowserTimeout() { + final Integer timeout =get(BROWSER_TIMEOUT); + return timeout != null ? timeout : 0; + } + + public void setBrowserTimeout(int browserTimeout) { + put(BROWSER_TIMEOUT, browserTimeout); } public int getNewSessionWaitTimeout() { @@ -375,7 +400,16 @@ public void setCleanupCycle(int cleanupCycle) { } public void setTimeout(int timeout) { - this.timeout = timeout; + put(CLIENT_TIMEOUT, timeout); + } + + private void put(JsonKey key, Object value){ + allParams.put(key.getKey(), value); + } + + private T get(JsonKey jsonKey) { + //noinspection unchecked + return (T) allParams.get(jsonKey.getKey()); } public void setNewSessionWaitTimeout(int newSessionWaitTimeout) { @@ -433,7 +467,8 @@ public String prettyPrint() { b.append("host: ").append(host).append("\n"); b.append("port: ").append(port).append("\n"); b.append("cleanupCycle: ").append(cleanupCycle).append("\n"); - b.append("timeout: ").append(timeout).append("\n"); + b.append("timeout: ").append(getTimeout()).append("\n"); + b.append("browserTimeout: ").append(getBrowserTimeout()).append("\n"); b.append("newSessionWaitTimeout: ").append(newSessionWaitTimeout).append("\n"); b.append("grid1Mapping: ").append(grid1Mapping).append("\n"); diff --git a/java/server/src/org/openqa/grid/internal/utils/JsonKey.java b/java/server/src/org/openqa/grid/internal/utils/JsonKey.java new file mode 100644 index 0000000000000..a79370b988394 --- /dev/null +++ b/java/server/src/org/openqa/grid/internal/utils/JsonKey.java @@ -0,0 +1,45 @@ +package org.openqa.grid.internal.utils; +/* +Copyright 2011 WebDriver committers +Copyright 2011 Software Freedom Conservancy + +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. +*/ +/** + * Represents a string value in a json key + */ +public class JsonKey { + private final String key; + private final String asParam; + + public JsonKey(String key) { + this.key = key; + this.asParam = "-" + key; + } + + public static JsonKey key(String key){ + return new JsonKey(key); + } + + public boolean matches(String arg) { + return (asParam.equalsIgnoreCase(arg)); + } + + public String getAsParam() { + return asParam; + } + + public String getKey() { + return key; + } +} diff --git a/java/server/src/org/openqa/grid/internal/utils/SelfRegisteringRemote.java b/java/server/src/org/openqa/grid/internal/utils/SelfRegisteringRemote.java index d1117048c436c..966651aef9037 100644 --- a/java/server/src/org/openqa/grid/internal/utils/SelfRegisteringRemote.java +++ b/java/server/src/org/openqa/grid/internal/utils/SelfRegisteringRemote.java @@ -16,7 +16,6 @@ import org.apache.http.HttpHost; import org.apache.http.HttpResponse; -import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.entity.StringEntity; import org.apache.http.message.BasicHttpEntityEnclosingRequest; @@ -35,26 +34,23 @@ import org.openqa.jetty.jetty.servlet.ServletHandler; import org.openqa.selenium.Platform; import org.openqa.selenium.remote.DesiredCapabilities; +import org.openqa.selenium.server.RemoteControlConfiguration; import org.openqa.selenium.server.SeleniumServer; import org.openqa.selenium.server.log.LoggingManager; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.security.InvalidParameterException; import java.util.Arrays; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Logger; import javax.servlet.Servlet; -import junit.framework.Assert; - import static org.openqa.grid.common.RegistrationRequest.AUTO_REGISTER; public class SelfRegisteringRemote { @@ -86,19 +82,29 @@ public URL getRemoteURL() { public void startRemoteServer() throws Exception { + System.setProperty("org.openqa.jetty.http.HttpRequest.maxFormContentSize", "0"); + + + nodeConfig.validate(); + RemoteControlConfiguration remoteControlConfiguration = nodeConfig.getRemoteControlConfiguration(); + try { - JSONObject hubParameters = getHubConfiguration("timeout"); - int timeout = hubParameters.getInt("timeout"); - // TODO freynaud use the timeout from the hub to setup the node ones. + final String CLIENT_TIMEOUT = "timeout"; + final String BROWSER_TIMEOUT = "browserTimeout"; + JSONObject hubParameters = getHubConfiguration(CLIENT_TIMEOUT, BROWSER_TIMEOUT); + if (hubParameters.has(CLIENT_TIMEOUT)){ + int timeout = hubParameters.getInt(CLIENT_TIMEOUT) / 1000; + remoteControlConfiguration.setTimeoutInSeconds(timeout); + } + if (hubParameters.has(BROWSER_TIMEOUT)) { + int browserTimeout = hubParameters.getInt(BROWSER_TIMEOUT); + remoteControlConfiguration.setBrowserTimeoutInMs(browserTimeout); + } }catch (Exception e) { log.warning("error getting the parameters from the hub. The node may end up with wrong timeouts."+e.getMessage()); } - - nodeConfig.validate(); - - System.setProperty("org.openqa.jetty.http.HttpRequest.maxFormContentSize", "0"); - server = new SeleniumServer(nodeConfig.getRemoteControlConfiguration()); + server = new SeleniumServer(remoteControlConfiguration); Server jetty = server.getServer(); diff --git a/java/server/src/org/openqa/grid/internal/utils/ServerJsonValues.java b/java/server/src/org/openqa/grid/internal/utils/ServerJsonValues.java new file mode 100644 index 0000000000000..fc735e555f4c3 --- /dev/null +++ b/java/server/src/org/openqa/grid/internal/utils/ServerJsonValues.java @@ -0,0 +1,21 @@ +package org.openqa.grid.internal.utils; + +/** + * Well-known JSON constants in use by grid/server + */ +public class ServerJsonValues { + + /** + * how many ms can a browser be hanging before being considered hanging (dead). The grid does not + * act on this value by itself, but passes the value on to the nodes, which do. + */ + public static final JsonKey BROWSER_TIMEOUT = JsonKey.key("browserTimeout"); + + /** + * how many ms can a session be idle before being considered timed out. Working together with + * cleanup cycle. Worst case scenario, a session can be idle for timout + cleanup cycle before the + * timeout is detected. + */ + public static final JsonKey CLIENT_TIMEOUT = JsonKey.key("timeout"); + +} diff --git a/java/server/src/org/openqa/grid/web/servlet/ConsoleServlet.java b/java/server/src/org/openqa/grid/web/servlet/ConsoleServlet.java index 55d4038babd71..3b7258f1d6c88 100644 --- a/java/server/src/org/openqa/grid/web/servlet/ConsoleServlet.java +++ b/java/server/src/org/openqa/grid/web/servlet/ConsoleServlet.java @@ -210,6 +210,8 @@ private String prettyHtmlPrint(GridHubConfiguration config) { b.append(key("port")).append(config.getPort()).append("
"); b.append(key("cleanUpCycle")).append(config.getCleanupCycle()).append("
"); b.append(key("timeout")).append(config.getTimeout()).append("
"); + b.append(key("browserTimeout")).append(config.getBrowserTimeout()).append("
"); + b.append(key("newSessionWaitTimeout")).append(config.getNewSessionWaitTimeout()) .append("
"); diff --git a/java/server/src/org/openqa/grid/web/servlet/beta/ConsoleServlet.java b/java/server/src/org/openqa/grid/web/servlet/beta/ConsoleServlet.java index a79d6e57fd22f..214fcd1f77b8f 100644 --- a/java/server/src/org/openqa/grid/web/servlet/beta/ConsoleServlet.java +++ b/java/server/src/org/openqa/grid/web/servlet/beta/ConsoleServlet.java @@ -256,6 +256,7 @@ private String prettyHtmlPrint(GridHubConfiguration config) { b.append(key("port")).append(config.getPort()).append("
"); b.append(key("cleanUpCycle")).append(config.getCleanupCycle()).append("
"); b.append(key("timeout")).append(config.getTimeout()).append("
"); + b.append(key("browserTimeout")).append(config.getBrowserTimeout()).append("
"); b.append(key("newSessionWaitTimeout")).append(config.getNewSessionWaitTimeout()) .append("
"); diff --git a/java/server/src/org/openqa/selenium/remote/server/DriverServlet.java b/java/server/src/org/openqa/selenium/remote/server/DriverServlet.java index d72a282ae5d7d..a9182d657d300 100644 --- a/java/server/src/org/openqa/selenium/remote/server/DriverServlet.java +++ b/java/server/src/org/openqa/selenium/remote/server/DriverServlet.java @@ -27,6 +27,7 @@ import javax.servlet.http.HttpServletResponse; import org.openqa.selenium.logging.LoggingHandler; +import org.openqa.selenium.remote.SessionTerminatedException; import org.openqa.selenium.remote.server.handler.AcceptAlert; import org.openqa.selenium.remote.server.handler.AddConfig; import org.openqa.selenium.remote.server.handler.AddCookie; @@ -143,6 +144,7 @@ import org.openqa.selenium.remote.server.xdrpc.CrossDomainRpcLoader; import org.openqa.selenium.remote.server.xdrpc.CrossDomainRpcRenderer; import org.openqa.selenium.remote.server.xdrpc.HttpServletRequestProxy; +import org.openqa.selenium.server.RemoteControlConfiguration; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Supplier; @@ -181,15 +183,33 @@ public void init() throws ServletException { DriverSessions driverSessions = sessionsSupplier.get(); setupMappings(driverSessions, logger); - int sessionTimeOut = Integer.parseInt(System.getProperty("webdriver.server.session.timeout", "1800")); - int browserTimeout = Integer.parseInt(System.getProperty("webdriver.server.browser.timeout", "0")); - if (sessionTimeOut > 0) { - sessionCleaner = new SessionCleaner(driverSessions, logger, 1000 * sessionTimeOut, 1000* browserTimeout); + RemoteControlConfiguration rcc = + (RemoteControlConfiguration) getServletContext().getAttribute(RemoteControlConfiguration.KEY); + + int sessionTimeOutInMs = + getValueToUseInMs("webdriver.server.session.timeout", (int)rcc.getTimeoutInMs(), 1800); + int browserTimeoutInMs = getValueToUseInMs(rcc.getBrowserTimeoutInMs(), 0); + + if (sessionTimeOutInMs > 0 || browserTimeoutInMs > 0) { + sessionCleaner = new SessionCleaner(driverSessions, logger, sessionTimeOutInMs, browserTimeoutInMs); sessionCleaner.start(); } } - @Override + private int getValueToUseInMs(String sysPropName, int rccTimeOutMs, int defaultValueIfAllElse) { + final String property = System.getProperty(sysPropName); + if (property == null){ + return getValueToUseInMs(rccTimeOutMs, defaultValueIfAllElse); + } else { + return Integer.parseInt(property) * 1000; + } + } + + private int getValueToUseInMs(int rccTimeOutMs, int defaultValueIfAllElse) { + return (rccTimeOutMs > 0) ? rccTimeOutMs : defaultValueIfAllElse * 1000; + } + + @Override public void destroy() { getLogger().removeHandler(LoggingHandler.getInstance()); if (sessionCleaner != null) { @@ -577,6 +597,8 @@ protected void handleRequest(UrlMapper mapper, HttpServletRequest request, } else { config.handle(request.getPathInfo(), request, response); } + } catch (SessionTerminatedException e){ + response.setStatus(HttpServletResponse.SC_NOT_FOUND); } catch (Exception e) { log("Fatal, unhandled exception: " + request.getPathInfo() + ": " + e); throw new ServletException(e); diff --git a/java/server/src/org/openqa/selenium/remote/server/SessionCleaner.java b/java/server/src/org/openqa/selenium/remote/server/SessionCleaner.java index 0dbd28de9ba86..bc58bc10641f5 100644 --- a/java/server/src/org/openqa/selenium/remote/server/SessionCleaner.java +++ b/java/server/src/org/openqa/selenium/remote/server/SessionCleaner.java @@ -31,6 +31,7 @@ class SessionCleaner extends Thread { // Thread safety reviewed private final DriverSessions driverSessions; private final int clientGoneTimeout; private final int insideBrowserTimeout; + private final int sleepInterval; private final Logger log; private volatile boolean running = true; @@ -40,6 +41,12 @@ class SessionCleaner extends Thread { // Thread safety reviewed this.clientGoneTimeout = clientGoneTimeout; this.insideBrowserTimeout = insideBrowserTimeout; this.driverSessions = driverSessions; + if (clientGoneTimeout == 0 && insideBrowserTimeout == 0){ + throw new IllegalStateException("SessionCleaner not supposed to start when no timeouts specified"); + } + int lowestNonZero = Math.min((insideBrowserTimeout > 0) ? insideBrowserTimeout : clientGoneTimeout, + clientGoneTimeout > 0 ? clientGoneTimeout : insideBrowserTimeout); + this.sleepInterval = lowestNonZero / 10; } @@ -49,7 +56,7 @@ public void run() { while (running) { checkExpiry(); try { - Thread.sleep(clientGoneTimeout / 10); + Thread.sleep(sleepInterval); } catch (InterruptedException e) { log.info("Exiting session cleaner thread"); } diff --git a/java/server/src/org/openqa/selenium/remote/server/rest/ResultConfig.java b/java/server/src/org/openqa/selenium/remote/server/rest/ResultConfig.java index e1b24f68c5cb9..de9aa5b1c8e95 100644 --- a/java/server/src/org/openqa/selenium/remote/server/rest/ResultConfig.java +++ b/java/server/src/org/openqa/selenium/remote/server/rest/ResultConfig.java @@ -28,6 +28,7 @@ import org.openqa.selenium.remote.JsonToBeanConverter; import org.openqa.selenium.remote.PropertyMunger; import org.openqa.selenium.remote.SessionId; +import org.openqa.selenium.remote.SessionTerminatedException; import org.openqa.selenium.remote.SimplePropertyDescriptor; import org.openqa.selenium.remote.UnreachableBrowserException; import org.openqa.selenium.remote.server.DriverSessions; @@ -185,9 +186,7 @@ public void handle(String pathInfo, final HttpServletRequest request, SessionId sessId = sessionId != null ? new SessionId(sessionId) : null; ResultType result; - if (isSessionTerminated(sessId, request, response)) { - return; - } + throwUpIfSessionTerminated(sessId); final RestishHandler handler = getHandler(pathInfo, sessId); if (handler instanceof JsonParametersAware) { @@ -197,9 +196,7 @@ public void handle(String pathInfo, final HttpServletRequest request, request.setAttribute("handler", handler); - if (isSessionTerminated(sessId, request, response)) { - return; - } + throwUpIfSessionTerminated(sessId); try { log.info(String.format("Executing: %s at URL: %s)", handler.toString(), pathInfo)); @@ -207,8 +204,11 @@ public void handle(String pathInfo, final HttpServletRequest request, addHandlerAttributesToRequest(request, handler); log.info("Done: " + pathInfo); } catch (UnreachableBrowserException e){ + throwUpIfSessionTerminated(sessId); replyError(request, response, e); return; + } catch (SessionTerminatedException e){ + throw e; } catch (Exception e) { result = ResultType.EXCEPTION; log.log(Level.WARNING, "Exception thrown", e); @@ -240,8 +240,8 @@ public ResultType call() throws Exception { try { ((WebDriverHandler) handler).execute(task); task.get(); - } catch (RejectedExecutionException e){ // The session is gone - respondSessionError(sessId, request, response); + } catch (RejectedExecutionException e){ + throw new SessionTerminatedException(); } if (handler instanceof DeleteSession) { @@ -268,23 +268,13 @@ private void replyError(HttpServletRequest request, final HttpServletResponse re } - private boolean isSessionTerminated(SessionId sessId, HttpServletRequest request, - HttpServletResponse response) throws Exception { - if (sessId == null) return false; + private void throwUpIfSessionTerminated(SessionId sessId) throws Exception { + if (sessId == null) return; Session session = sessions.get(sessId); final boolean isTerminated = session == null; if (isTerminated){ - respondSessionError(sessId, request, response); + throw new SessionTerminatedException(); } - return isTerminated; - } - - private void respondSessionError(SessionId sessId, HttpServletRequest request, - HttpServletResponse response) throws Exception { - SessionNotFoundException sessionNotFoundException = - new SessionNotFoundException("404 session " + sessId + " not found"); - request.setAttribute("exception", sessionNotFoundException); - replyError(request, response, sessionNotFoundException); } @VisibleForTesting diff --git a/java/server/src/org/openqa/selenium/server/RemoteControlConfiguration.java b/java/server/src/org/openqa/selenium/server/RemoteControlConfiguration.java index 328a20b142b59..ff33402714fd9 100644 --- a/java/server/src/org/openqa/selenium/server/RemoteControlConfiguration.java +++ b/java/server/src/org/openqa/selenium/server/RemoteControlConfiguration.java @@ -11,6 +11,7 @@ */ public class RemoteControlConfiguration { + public static final String KEY = RemoteControlConfiguration.class.getName() + ".config"; public static final int DEFAULT_PORT = 4444; private static final int USE_SAME_PORT = -1; public static final int MINUTES = 60; @@ -52,6 +53,7 @@ public class RemoteControlConfiguration { private String forcedBrowserMode; private boolean honorSystemProxy; private int timeoutInSeconds; + private int browserTimeoutInMs; private int retryTimeoutInSeconds; /** * useful for situations where Selenium is being invoked programatically and the outside container @@ -281,10 +283,22 @@ public long getTimeoutInSeconds() { return timeoutInSeconds; } + public long getTimeoutInMs() { + return timeoutInSeconds * 1000; + } + public void setTimeoutInSeconds(int newTimeoutInSeconds) { timeoutInSeconds = newTimeoutInSeconds; } + public int getBrowserTimeoutInMs() { + return browserTimeoutInMs; + } + + public void setBrowserTimeoutInMs(int browserTimeoutInMs) { + this.browserTimeoutInMs = browserTimeoutInMs; + } + public int getRetryTimeoutInSeconds() { return retryTimeoutInSeconds; } diff --git a/java/server/src/org/openqa/selenium/server/SeleniumServer.java b/java/server/src/org/openqa/selenium/server/SeleniumServer.java index c0f4212ed60dc..101e7fdd26e41 100644 --- a/java/server/src/org/openqa/selenium/server/SeleniumServer.java +++ b/java/server/src/org/openqa/selenium/server/SeleniumServer.java @@ -362,6 +362,8 @@ private HttpContext createDriverContextWithSeleniumDriverResourceHandler( private HttpContext createWebDriverRemoteContext(DriverSessions webdrDriverSessions) { HttpContext webdriverContext = new HttpContext(); + + webdriverContext.setAttribute(RemoteControlConfiguration.KEY, configuration); webdriverContext.setAttribute(DriverServlet.SESSIONS_KEY, webdrDriverSessions); webdriverContext.setContextPath("/wd"); ServletHandler handler = new ServletHandler(); diff --git a/java/server/src/org/openqa/selenium/server/cli/RemoteControlLauncher.java b/java/server/src/org/openqa/selenium/server/cli/RemoteControlLauncher.java index a3337e8b06fc6..99979c3637a07 100644 --- a/java/server/src/org/openqa/selenium/server/cli/RemoteControlLauncher.java +++ b/java/server/src/org/openqa/selenium/server/cli/RemoteControlLauncher.java @@ -20,7 +20,9 @@ public static void usage(String msg) { printWrappedErrorLine(INDENT, "-port : the port number the selenium server should use (default 4444)"); printWrappedErrorLine(INDENT, - "-timeout : an integer number of seconds before we should give up"); + "-timeout : an integer number of seconds we should allow a client to be idle"); + printWrappedErrorLine(INDENT, + "-browserTimeout : an integer number of seconds a browser is allowed to hang"); printWrappedErrorLine(INDENT, "-interactive: puts you into interactive mode. See the tutorial for more details"); printWrappedErrorLine( diff --git a/java/server/test/org/openqa/grid/e2e/build.desc b/java/server/test/org/openqa/grid/e2e/build.desc index 3dea47e393a5f..e6a708f3fd9b0 100644 --- a/java/server/test/org/openqa/grid/e2e/build.desc +++ b/java/server/test/org/openqa/grid/e2e/build.desc @@ -2,7 +2,7 @@ java_test(name = "test", srcs = [ "misc/**/*.java", - "node/**/*.java", + "node/*.java", "utils/**/*.java", ], diff --git a/java/server/test/org/openqa/grid/e2e/node/BrowserTimeOutTest.java b/java/server/test/org/openqa/grid/e2e/node/BrowserTimeOutTest.java new file mode 100644 index 0000000000000..5513118c8c11a --- /dev/null +++ b/java/server/test/org/openqa/grid/e2e/node/BrowserTimeOutTest.java @@ -0,0 +1,85 @@ +/* +Copyright 2011 WebDriver committers +Copyright 2011 Software Freedom Conservancy + +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 org.openqa.grid.e2e.node; + +import org.openqa.grid.common.GridRole; +import org.openqa.grid.e2e.utils.GridTestHelper; +import org.openqa.grid.e2e.utils.RegistryTestHelper; +import org.openqa.grid.internal.utils.GridHubConfiguration; +import org.openqa.grid.internal.utils.SelfRegisteringRemote; +import org.openqa.grid.web.Hub; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebDriverException; +import org.openqa.selenium.remote.DesiredCapabilities; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Arrays; + +/** + * checks that the session is stopped and browser released when browser timeout happens. + */ +public class BrowserTimeOutTest { + + private Hub hub; + private SelfRegisteringRemote node; + + @BeforeClass(alwaysRun = true) + public void setup() throws Exception { + GridHubConfiguration gridHubConfiguration = new GridHubConfiguration(); + gridHubConfiguration.setBrowserTimeout(50); + gridHubConfiguration.setServlets(Arrays.asList("org.openqa.grid.e2e.node.SlowServlet")); + hub = GridTestHelper.getHub(gridHubConfiguration); + + // register a selenium 1 + node = GridTestHelper.getRemoteWithoutCapabilities(hub.getUrl(), GridRole.NODE); + node.addBrowser(GridTestHelper.getSelenium1FirefoxCapability(), 1); + node.addBrowser(DesiredCapabilities.firefox(), 1); + node.startRemoteServer(); + node.sendRegistrationRequest(); + + RegistryTestHelper.waitForNode(hub.getRegistry(), 1); + } + + + @Test + public void testWebDriverTimesOut() throws InterruptedException, MalformedURLException { + String url = "http://" + hub.getHost() + ":" + hub.getPort() + "/grid/admin/SlowServlet"; + DesiredCapabilities ff = DesiredCapabilities.firefox(); + WebDriver driver = new RemoteWebDriver(new URL(hub.getUrl() + "/wd/hub"), ff); + + try { + driver.get(url); + } catch(WebDriverException e){ + e.printStackTrace(); + } finally { + RegistryTestHelper.waitForActiveTestSessionCount(hub.getRegistry(), 0); + } + } + + @AfterClass + public void teardown() throws Exception { + node.stopRemoteServer(); + hub.stop(); + } + +} diff --git a/java/server/test/org/openqa/grid/e2e/node/SlowServlet.java b/java/server/test/org/openqa/grid/e2e/node/SlowServlet.java new file mode 100644 index 0000000000000..0085740b0e5f8 --- /dev/null +++ b/java/server/test/org/openqa/grid/e2e/node/SlowServlet.java @@ -0,0 +1,41 @@ +package org.openqa.grid.e2e.node; + +import org.openqa.grid.internal.Registry; +import org.openqa.grid.web.servlet.RegistryBasedServlet; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Beacuse re-use is discouraged in the CFB +*/ +public class SlowServlet extends RegistryBasedServlet { + private static final long serialVersionUID = 7653463271803124556L; + + public SlowServlet() { + this(null); + } + + public SlowServlet(Registry registry) { + super(registry); + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + try { + Thread.sleep(100000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + response.setContentType("text/html"); + response.setCharacterEncoding("UTF-8"); + response.setStatus(200); + + response.getOutputStream().write("OK".getBytes()); + response.getOutputStream().flush(); + } +} diff --git a/java/server/test/org/openqa/grid/e2e/utils/RegistryTestHelper.java b/java/server/test/org/openqa/grid/e2e/utils/RegistryTestHelper.java index 5796430ff41c5..1693a2acb90e0 100644 --- a/java/server/test/org/openqa/grid/e2e/utils/RegistryTestHelper.java +++ b/java/server/test/org/openqa/grid/e2e/utils/RegistryTestHelper.java @@ -43,4 +43,18 @@ public Integer call() throws Exception { } }); } + + + public static void waitForActiveTestSessionCount(final Registry r, final int activeTestSesssions) { + TestWaiter.waitFor(new Callable() { + public Integer call() throws Exception { + Integer i = r.getActiveSessions().size(); + if (i != activeTestSesssions) { + return null; + } else { + return i; + } + } + }); + } } diff --git a/java/server/test/org/openqa/grid/internal/utils/GridHubConfigurationTest.java b/java/server/test/org/openqa/grid/internal/utils/GridHubConfigurationTest.java new file mode 100644 index 0000000000000..b5870a0ffbb3e --- /dev/null +++ b/java/server/test/org/openqa/grid/internal/utils/GridHubConfigurationTest.java @@ -0,0 +1,43 @@ +package org.openqa.grid.internal.utils; +/* +Copyright 2011 WebDriver committers +Copyright 2011 Software Freedom Conservancy + +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. +*/ +import org.junit.Test; + +import static com.thoughtworks.selenium.SeleneseTestBase.assertEquals; +import static org.openqa.grid.internal.utils.ServerJsonValues.*; + +public class GridHubConfigurationTest { + + @Test + public void testGetTimeout() throws Exception { + GridHubConfiguration gridHubConfiguration = new GridHubConfiguration(); + assertEquals(300000, gridHubConfiguration.getTimeout()); // From DefaultHub.json file + gridHubConfiguration.setTimeout(123); + assertEquals(123, gridHubConfiguration.getTimeout()); + assertEquals(123,gridHubConfiguration.getAllParams().get(CLIENT_TIMEOUT.getKey())); + } + + @Test + public void testGetBrowserTimeout() throws Exception { + GridHubConfiguration gridHubConfiguration = new GridHubConfiguration(); + assertEquals(0, gridHubConfiguration.getBrowserTimeout());// From DefaultHub.json file + gridHubConfiguration.setBrowserTimeout(1233); + assertEquals(1233, gridHubConfiguration.getBrowserTimeout()); + assertEquals(1233,gridHubConfiguration.getAllParams().get(BROWSER_TIMEOUT.getKey())); + + } +} diff --git a/java/server/test/org/openqa/selenium/remote/server/DriverServletTest.java b/java/server/test/org/openqa/selenium/remote/server/DriverServletTest.java index 8b8be2f4c0d0f..676792807f76f 100644 --- a/java/server/test/org/openqa/selenium/remote/server/DriverServletTest.java +++ b/java/server/test/org/openqa/selenium/remote/server/DriverServletTest.java @@ -31,9 +31,19 @@ import org.openqa.selenium.remote.server.testing.FakeHttpServletResponse; import org.openqa.selenium.remote.server.testing.TestSessions; import org.openqa.selenium.remote.server.testing.UrlInfo; +import org.openqa.selenium.server.RemoteControlConfiguration; +import org.seleniumhq.jetty7.server.handler.ContextHandler; import java.io.IOException; - +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Enumeration; +import java.util.Set; + +import javax.servlet.RequestDispatcher; +import javax.servlet.Servlet; +import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; @@ -65,8 +75,14 @@ public void log(String msg) { @Override public void log(String message, Throwable t) { } - }; + @Override + public ServletContext getServletContext() { + final ContextHandler.Context servletContext = new ContextHandler().getServletContext(); + servletContext.setAttribute(RemoteControlConfiguration.KEY, new RemoteControlConfiguration()); + return servletContext; + } + }; driverServlet.init(); } diff --git a/java/server/test/org/openqa/selenium/remote/server/testing/TestSession.java b/java/server/test/org/openqa/selenium/remote/server/testing/TestSession.java index 8b06c97361949..668f9e5a76915 100644 --- a/java/server/test/org/openqa/selenium/remote/server/testing/TestSession.java +++ b/java/server/test/org/openqa/selenium/remote/server/testing/TestSession.java @@ -55,14 +55,20 @@ public void close() { executor.shutdown(); } - public X execute(FutureTask future) throws Exception { - try { - inUseWithThread = Thread.currentThread(); - executor.execute(future); + public X execute(final FutureTask future) throws Exception { + executor.execute(new Runnable() { + public void run() { + inUseWithThread = Thread.currentThread(); + inUseWithThread.setName("Session " + sessionId + " processing inside browser"); + try { + future.run(); + } finally { + inUseWithThread = null; + Thread.currentThread().setName("Session " + sessionId + " awaiting client"); + } + } + }); return future.get(); - } finally { - inUseWithThread = null; - } } public WebDriver getDriver() {