Skip to content

Commit 8be1107

Browse files
committed
[java] Implementing ability to specify command execution timeout in RemoteWebDriver
1 parent 77c187a commit 8be1107

File tree

10 files changed

+188
-82
lines changed

10 files changed

+188
-82
lines changed

java/client/src/org/openqa/selenium/remote/CommandExecutor.java

+6
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,15 @@
1818
package org.openqa.selenium.remote;
1919

2020
import java.io.IOException;
21+
import java.time.Duration;
2122

2223
@FunctionalInterface
2324
public interface CommandExecutor {
2425

2526
Response execute(Command command) throws IOException;
27+
28+
default void setCommandExecutionTimeout(Duration timeout) {
29+
throw new UnsupportedOperationException(
30+
"This command executor does not allow to change command execution timeout");
31+
}
2632
}

java/client/src/org/openqa/selenium/remote/HttpCommandExecutor.java

+20-11
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.io.IOException;
3535
import java.net.MalformedURLException;
3636
import java.net.URL;
37+
import java.time.Duration;
3738
import java.util.Map;
3839

3940
import static java.util.Collections.emptyMap;
@@ -68,19 +69,22 @@ public HttpCommandExecutor(URL addressOfRemoteServer) {
6869
* @param addressOfRemoteServer URL of remote end Selenium server
6970
*/
7071
public HttpCommandExecutor(
71-
Map<String, CommandInfo> additionalCommands,
72-
URL addressOfRemoteServer) {
72+
Map<String, CommandInfo> additionalCommands,
73+
URL addressOfRemoteServer)
74+
{
7375
this(additionalCommands, addressOfRemoteServer, defaultClientFactory);
7476
}
7577

7678
public HttpCommandExecutor(
77-
Map<String, CommandInfo> additionalCommands,
78-
URL addressOfRemoteServer,
79-
HttpClient.Factory httpClientFactory) {
79+
Map<String, CommandInfo> additionalCommands,
80+
URL addressOfRemoteServer,
81+
HttpClient.Factory httpClientFactory)
82+
{
8083
try {
8184
remoteServer = addressOfRemoteServer == null
82-
? new URL(System.getProperty("webdriver.remote.server", "http://localhost:4444/"))
83-
: addressOfRemoteServer;
85+
? new URL(System.getProperty("webdriver.remote.server",
86+
"http://localhost:4444/"))
87+
: addressOfRemoteServer;
8488
} catch (MalformedURLException e) {
8589
throw new WebDriverException(e);
8690
}
@@ -126,7 +130,7 @@ public Response execute(Command command) throws IOException {
126130
if (!GET_ALL_SESSIONS.equals(command.getName())
127131
&& !NEW_SESSION.equals(command.getName())) {
128132
throw new NoSuchSessionException(
129-
"Session ID is null. Using WebDriver after calling quit()?");
133+
"Session ID is null. Using WebDriver after calling quit()?");
130134
}
131135
}
132136

@@ -149,7 +153,7 @@ public Response execute(Command command) throws IOException {
149153

150154
if (commandCodec == null || responseCodec == null) {
151155
throw new WebDriverException(
152-
"No command or response codec has been defined. Unable to proceed");
156+
"No command or response codec has been defined. Unable to proceed");
153157
}
154158

155159
HttpRequest httpRequest = commandCodec.encode(command);
@@ -180,10 +184,15 @@ public Response execute(Command command) throws IOException {
180184
} catch (UnsupportedCommandException e) {
181185
if (e.getMessage() == null || "".equals(e.getMessage())) {
182186
throw new UnsupportedOperationException(
183-
"No information from server. Command name was: " + command.getName(),
184-
e.getCause());
187+
"No information from server. Command name was: " + command.getName(),
188+
e.getCause());
185189
}
186190
throw e;
187191
}
188192
}
193+
194+
@Override
195+
public synchronized void setCommandExecutionTimeout(Duration timeout) {
196+
client.setReadTimeout(timeout);
197+
}
189198
}

java/client/src/org/openqa/selenium/remote/RemoteWebDriver.java

+52-45
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,10 @@ protected void setCommandExecutor(CommandExecutor executor) {
279279
this.executor = executor;
280280
}
281281

282+
public synchronized void setCommandExecutionTimeout(Duration timeout) {
283+
executor.setCommandExecutionTimeout(timeout);
284+
}
285+
282286
@Override
283287
public Capabilities getCapabilities() {
284288
return capabilities;
@@ -316,9 +320,10 @@ public <X> X getScreenshotAs(OutputType<X> outputType) throws WebDriverException
316320
String base64EncodedPng = new String((byte[]) result, UTF_8);
317321
return outputType.convertFromBase64Png(base64EncodedPng);
318322
} else {
319-
throw new RuntimeException(String.format("Unexpected result for %s command: %s",
320-
DriverCommand.SCREENSHOT,
321-
result == null ? "null" : result.getClass().getName() + " instance"));
323+
throw new RuntimeException(String.format(
324+
"Unexpected result for %s command: %s",
325+
DriverCommand.SCREENSHOT,
326+
result == null ? "null" : result.getClass().getName() + " instance"));
322327
}
323328
}
324329

@@ -438,14 +443,15 @@ public String getWindowHandle() {
438443
public Object executeScript(String script, Object... args) {
439444
if (!isJavascriptEnabled()) {
440445
throw new UnsupportedOperationException(
441-
"You must be using an underlying instance of WebDriver that supports executing javascript");
446+
"You must be using an underlying instance of WebDriver that supports executing javascript");
442447
}
443448

444449
// Escape the quote marks
445450
script = script.replaceAll("\"", "\\\"");
446451

447-
List<Object> convertedArgs = Stream.of(args).map(new WebElementToJsonConverter()).collect(
448-
Collectors.toList());
452+
List<Object> convertedArgs = Stream.of(args)
453+
.map(new WebElementToJsonConverter())
454+
.collect(Collectors.toList());
449455

450456
return execute(DriverCommand.EXECUTE_SCRIPT(script, convertedArgs)).getValue();
451457
}
@@ -454,14 +460,15 @@ public Object executeScript(String script, Object... args) {
454460
public Object executeAsyncScript(String script, Object... args) {
455461
if (!isJavascriptEnabled()) {
456462
throw new UnsupportedOperationException("You must be using an underlying instance of " +
457-
"WebDriver that supports executing javascript");
463+
"WebDriver that supports executing javascript");
458464
}
459465

460466
// Escape the quote marks
461467
script = script.replaceAll("\"", "\\\"");
462468

463-
List<Object> convertedArgs = Stream.of(args).map(new WebElementToJsonConverter()).collect(
464-
Collectors.toList());
469+
List<Object> convertedArgs = Stream.of(args)
470+
.map(new WebElementToJsonConverter())
471+
.collect(Collectors.toList());
465472

466473
return execute(DriverCommand.EXECUTE_ASYNC_SCRIPT(script, convertedArgs)).getValue();
467474
}
@@ -596,15 +603,15 @@ public Mouse getMouse() {
596603

597604
@Override
598605
public VirtualAuthenticator addVirtualAuthenticator(VirtualAuthenticatorOptions options) {
599-
String authenticatorId = (String)
600-
execute(DriverCommand.ADD_VIRTUAL_AUTHENTICATOR, options.toMap()).getValue();
606+
String authenticatorId = (String) execute(
607+
DriverCommand.ADD_VIRTUAL_AUTHENTICATOR, options.toMap()).getValue();
601608
return new RemoteVirtualAuthenticator(authenticatorId);
602609
}
603610

604611
@Override
605612
public void removeVirtualAuthenticator(VirtualAuthenticator authenticator) {
606613
execute(DriverCommand.REMOVE_VIRTUAL_AUTHENTICATOR,
607-
ImmutableMap.of("authenticatorId", authenticator.getId()));
614+
ImmutableMap.of("authenticatorId", authenticator.getId()));
608615
}
609616

610617
/**
@@ -687,24 +694,24 @@ public Set<Cookie> getCookies() {
687694
}
688695

689696
((Collection<?>) returned).stream()
690-
.map(o -> (Map<String, Object>) o)
691-
.map(rawCookie -> {
692-
// JSON object keys are defined in
693-
// https://w3c.github.io/webdriver/#dfn-table-for-cookie-conversion.
694-
Cookie.Builder builder =
695-
new Cookie.Builder((String) rawCookie.get("name"), (String) rawCookie.get("value"))
696-
.path((String) rawCookie.get("path"))
697-
.domain((String) rawCookie.get("domain"))
698-
.isSecure(rawCookie.containsKey("secure") && (Boolean) rawCookie.get("secure"))
699-
.isHttpOnly(
700-
rawCookie.containsKey("httpOnly") && (Boolean) rawCookie.get("httpOnly"))
701-
.sameSite((String) rawCookie.get("sameSite"));
702-
703-
Number expiryNum = (Number) rawCookie.get("expiry");
704-
builder.expiresOn(expiryNum == null ? null : new Date(SECONDS.toMillis(expiryNum.longValue())));
705-
return builder.build();
706-
})
707-
.forEach(toReturn::add);
697+
.map(o -> (Map<String, Object>) o)
698+
.map(rawCookie -> {
699+
// JSON object keys are defined in
700+
// https://w3c.github.io/webdriver/#dfn-table-for-cookie-conversion.
701+
Cookie.Builder builder =
702+
new Cookie.Builder((String) rawCookie.get("name"), (String) rawCookie.get("value"))
703+
.path((String) rawCookie.get("path"))
704+
.domain((String) rawCookie.get("domain"))
705+
.isSecure(rawCookie.containsKey("secure") && (Boolean) rawCookie.get("secure"))
706+
.isHttpOnly(
707+
rawCookie.containsKey("httpOnly") && (Boolean) rawCookie.get("httpOnly"))
708+
.sameSite((String) rawCookie.get("sameSite"));
709+
710+
Number expiryNum = (Number) rawCookie.get("expiry");
711+
builder.expiresOn(expiryNum == null ? null : new Date(SECONDS.toMillis(expiryNum.longValue())));
712+
return builder.build();
713+
})
714+
.forEach(toReturn::add);
708715

709716
return toReturn;
710717
}
@@ -903,10 +910,10 @@ public WebDriver frame(int frameIndex) {
903910
public WebDriver frame(String frameName) {
904911
String name = frameName.replaceAll("(['\"\\\\#.:;,!?+<>=~*^$|%&@`{}\\-/\\[\\]\\(\\)])", "\\\\$1");
905912
List<WebElement> frameElements = RemoteWebDriver.this.findElements(
906-
By.cssSelector("frame[name='" + name + "'],iframe[name='" + name + "']"));
913+
By.cssSelector("frame[name='" + name + "'],iframe[name='" + name + "']"));
907914
if (frameElements.size() == 0) {
908915
frameElements = RemoteWebDriver.this.findElements(
909-
By.cssSelector("frame#" + name + ",iframe#" + name));
916+
By.cssSelector("frame#" + name + ",iframe#" + name));
910917
}
911918
if (frameElements.size() == 0) {
912919
throw new NoSuchFrameException("No frame element found by name or id " + frameName);
@@ -1028,16 +1035,16 @@ public String getId() {
10281035
@Override
10291036
public void addCredential(Credential credential) {
10301037
execute(DriverCommand.ADD_CREDENTIAL,
1031-
new ImmutableMap.Builder<String, Object>()
1032-
.putAll(credential.toMap())
1033-
.put("authenticatorId", id)
1034-
.build());
1038+
new ImmutableMap.Builder<String, Object>()
1039+
.putAll(credential.toMap())
1040+
.put("authenticatorId", id)
1041+
.build());
10351042
}
10361043

10371044
@Override
10381045
public List<Credential> getCredentials() {
1039-
List<Map<String, Object>> response = (List<Map<String, Object>>)
1040-
execute(DriverCommand.GET_CREDENTIALS, ImmutableMap.of("authenticatorId", id)).getValue();
1046+
List<Map<String, Object>> response = (List<Map<String, Object>>) execute(
1047+
DriverCommand.GET_CREDENTIALS, ImmutableMap.of("authenticatorId", id)).getValue();
10411048
return response.stream().map(Credential::fromMap).collect(Collectors.toList());
10421049
}
10431050

@@ -1049,7 +1056,7 @@ public void removeCredential(byte[] credentialId) {
10491056
@Override
10501057
public void removeCredential(String credentialId) {
10511058
execute(DriverCommand.REMOVE_CREDENTIAL,
1052-
ImmutableMap.of("authenticatorId", id, "credentialId", credentialId));
1059+
ImmutableMap.of("authenticatorId", id, "credentialId", credentialId));
10531060
}
10541061

10551062
@Override
@@ -1060,7 +1067,7 @@ public void removeAllCredentials() {
10601067
@Override
10611068
public void setUserVerified(boolean verified) {
10621069
execute(DriverCommand.SET_USER_VERIFIED,
1063-
ImmutableMap.of("authenticatorId", id, "isUserVerified", verified));
1070+
ImmutableMap.of("authenticatorId", id, "isUserVerified", verified));
10641071
}
10651072
}
10661073

@@ -1087,10 +1094,10 @@ public String toString() {
10871094
}
10881095

10891096
return String.format(
1090-
"%s: %s on %s (%s)",
1091-
getClass().getSimpleName(),
1092-
caps.getBrowserName(),
1093-
platform,
1094-
getSessionId());
1097+
"%s: %s on %s (%s)",
1098+
getClass().getSimpleName(),
1099+
caps.getBrowserName(),
1100+
platform,
1101+
getSessionId());
10951102
}
10961103
}

java/client/src/org/openqa/selenium/remote/http/HttpClient.java

+9-4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package org.openqa.selenium.remote.http;
1919

2020
import java.net.URL;
21+
import java.time.Duration;
2122
import java.util.ServiceLoader;
2223
import java.util.Set;
2324
import java.util.stream.Collectors;
@@ -34,6 +35,10 @@ public interface HttpClient extends HttpHandler {
3435

3536
WebSocket openSocket(HttpRequest request, WebSocket.Listener listener);
3637

38+
default void setReadTimeout(Duration timeout) {
39+
throw new UnsupportedOperationException("This client does not allow to change read timeout");
40+
}
41+
3742
interface Factory {
3843

3944
/**
@@ -47,15 +52,15 @@ interface Factory {
4752
static Factory create(String name) {
4853
ServiceLoader<HttpClient.Factory> loader = ServiceLoader.load(HttpClient.Factory.class);
4954
Set<Factory> factories = StreamSupport.stream(loader.spliterator(), true)
50-
.filter(p -> p.getClass().isAnnotationPresent(HttpClientName.class))
51-
.filter(p -> name.equals(p.getClass().getAnnotation(HttpClientName.class).value()))
52-
.collect(Collectors.toSet());
55+
.filter(p -> p.getClass().isAnnotationPresent(HttpClientName.class))
56+
.filter(p -> name.equals(p.getClass().getAnnotation(HttpClientName.class).value()))
57+
.collect(Collectors.toSet());
5358
if (factories.isEmpty()) {
5459
throw new IllegalArgumentException("Unknown HttpClient factory " + name);
5560
}
5661
if (factories.size() > 1) {
5762
throw new IllegalStateException(String.format(
58-
"There are multiple HttpClient factories by name %s, check your classpath", name));
63+
"There are multiple HttpClient factories by name %s, check your classpath", name));
5964
}
6065
return factories.iterator().next();
6166
}

java/client/src/org/openqa/selenium/remote/http/HttpHandler.java

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package org.openqa.selenium.remote.http;
1919

2020
import java.io.UncheckedIOException;
21+
import java.time.Duration;
2122

2223
@FunctionalInterface
2324
public interface HttpHandler {

0 commit comments

Comments
 (0)