Skip to content

Commit 6ff2071

Browse files
Merge pull request #894 from TikhomirovSergey/master
#875 FIX
2 parents ed07bcd + 8b46991 commit 6ff2071

File tree

12 files changed

+234
-39
lines changed

12 files changed

+234
-39
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ compileJava {
5050
]
5151
}
5252

53-
ext.seleniumVersion = '3.11.0'
53+
ext.seleniumVersion = '3.12.0'
5454

5555
dependencies {
5656
compile ("org.seleniumhq.selenium:selenium-java:${seleniumVersion}") {

src/main/java/io/appium/java_client/android/nativekey/AndroidKey.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1411,6 +1411,8 @@ public boolean isSystemKey() {
14111411
}
14121412

14131413
/**
1414+
* Is it wake key or not.
1415+
*
14141416
* @return true if this a wakeup key.
14151417
*/
14161418
public boolean isWakeKey() {

src/main/java/io/appium/java_client/events/DefaultAspect.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.aspectj.lang.JoinPoint;
2525
import org.aspectj.lang.ProceedingJoinPoint;
2626
import org.aspectj.lang.annotation.After;
27+
import org.aspectj.lang.annotation.AfterReturning;
2728
import org.aspectj.lang.annotation.Around;
2829
import org.aspectj.lang.annotation.Aspect;
2930
import org.aspectj.lang.annotation.Before;
@@ -38,6 +39,7 @@
3839
import java.util.Collection;
3940
import java.util.List;
4041

42+
@SuppressWarnings("unused")
4143
@Aspect
4244
class DefaultAspect {
4345

@@ -85,6 +87,8 @@ class DefaultAspect {
8587
+ "context(..))";
8688
private static final String EXECUTION_SWITCH_TO_WINDOW = "execution(* org.openqa.selenium.WebDriver.TargetLocator"
8789
+ ".window(..))";
90+
private static final String EXECUTION_TAKE_SCREENSHOT_AS = "execution(* org.openqa.selenium.TakesScreenshot"
91+
+ ".getScreenshotAs(..))";
8892
private static final String AROUND = "execution(* org.openqa.selenium.WebDriver.*(..)) || "
8993
+ "execution(* org.openqa.selenium.WebElement.*(..)) || "
9094
+ "execution(* org.openqa.selenium.WebDriver.Navigation.*(..)) || "
@@ -114,7 +118,8 @@ class DefaultAspect {
114118
+ "execution(* io.appium.java_client.MobileElement.*(..)) || "
115119
+ "execution(* org.openqa.selenium.remote.RemoteWebDriver.*(..)) || "
116120
+ "execution(* org.openqa.selenium.remote.RemoteWebElement.*(..)) || "
117-
+ "execution(* org.openqa.selenium.Alert.*(..))";
121+
+ "execution(* org.openqa.selenium.Alert.*(..)) || "
122+
+ "execution(* org.openqa.selenium.TakesScreenshot.*(..))";
118123

119124
private final AbstractApplicationContext context;
120125
private final WebDriver driver;
@@ -483,6 +488,24 @@ public void afterSwitchToWindow(JoinPoint joinPoint) throws Throwable {
483488
}
484489
}
485490

491+
@Before(EXECUTION_TAKE_SCREENSHOT_AS)
492+
public void beforeTakeScreenShot(JoinPoint joinPoint) throws Throwable {
493+
try {
494+
listener.beforeGetScreenshotAs(castArgument(joinPoint, 0));
495+
} catch (Throwable t) {
496+
throw getRootCause(t);
497+
}
498+
}
499+
500+
@AfterReturning(value = EXECUTION_TAKE_SCREENSHOT_AS, returning = "result")
501+
public void afterTakeScreenShot(JoinPoint joinPoint, Object result) throws Throwable {
502+
try {
503+
listener.afterGetScreenshotAs(castArgument(joinPoint, 0), result);
504+
} catch (Throwable t) {
505+
throw getRootCause(t);
506+
}
507+
}
508+
486509
@Before(EXECUTION_ROTATE)
487510
public void beforeRotation(JoinPoint joinPoint) throws Throwable {
488511
try {

src/main/java/io/appium/java_client/events/DefaultListener.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.openqa.selenium.Alert;
3131
import org.openqa.selenium.By;
3232
import org.openqa.selenium.Dimension;
33+
import org.openqa.selenium.OutputType;
3334
import org.openqa.selenium.Point;
3435
import org.openqa.selenium.ScreenOrientation;
3536
import org.openqa.selenium.WebDriver;
@@ -133,6 +134,16 @@ class DefaultListener
133134
((ListensToException) dispatcher).onException(throwable, driver);
134135
}
135136

137+
@Override
138+
public <X> void beforeGetScreenshotAs(OutputType<X> target) {
139+
((WebDriverEventListener) dispatcher).beforeGetScreenshotAs(target);
140+
}
141+
142+
@Override
143+
public <X> void afterGetScreenshotAs(OutputType<X> target, X screenshot) {
144+
((WebDriverEventListener) dispatcher).afterGetScreenshotAs(target, screenshot);
145+
}
146+
136147
public void add(Collection<Listener> listeners) {
137148
this.listeners.addAll(listeners);
138149
}

src/main/java/io/appium/java_client/remote/AppiumCommandExecutor.java

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,45 @@
1818

1919
import static com.google.common.base.Preconditions.checkNotNull;
2020
import static com.google.common.base.Throwables.throwIfUnchecked;
21+
import static java.lang.String.format;
22+
import static java.nio.charset.StandardCharsets.UTF_8;
2123
import static java.util.Optional.ofNullable;
24+
import static java.util.logging.Logger.getLogger;
25+
import static org.openqa.selenium.remote.DriverCommand.NEW_SESSION;
2226

2327
import com.google.common.base.Supplier;
2428
import com.google.common.base.Throwables;
2529

30+
import com.google.common.io.CountingOutputStream;
31+
import com.google.common.io.FileBackedOutputStream;
32+
33+
import org.openqa.selenium.Capabilities;
34+
import org.openqa.selenium.ImmutableCapabilities;
35+
import org.openqa.selenium.SessionNotCreatedException;
2636
import org.openqa.selenium.WebDriverException;
2737
import org.openqa.selenium.remote.Command;
2838
import org.openqa.selenium.remote.CommandCodec;
2939
import org.openqa.selenium.remote.CommandInfo;
40+
import org.openqa.selenium.remote.Dialect;
3041
import org.openqa.selenium.remote.DriverCommand;
3142
import org.openqa.selenium.remote.HttpCommandExecutor;
43+
import org.openqa.selenium.remote.ProtocolHandshake;
3244
import org.openqa.selenium.remote.Response;
45+
import org.openqa.selenium.remote.ResponseCodec;
3346
import org.openqa.selenium.remote.http.HttpClient;
3447
import org.openqa.selenium.remote.http.HttpRequest;
48+
import org.openqa.selenium.remote.http.HttpResponse;
3549
import org.openqa.selenium.remote.http.W3CHttpCommandCodec;
3650
import org.openqa.selenium.remote.service.DriverService;
3751

52+
import java.io.BufferedInputStream;
3853
import java.io.IOException;
54+
import java.io.InputStream;
55+
import java.io.OutputStreamWriter;
56+
import java.io.Writer;
3957
import java.lang.reflect.Field;
58+
import java.lang.reflect.InvocationTargetException;
59+
import java.lang.reflect.Method;
4060
import java.net.ConnectException;
4161
import java.net.URL;
4262
import java.util.Map;
@@ -111,6 +131,76 @@ private void setCommandCodec(CommandCodec<HttpRequest> newCodec) {
111131
setPrivateFieldValue("commandCodec", newCodec);
112132
}
113133

134+
private void setResponseCodec(ResponseCodec<HttpResponse> codec) {
135+
setPrivateFieldValue("responseCodec", codec);
136+
}
137+
138+
private HttpClient getClient() {
139+
//noinspection unchecked
140+
return getPrivateFieldValue("client", HttpClient.class);
141+
}
142+
143+
private Response createSession(Command command) throws IOException {
144+
if (getCommandCodec() != null) {
145+
throw new SessionNotCreatedException("Session already exists");
146+
}
147+
ProtocolHandshake handshake = new ProtocolHandshake() {
148+
@SuppressWarnings("unchecked")
149+
public Result createSession(HttpClient client, Command command)
150+
throws IOException {
151+
Capabilities desiredCapabilities = (Capabilities) command.getParameters().get("desiredCapabilities");
152+
Capabilities desired = desiredCapabilities == null ? new ImmutableCapabilities() : desiredCapabilities;
153+
154+
//the number of bytes before the stream should switch to buffering to a file
155+
int threshold = (int) Math.min(Runtime.getRuntime().freeMemory() / 10, Integer.MAX_VALUE);
156+
FileBackedOutputStream os = new FileBackedOutputStream(threshold);
157+
try {
158+
159+
CountingOutputStream counter = new CountingOutputStream(os);
160+
Writer writer = new OutputStreamWriter(counter, UTF_8);
161+
NewAppiumSessionPayload payload = NewAppiumSessionPayload.create(desired);
162+
payload.writeTo(writer);
163+
164+
try (InputStream rawIn = os.asByteSource().openBufferedStream();
165+
BufferedInputStream contentStream = new BufferedInputStream(rawIn)) {
166+
167+
Method createSessionMethod = this.getClass().getSuperclass()
168+
.getDeclaredMethod("createSession", HttpClient.class, InputStream.class, long.class);
169+
createSessionMethod.setAccessible(true);
170+
171+
Optional<Result> result = (Optional<Result>) createSessionMethod
172+
.invoke(this, client, contentStream, counter.getCount());
173+
174+
return result.map(result1 -> {
175+
Result toReturn = result.get();
176+
getLogger(ProtocolHandshake.class.getName())
177+
.info(format("Detected dialect: %s", toReturn.getDialect()));
178+
return toReturn;
179+
}).orElseThrow(() -> new SessionNotCreatedException(
180+
format("Unable to create new remote session. desired capabilities = %s", desired)));
181+
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
182+
throw new WebDriverException(format("It is impossible to create a new session "
183+
+ "because 'createSession' which takes %s, %s and %s was not found "
184+
+ "or it is not accessible",
185+
HttpClient.class.getSimpleName(),
186+
InputStream.class.getSimpleName(),
187+
long.class.getSimpleName()), e);
188+
}
189+
} finally {
190+
os.reset();
191+
}
192+
}
193+
};
194+
195+
ProtocolHandshake.Result result = handshake
196+
.createSession(getClient(), command);
197+
Dialect dialect = result.getDialect();
198+
setCommandCodec(dialect.getCommandCodec());
199+
getAdditionalCommands().forEach(this::defineCommand);
200+
setResponseCodec(dialect.getResponseCodec());
201+
return result.createResponse();
202+
}
203+
114204
@Override
115205
public Response execute(Command command) throws WebDriverException {
116206
if (DriverCommand.NEW_SESSION.equals(command.getName())) {
@@ -125,7 +215,7 @@ public Response execute(Command command) throws WebDriverException {
125215

126216
Response response;
127217
try {
128-
response = super.execute(command);
218+
response = NEW_SESSION.equals(command.getName()) ? createSession(command) : super.execute(command);
129219
} catch (Throwable t) {
130220
Throwable rootCause = Throwables.getRootCause(t);
131221
if (rootCause instanceof ConnectException

0 commit comments

Comments
 (0)