Skip to content

Commit 6b91363

Browse files
Merge pull request #240 from TikhomirovSergey/#147-fix
#147 Fix. The Appium node silent starting
2 parents d70f3b4 + e48c5d2 commit 6b91363

33 files changed

+1722
-204
lines changed

pom.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@
3838
<artifactId>cglib</artifactId>
3939
<version>3.1</version>
4040
</dependency>
41+
<dependency>
42+
<groupId>commons-validator</groupId>
43+
<artifactId>commons-validator</artifactId>
44+
<version>1.4.1</version>
45+
</dependency>
4146
</dependencies>
4247
<packaging>jar</packaging>
4348
<name>java-client</name>
@@ -65,6 +70,12 @@
6570
<url>https://github.com/jonahss</url>
6671
<id>jonahss</id>
6772
</developer>
73+
<developer>
74+
<email>[email protected]</email>
75+
<name>Sergey Tikhomirov</name>
76+
<url>https://github.com/TikhomirovSergey</url>
77+
<id>TikhomirovSergey</id>
78+
</developer>
6879
</developers>
6980

7081
<distributionManagement>

src/main/java/io/appium/java_client/AppiumDriver.java

Lines changed: 87 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
import static io.appium.java_client.MobileCommand.SHAKE;
4747
import static io.appium.java_client.MobileCommand.START_ACTIVITY;
4848
import static io.appium.java_client.MobileCommand.TOGGLE_LOCATION_SERVICES;
49+
50+
import io.appium.java_client.remote.AppiumCommandExecutor;
4951
import io.appium.java_client.remote.MobileCapabilityType;
5052

5153
import java.net.URL;
@@ -55,6 +57,8 @@
5557

5658
import javax.xml.bind.DatatypeConverter;
5759

60+
import io.appium.java_client.service.local.AppiumDriverLocalService;
61+
import io.appium.java_client.service.local.AppiumServiceBuilder;
5862
import org.openqa.selenium.By;
5963
import org.openqa.selenium.Capabilities;
6064
import org.openqa.selenium.Dimension;
@@ -64,14 +68,7 @@
6468
import org.openqa.selenium.WebDriverException;
6569
import org.openqa.selenium.WebElement;
6670
import org.openqa.selenium.html5.Location;
67-
import org.openqa.selenium.remote.CommandInfo;
68-
import org.openqa.selenium.remote.DesiredCapabilities;
69-
import org.openqa.selenium.remote.DriverCommand;
70-
import org.openqa.selenium.remote.ErrorHandler;
71-
import org.openqa.selenium.remote.ExecuteMethod;
72-
import org.openqa.selenium.remote.HttpCommandExecutor;
73-
import org.openqa.selenium.remote.RemoteWebElement;
74-
import org.openqa.selenium.remote.Response;
71+
import org.openqa.selenium.remote.*;
7572
import org.openqa.selenium.remote.html5.RemoteLocationContext;
7673
import org.openqa.selenium.remote.http.HttpMethod;
7774

@@ -197,76 +194,34 @@ protected static ImmutableMap<String, Object> getCommandImmutableMap(
197194
return builder.build();
198195
}
199196

200-
public AppiumDriver(URL remoteAddress, Capabilities desiredCapabilities) {
197+
private AppiumDriver(CommandExecutor executor, Capabilities capabilities){
198+
super(executor, capabilities);
199+
this.executeMethod = new AppiumExecutionMethod(this);
200+
locationContext = new RemoteLocationContext(executeMethod);
201+
super.setErrorHandler(errorHandler);
202+
}
201203

202-
super(remoteAddress, desiredCapabilities);
203-
204-
this.executeMethod = new AppiumExecutionMethod(this);
205-
this.remoteAddress = remoteAddress;
206-
locationContext = new RemoteLocationContext(executeMethod);
207-
208-
ImmutableMap.Builder<String, CommandInfo> builder = ImmutableMap
209-
.builder();
210-
builder.put(RESET, postC("/session/:sessionId/appium/app/reset"))
211-
.put(GET_STRINGS,
212-
postC("/session/:sessionId/appium/app/strings"))
213-
.put(KEY_EVENT,
214-
postC("/session/:sessionId/appium/device/keyevent"))
215-
.put(CURRENT_ACTIVITY,
216-
getC("/session/:sessionId/appium/device/current_activity"))
217-
.put(SET_VALUE,
218-
postC("/session/:sessionId/appium/element/:id/value"))
219-
.put(PULL_FILE,
220-
postC("/session/:sessionId/appium/device/pull_file"))
221-
.put(PULL_FOLDER,
222-
postC("/session/:sessionId/appium/device/pull_folder"))
223-
.put(HIDE_KEYBOARD,
224-
postC("/session/:sessionId/appium/device/hide_keyboard"))
225-
.put(PUSH_FILE,
226-
postC("/session/:sessionId/appium/device/push_file"))
227-
.put(RUN_APP_IN_BACKGROUND,
228-
postC("/session/:sessionId/appium/app/background"))
229-
.put(PERFORM_TOUCH_ACTION,
230-
postC("/session/:sessionId/touch/perform"))
231-
.put(PERFORM_MULTI_TOUCH,
232-
postC("/session/:sessionId/touch/multi/perform"))
233-
.put(IS_APP_INSTALLED,
234-
postC("/session/:sessionId/appium/device/app_installed"))
235-
.put(INSTALL_APP,
236-
postC("/session/:sessionId/appium/device/install_app"))
237-
.put(REMOVE_APP,
238-
postC("/session/:sessionId/appium/device/remove_app"))
239-
.put(LAUNCH_APP, postC("/session/:sessionId/appium/app/launch"))
240-
.put(CLOSE_APP, postC("/session/:sessionId/appium/app/close"))
241-
.put(END_TEST_COVERAGE,
242-
postC("/session/:sessionId/appium/app/end_test_coverage"))
243-
.put(LOCK, postC("/session/:sessionId/appium/device/lock"))
244-
.put(IS_LOCKED,
245-
postC("/session/:sessionId/appium/device/is_locked"))
246-
.put(SHAKE, postC("/session/:sessionId/appium/device/shake"))
247-
.put(COMPLEX_FIND,
248-
postC("/session/:sessionId/appium/app/complex_find"))
249-
.put(OPEN_NOTIFICATIONS,
250-
postC("/session/:sessionId/appium/device/open_notifications"))
251-
.put(GET_NETWORK_CONNECTION,
252-
getC("/session/:sessionId/network_connection"))
253-
.put(SET_NETWORK_CONNECTION,
254-
postC("/session/:sessionId/network_connection"))
255-
.put(GET_SETTINGS, getC("/session/:sessionId/appium/settings"))
256-
.put(SET_SETTINGS, postC("/session/:sessionId/appium/settings"))
257-
.put(START_ACTIVITY,
258-
postC("/session/:sessionId/appium/device/start_activity"))
259-
.put(TOGGLE_LOCATION_SERVICES, postC("/session/:sessionId/appium/device/toggle_location_services"));
260-
261-
ImmutableMap<String, CommandInfo> mobileCommands = builder.build();
262-
263-
HttpCommandExecutor mobileExecutor = new HttpCommandExecutor(
264-
mobileCommands, remoteAddress);
265-
super.setCommandExecutor(mobileExecutor);
266-
267-
super.setErrorHandler(errorHandler);
204+
public AppiumDriver(URL remoteAddress, Capabilities desiredCapabilities) {
205+
this(new AppiumCommandExecutor(
206+
getMobileCommands(), remoteAddress), desiredCapabilities);
207+
this.remoteAddress = remoteAddress;
268208
}
269209

210+
public AppiumDriver(AppiumDriverLocalService service, Capabilities desiredCapabilities) {
211+
this(new AppiumCommandExecutor(
212+
getMobileCommands(), service), desiredCapabilities);
213+
this.remoteAddress = service.getUrl();
214+
}
215+
216+
public AppiumDriver(AppiumServiceBuilder builder, Capabilities desiredCapabilities) {
217+
this(builder.build(), desiredCapabilities);
218+
}
219+
220+
public AppiumDriver(Capabilities desiredCapabilities) {
221+
this(AppiumDriverLocalService.buildDefaultService(), desiredCapabilities);
222+
}
223+
224+
270225
@Override
271226
protected Response execute(String command) {
272227
return super.execute(command, ImmutableMap.<String, Object>of());
@@ -708,6 +663,63 @@ private static CommandInfo postC(String url) {
708663
return new CommandInfo(url, HttpMethod.POST);
709664
}
710665

666+
private static ImmutableMap<String, CommandInfo> getMobileCommands(){
667+
ImmutableMap.Builder<String, CommandInfo> builder = ImmutableMap
668+
.builder();
669+
builder.put(RESET, postC("/session/:sessionId/appium/app/reset"))
670+
.put(GET_STRINGS,
671+
postC("/session/:sessionId/appium/app/strings"))
672+
.put(KEY_EVENT,
673+
postC("/session/:sessionId/appium/device/keyevent"))
674+
.put(CURRENT_ACTIVITY,
675+
getC("/session/:sessionId/appium/device/current_activity"))
676+
.put(SET_VALUE,
677+
postC("/session/:sessionId/appium/element/:id/value"))
678+
.put(PULL_FILE,
679+
postC("/session/:sessionId/appium/device/pull_file"))
680+
.put(PULL_FOLDER,
681+
postC("/session/:sessionId/appium/device/pull_folder"))
682+
.put(HIDE_KEYBOARD,
683+
postC("/session/:sessionId/appium/device/hide_keyboard"))
684+
.put(PUSH_FILE,
685+
postC("/session/:sessionId/appium/device/push_file"))
686+
.put(RUN_APP_IN_BACKGROUND,
687+
postC("/session/:sessionId/appium/app/background"))
688+
.put(PERFORM_TOUCH_ACTION,
689+
postC("/session/:sessionId/touch/perform"))
690+
.put(PERFORM_MULTI_TOUCH,
691+
postC("/session/:sessionId/touch/multi/perform"))
692+
.put(IS_APP_INSTALLED,
693+
postC("/session/:sessionId/appium/device/app_installed"))
694+
.put(INSTALL_APP,
695+
postC("/session/:sessionId/appium/device/install_app"))
696+
.put(REMOVE_APP,
697+
postC("/session/:sessionId/appium/device/remove_app"))
698+
.put(LAUNCH_APP, postC("/session/:sessionId/appium/app/launch"))
699+
.put(CLOSE_APP, postC("/session/:sessionId/appium/app/close"))
700+
.put(END_TEST_COVERAGE,
701+
postC("/session/:sessionId/appium/app/end_test_coverage"))
702+
.put(LOCK, postC("/session/:sessionId/appium/device/lock"))
703+
.put(IS_LOCKED,
704+
postC("/session/:sessionId/appium/device/is_locked"))
705+
.put(SHAKE, postC("/session/:sessionId/appium/device/shake"))
706+
.put(COMPLEX_FIND,
707+
postC("/session/:sessionId/appium/app/complex_find"))
708+
.put(OPEN_NOTIFICATIONS,
709+
postC("/session/:sessionId/appium/device/open_notifications"))
710+
.put(GET_NETWORK_CONNECTION,
711+
getC("/session/:sessionId/network_connection"))
712+
.put(SET_NETWORK_CONNECTION,
713+
postC("/session/:sessionId/network_connection"))
714+
.put(GET_SETTINGS, getC("/session/:sessionId/appium/settings"))
715+
.put(SET_SETTINGS, postC("/session/:sessionId/appium/settings"))
716+
.put(START_ACTIVITY,
717+
postC("/session/:sessionId/appium/device/start_activity"))
718+
.put(TOGGLE_LOCATION_SERVICES, postC("/session/:sessionId/appium/device/toggle_location_services"));
719+
720+
return builder.build();
721+
}
722+
711723
@SuppressWarnings("unused")
712724
private static CommandInfo deleteC(String url) {
713725
return new CommandInfo(url, HttpMethod.DELETE);

src/main/java/io/appium/java_client/DefaultGenericMobileDriver.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
import org.openqa.selenium.By;
77
import org.openqa.selenium.Capabilities;
88
import org.openqa.selenium.WebElement;
9+
import org.openqa.selenium.remote.CommandExecutor;
910
import org.openqa.selenium.remote.RemoteWebDriver;
1011
import org.openqa.selenium.remote.Response;
1112

12-
import java.net.URL;
1313
import java.util.List;
1414
import java.util.Map;
1515

@@ -18,8 +18,8 @@ abstract class DefaultGenericMobileDriver<T extends WebElement> extends RemoteWe
1818
GenericSearchContext<T>, GenericFindsById<T>, GenericFindsByXPath<T>, GenericFindsByLinkText<T>, GenericFindsByTagName<T>,
1919
GenericFindsByClassName<T>, GenericFindsByCssSelector<T>, GenericFindsByName<T>{
2020

21-
public DefaultGenericMobileDriver(URL remoteAddress, Capabilities desiredCapabilities) {
22-
super(remoteAddress, desiredCapabilities);
21+
public DefaultGenericMobileDriver(CommandExecutor executor, Capabilities desiredCapabilities){
22+
super(executor, desiredCapabilities);
2323
}
2424

2525
@Override

src/main/java/io/appium/java_client/android/AndroidDriver.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import io.appium.java_client.android.internal.JsonToAndroidElementConverter;
1010
import io.appium.java_client.remote.MobilePlatform;
1111

12+
import io.appium.java_client.service.local.AppiumDriverLocalService;
13+
import io.appium.java_client.service.local.AppiumServiceBuilder;
1214
import org.openqa.selenium.Capabilities;
1315
import org.openqa.selenium.WebElement;
1416
import org.openqa.selenium.remote.Response;
@@ -51,6 +53,24 @@ public AndroidDriver(URL remoteAddress, Capabilities desiredCapabilities) {
5153
this.setElementConverter(new JsonToAndroidElementConverter(this));
5254
}
5355

56+
public AndroidDriver(AppiumDriverLocalService service, Capabilities desiredCapabilities) {
57+
super(service, substituteMobilePlatform(desiredCapabilities,
58+
ANDROID_PLATFORM));
59+
this.setElementConverter(new JsonToAndroidElementConverter(this));
60+
}
61+
62+
public AndroidDriver(AppiumServiceBuilder builder, Capabilities desiredCapabilities) {
63+
super(builder, substituteMobilePlatform(desiredCapabilities,
64+
ANDROID_PLATFORM));
65+
this.setElementConverter(new JsonToAndroidElementConverter(this));
66+
}
67+
68+
public AndroidDriver(Capabilities desiredCapabilities) {
69+
super(substituteMobilePlatform(desiredCapabilities,
70+
ANDROID_PLATFORM));
71+
this.setElementConverter(new JsonToAndroidElementConverter(this));
72+
}
73+
5474
/**
5575
* Scroll forward to the element which has a description or name which contains the input text.
5676
* The scrolling is performed on the first scrollView present on the UI

src/main/java/io/appium/java_client/ios/IOSDriver.java

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import io.appium.java_client.ios.internal.JsonToIOSElementConverter;
1010
import io.appium.java_client.remote.MobilePlatform;
1111

12+
import io.appium.java_client.service.local.AppiumDriverLocalService;
13+
import io.appium.java_client.service.local.AppiumServiceBuilder;
1214
import org.openqa.selenium.Capabilities;
1315
import org.openqa.selenium.WebElement;
1416

@@ -36,15 +38,33 @@ public IOSDriver(URL remoteAddress, Capabilities desiredCapabilities) {
3638
super(remoteAddress, substituteMobilePlatform(desiredCapabilities,
3739
IOS_PLATFORM));
3840
this.setElementConverter(new JsonToIOSElementConverter(this));
39-
}
41+
}
42+
43+
public IOSDriver(AppiumDriverLocalService service, Capabilities desiredCapabilities) {
44+
super(service, substituteMobilePlatform(desiredCapabilities,
45+
IOS_PLATFORM));
46+
this.setElementConverter(new JsonToIOSElementConverter(this));
47+
}
48+
49+
public IOSDriver(AppiumServiceBuilder builder, Capabilities desiredCapabilities) {
50+
super(builder, substituteMobilePlatform(desiredCapabilities,
51+
IOS_PLATFORM));
52+
this.setElementConverter(new JsonToIOSElementConverter(this));
53+
}
54+
55+
public IOSDriver(Capabilities desiredCapabilities) {
56+
super(substituteMobilePlatform(desiredCapabilities,
57+
IOS_PLATFORM));
58+
this.setElementConverter(new JsonToIOSElementConverter(this));
59+
}
4060

4161
/**
4262
* Scroll to the element whose 'text' attribute contains the input text.
4363
* This scrolling happens within the first UIATableView on the UI. Use the method on IOSElement to scroll from a different ScrollView.
4464
* @param text input text contained in text attribute
4565
*/
4666
@SuppressWarnings("unchecked")
47-
@Override
67+
@Override
4868
public RequiredElementType scrollTo(String text) {
4969
return (RequiredElementType) ((ScrollsTo<?>)
5070
findElementByClassName("UIATableView")).scrollTo(text);
@@ -56,7 +76,7 @@ public RequiredElementType scrollTo(String text) {
5676
* @param text input text to match
5777
*/
5878
@SuppressWarnings("unchecked")
59-
@Override
79+
@Override
6080
public RequiredElementType scrollToExact(String text) {
6181
return (RequiredElementType) ((ScrollsTo<?>)
6282
findElementByClassName("UIATableView")).scrollToExact(text);
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package io.appium.java_client.remote;
2+
3+
4+
import com.google.common.base.Throwables;
5+
import org.openqa.selenium.WebDriverException;
6+
import org.openqa.selenium.remote.*;
7+
import org.openqa.selenium.remote.http.HttpClient;
8+
import org.openqa.selenium.remote.service.DriverService;
9+
10+
import java.io.IOException;
11+
import java.net.ConnectException;
12+
import java.net.URL;
13+
import java.util.Map;
14+
15+
public class AppiumCommandExecutor extends HttpCommandExecutor{
16+
17+
private final DriverService service;
18+
19+
public AppiumCommandExecutor(Map<String, CommandInfo> additionalCommands, URL addressOfRemoteServer) {
20+
super(additionalCommands, addressOfRemoteServer);
21+
service = null;
22+
}
23+
24+
public AppiumCommandExecutor(Map<String, CommandInfo> additionalCommands, DriverService service) {
25+
super(additionalCommands, service.getUrl());
26+
this.service = service;
27+
}
28+
29+
@Override
30+
public Response execute(Command command) throws IOException, WebDriverException {
31+
if (DriverCommand.NEW_SESSION.equals(command.getName()) && service != null) {
32+
service.start();
33+
}
34+
35+
try {
36+
return super.execute(command);
37+
} catch (Throwable t) {
38+
Throwable rootCause = Throwables.getRootCause(t);
39+
if (rootCause instanceof ConnectException &&
40+
rootCause.getMessage().contains("Connection refused") && service != null){
41+
if (service.isRunning())
42+
throw new WebDriverException("The session is closed!", t);
43+
44+
if (!service.isRunning())
45+
throw new WebDriverException("The appium server has accidentally died!", t);
46+
}
47+
Throwables.propagateIfPossible(t);
48+
throw new WebDriverException(t);
49+
} finally {
50+
if (DriverCommand.QUIT.equals(command.getName()) && service != null) {
51+
service.stop();
52+
}
53+
}
54+
}
55+
56+
}

0 commit comments

Comments
 (0)