Вопросы по appium и тестированию Android приложений.

Решил перейти на uiautomator2, появилась проблема, что тесты не падают со статусом failure и не переходят на следующий тест если драйвер не находит элемент или тест пошел не по плану.

Запускаю из мавен плагина test

Лог:
[debug] [W3C (f464825f)] Calling AppiumDriver.findElements() with args: [“id”,“junk_button”,“f464825f-d262-488d-abfa-c58efb894faf”]
[debug] [BaseDriver] Valid locator strategies for this request: xpath, id, class name, accessibility id, -android uiautomator
[debug] [BaseDriver] Waiting up to 0 ms for condition
[debug] [JSONWP Proxy] Matched ‘/elements’ to command name ‘findElements’
[debug] [JSONWP Proxy] Proxying [POST /elements] to [POST http://localhost:8201/wd/hub/session/ea8fb676-04bc-4e31-af75-6596c562a078/elements] with body: {“strategy”:“id”,“selector”:“junk_button”,“context”:“”,“multiple”:true}
[BaseDriver] Shutting down because we waited 60 seconds for a command
[debug] [UiAutomator2] Deleting UiAutomator2 session
[debug] [UiAutomator2] Deleting UiAutomator2 server session
[debug] [JSONWP Proxy] Matched ‘/’ to command name ‘deleteSession’
[debug] [JSONWP Proxy] Proxying [DELETE /] to [DELETE http://localhost:8200/wd/hub/session/0394954d-6e47-42eb-b27e-c5dba439260d] with no body
[Appium] Closing session, cause was ‘New Command Timeout of 60 seconds expired. Try customizing the timeout using the ‘newCommandTimeout’ desired capability’
[Appium] Removing session ba1b9eef-1b54-4ce7-bd9a-d9bc15dab568 from our master session list
[debug] [JSONWP Proxy] Got response with status 200: “{"sessionId":"0394954d-6e47-42eb-b27e-c5dba439260d","status":0,"value":"Session deleted"}”
[debug] [ADB] Running ‘/home/trash/Android/Sdk/platform-tools/adb -P 5037 -s 847faa24 shell am force-stop com.cache.clean.boost.master’
[debug] [UiAutomator2] [UIAutomator2] io.appium.uiautomator2.server.test.AppiumUiAutomator2Server:.
[debug] [UiAutomator2] [UIAutomator2] Time: 36.042
[debug] [UiAutomator2] [UIAutomator2] OK (1 test)
[JSONWP Proxy] Got an unexpected response: {“code”:“ECONNRESET”}
[debug] [W3C (f464825f)] Encountered internal error running command: UnknownError: An unknown server-side error occurred while processing the command. Original error: Could not proxy command to remote server. Original error: Error: socket hang up
[debug] [W3C (f464825f)] at JWProxy.command (/home/trash/node_modules/appium-base-driver/lib/jsonwp-proxy/proxy.js:236:13)
[HTTP] ← POST /wd/hub/session/f464825f-d262-488d-abfa-c58efb894faf/elements 500 8653 ms - 507
[HTTP]
Dec 08, 2018 4:04:20 PM org.openqa.selenium.support.ui.ExpectedConditions findElement
WARNING: WebDriverException thrown by findElement(By.id: junk_button)
org.openqa.selenium.WebDriverException: An unknown server-side error occurred while processing the command. Original error: Could not proxy command to remote server. Original error: Error: socket hang up
Build info: version: ‘3.12.0’, revision: ‘7c6e0b3’, time: ‘2018-05-08T14:04:26.12Z’
System info: host: ‘trash’, ip: ‘127.0.1.1’, os.name: ‘Linux’, os.arch: ‘amd64’, os.version: ‘4.15.0-42-generic’, java.version: ‘1.8.0_191’
Driver info: io.appium.java_client.android.AndroidDriver
Capabilities {app: /home/trash/Downloads/Great…, appPackage: com.cache.clean.boost.master, appWaitActivity: com.boost.clean.speed.great…, automationName: uiautomator2, databaseEnabled: false, desired: {app: /home/trash/Downloads/Great…, appPackage: com.cache.clean.boost.master, appWaitActivity: com.boost.clean.speed.great…, automationName: uiautomator2, deviceId: 847faa24, deviceName: testDevice, fullReset: false, noReset: true, platformName: android, platformVersion: 7.1.1}, deviceApiLevel: 25, deviceId: 847faa24, deviceManufacturer: samsung, deviceModel: SM-J510H, deviceName: 847faa24, deviceScreenDensity: 320, deviceScreenSize: 720x1280, deviceUDID: 847faa24, fullReset: false, javascriptEnabled: true, locationContextEnabled: false, networkConnectionEnabled: true, noReset: true, pixelRatio: 2, platform: LINUX, platformName: Android, platformVersion: 7.1.1, statBarHeight: 48, takesScreenshot: true, viewportRect: {height: 1232, left: 0, top: 48, width: 720}, warnings: {}, webStorageEnabled: false}
Session ID: f464825f-d262-488d-abfa-c58efb894faf
*** Element info: {Using=id, value=junk_button}
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.openqa.selenium.remote.http.W3CHttpResponseCodec.createException(W3CHttpResponseCodec.java:187)
at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:122)
at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:49)
at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:158)
at io.appium.java_client.remote.AppiumCommandExecutor.execute(AppiumCommandExecutor.java:231)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:543)
at io.appium.java_client.DefaultGenericMobileDriver.execute(DefaultGenericMobileDriver.java:42)
at io.appium.java_client.AppiumDriver.execute(AppiumDriver.java:1)
at io.appium.java_client.android.AndroidDriver.execute(AndroidDriver.java:1)
at org.openqa.selenium.remote.RemoteWebDriver.findElements(RemoteWebDriver.java:344)
at io.appium.java_client.DefaultGenericMobileDriver.findElements(DefaultGenericMobileDriver.java:54)
at io.appium.java_client.AppiumDriver.findElements(AppiumDriver.java:152)
at org.openqa.selenium.remote.RemoteWebDriver.findElementsById(RemoteWebDriver.java:367)
at io.appium.java_client.DefaultGenericMobileDriver.findElementsById(DefaultGenericMobileDriver.java:66)
at io.appium.java_client.AppiumDriver.findElementsById(AppiumDriver.java:156)
at org.openqa.selenium.By$ById.findElements(By.java:180)
at org.openqa.selenium.remote.RemoteWebDriver.findElements(RemoteWebDriver.java:305)
at io.appium.java_client.DefaultGenericMobileDriver.findElements(DefaultGenericMobileDriver.java:50)
at io.appium.java_client.AppiumDriver.findElements(AppiumDriver.java:148)
at org.openqa.selenium.support.ui.ExpectedConditions.findElement(ExpectedConditions.java:895)
at org.openqa.selenium.support.ui.ExpectedConditions.access$000(ExpectedConditions.java:44)
at org.openqa.selenium.support.ui.ExpectedConditions$6.apply(ExpectedConditions.java:183)
at org.openqa.selenium.support.ui.ExpectedConditions$6.apply(ExpectedConditions.java:180)
at org.openqa.selenium.support.ui.FluentWait.until(FluentWait.java:248)
at Finder.byId(Finder.java:12)
at GreaterCleaner.junkFilesTest(GreaterCleaner.java:49)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:124)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:583)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:719)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:989)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:109)
at org.testng.TestRunner.privateRun(TestRunner.java:648)
at org.testng.TestRunner.run(TestRunner.java:505)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:455)
at org.testng.SuiteRunner.access$000(SuiteRunner.java:40)
at org.testng.SuiteRunner$SuiteWorker.run(SuiteRunner.java:489)
at org.testng.internal.thread.ThreadUtil$1.call(ThreadUtil.java:52)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

[HTTP] → GET /wd/hub/session/f464825f-d262-488d-abfa-c58efb894faf/screenshot
[HTTP] {}
[debug] [W3C (f464825f)] Calling AppiumDriver.getScreenshot() with args: [“f464825f-d262-488d-abfa-c58efb894faf”]
[debug] [JSONWP Proxy] Matched ‘/screenshot’ to command name ‘getScreenshot’
[debug] [JSONWP Proxy] Proxying [GET /screenshot] to [GET http://localhost:8201/wd/hub/session/ea8fb676-04bc-4e31-af75-6596c562a078/screenshot] with no body
[JSONWP Proxy] Got an unexpected response: {“errno”:“ECONNRESET”,“code”:“ECONNRESET”,“syscall”:“read”}
[debug] [W3C (f464825f)] Encountered internal error running command: UnknownError: An unknown server-side error occurred while processing the command. Original error: Could not proxy command to remote server. Original error: Error: read ECONNRESET
[debug] [W3C (f464825f)] at JWProxy.command (/home/trash/node_modules/appium-base-driver/lib/jsonwp-proxy/proxy.js:236:13)
[HTTP] ← GET /wd/hub/session/f464825f-d262-488d-abfa-c58efb894faf/screenshot 500 20 ms - 509
[HTTP]
[HTTP] → GET /wd/hub/session/f464825f-d262-488d-abfa-c58efb894faf/screenshot
[HTTP] {}
[debug] [W3C (f464825f)] Calling AppiumDriver.getScreenshot() with args: [“f464825f-d262-488d-abfa-c58efb894faf”]
[debug] [JSONWP Proxy] Matched ‘/screenshot’ to command name ‘getScreenshot’
[debug] [JSONWP Proxy] Proxying [GET /screenshot] to [GET http://localhost:8201/wd/hub/session/ea8fb676-04bc-4e31-af75-6596c562a078/screenshot] with no body
[JSONWP Proxy] Got an unexpected response: {“errno”:“ECONNRESET”,“code”:“ECONNRESET”,“syscall”:“read”}
[debug] [W3C (f464825f)] Encountered internal error running command: UnknownError: An unknown server-side error occurred while processing the command. Original error: Could not proxy command to remote server. Original error: Error: read ECONNRESET
[debug] [W3C (f464825f)] at JWProxy.command (/home/trash/node_modules/appium-base-driver/lib/jsonwp-proxy/proxy.js:236:13)
[HTTP] ← GET /wd/hub/session/f464825f-d262-488d-abfa-c58efb894faf/screenshot 500 10 ms - 509
[HTTP]
[HTTP] → DELETE /wd/hub/session/f464825f-d262-488d-abfa-c58efb894faf
[HTTP] {}
[debug] [W3C (f464825f)] Calling AppiumDriver.deleteSession() with args: [“f464825f-d262-488d-abfa-c58efb894faf”]
[debug] [BaseDriver] Event ‘quitSessionRequested’ logged at 1544277860562 (16:04:20 GMT+0200 (Eastern European Standard Time))
[Appium] Removing session f464825f-d262-488d-abfa-c58efb894faf from our master session list
[debug] [UiAutomator2] Deleting UiAutomator2 session
[debug] [UiAutomator2] Deleting UiAutomator2 server session
[debug] [JSONWP Proxy] Matched ‘/’ to command name ‘deleteSession’
[debug] [JSONWP Proxy] Proxying [DELETE /] to [DELETE http://localhost:8201/wd/hub/session/ea8fb676-04bc-4e31-af75-6596c562a078] with no body
[JSONWP Proxy] Got an unexpected response: {“errno”:“ECONNRESET”,“code”:“ECONNRESET”,“syscall”:“read”}
[UiAutomator2] Did not get confirmation UiAutomator2 deleteSession worked; Error was: UnknownError: An unknown server-side error occurred while processing the command. Original error: Could not proxy command to remote server. Original error: Error: read ECONNRESET
[debug] [ADB] Running ‘/home/trash/Android/Sdk/platform-tools/adb -P 5037 -s 847faa24 shell am force-stop com.cache.clean.boost.master’
[debug] [Logcat] Stopping logcat capture
[debug] [ADB] Removing forwarded port socket connection: 8200
[debug] [ADB] Running ‘/home/trash/Android/Sdk/platform-tools/adb -P 5037 -s 847faa24 forward --remove tcp:8200’
[debug] [ADB] Device API level: 25
[debug] [Logcat] Stopping logcat capture
[debug] [ADB] Removing forwarded port socket connection: 8201
[debug] [ADB] Running ‘/home/trash/Android/Sdk/platform-tools/adb -P 5037 -s 847faa24 forward --remove tcp:8201’
[debug] [ADB] Device API level: 25
[debug] [BaseDriver] Event ‘quitSessionFinished’ logged at 1544277862484 (16:04:22 GMT+0200 (Eastern European Standard Time))
[debug] [W3C (f464825f)] Received response: null
[debug] [W3C (f464825f)] But deleting session, so not returning
[debug] [W3C (f464825f)] Responding to client with driver.deleteSession() result: null
[HTTP] ← DELETE /wd/hub/session/f464825f-d262-488d-abfa-c58efb894faf 200 1931 ms - 14
[HTTP]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 129.885 s - in TestSuite
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 02:12 min
[INFO] Finished at: 2018-12-08T16:04:25+02:00
[INFO] Final Memory: 22M/252M
[INFO] ------------------------------------------------------------------------

Process finished with exit code 0

Система Ubuntu
.nvm/versions/node/v11.4.0
Appium v1.10.0

Весь код в репе.
https://github.com/ddwmz/someTest/tree/master/comtestframe

у меня аппиум крашится регулярно с такой ошибкой, я создал тикет uncaughtException: Android bootstrap socket crashed: Error: read ECONNRESET · Issue #11606 · appium/appium · GitHub По их словам причина на моей стороне - проблема с окруженеием, но такие же ошибки возникают и других пользователей. Ошибка воспроизводится на резличных версиях аппума и от uiautomator2 я думаю что не зависит. Возможно глючит нода, после переустановки ошибка стала появлтся реже

1 лайк

Да, я гуглил ошибку и этот Ваш пост видел. У меня вообще все ок было на 1 автоматоре, со 2м вот постоянно проблемы вылазят, так его и не прикрутил, что бы он адекватно работал.

Вопрос по настройкам самого Appium Server - у вас все порты дефолтовые или нет?
У меня схожая проблема, возникала при паралелизации (использование не дефолтовых портов для каждого девайса), и была решена перенаправлением порта (withArgument(AndroidServerFlag.BOOTSTRAP_PORT_NUMBER,device.getDriverPort())) на стороне сервера, переопредилением порта на клиенте (сapabilities.setCapability(AndroidMobileCapabilityType.SYSTEM_PORT,device.getDriverPort())).
По умолчании должен использоватся порт 8200 - What is the strategy choosing port 8201 or 8200 · Issue #11345 · appium/appium · GitHub.

Да как раз таки парралельно юзаю, и под каждый смарт динамически поднимается сервер и порты соотв. не дефолтные, там условие, что любой свободный.

.usingAnyFreePort() - использую.

Что то не понял device.getDriverPort() это Вы откуда получаете?
Можно весь BeforeMethod увидеть?

Сори, ето пример, как есть, с моего фреймворка. device - инстанс информации про девайс полученая от самописного сервиса mobile local lab. При паралельном запуске .usingAnyFreePort() никак нельзя (как минимум у меня не вышло с UIAutomator2).
Если просто, то при поднятии нескольких Appium Server нужно каждому выделить как минимум 2 уникальных порта (если hybrid application - то 3). Для UIautomator создание Appium Server будет выглядеть следующим образом:
AppiumServiceBuilder appiumServiceBuilder = new AppiumServiceBuilder() ... .withIPAddress(23234) ... .withArgument(AndroidServerFlag.CHROME_DRIVER_PORT, 23235) .withArgument(AndroidServerFlag.BOOTSTRAP_PORT_NUMBER, 23236 ...) где 23234, 23235, 23236 - динамически присвоеные порты для каждого инстанса сервера/девайса.
В UIautomator2 на стороне клиента, в капабилити, нужно указать AndroidMobileCapabilityType.SYSTEM_PORT. Он должен быть тот же что и BOOTSTRAP_PORT_NUMBER, тоесть если брати пример выше - capabilities.setCapability(AndroidMobileCapabilityType.SYSTEM_PORT, 23236);
Если более развернуто, то я бы порекомендовал почитати статью Jonathan Lipps про паралелизацию тут: Appium Pro: Running Multiple Appium Tests in Parallel

1 лайк

Что-то я наверное не допонимаю.
Я использую в базовом класе теста

public class BaseTest {

public AppiumDriver driver;
public AppiumDriverLocalService appiumDriverLocalService;

public AppiumDriver getDriver(){
return driver;
}

@Parameters({“platformVersion”,“deviceId”, “appPackage”, “appWaitActivity”})
@BeforeMethod
public void setup(String androidVersion, String udid, String appPackage, String appWaitActivity)
throws MalformedURLException, InterruptedException{

String apkFile = “GreaterCleaner.apk”;
File file = new File(“/home/trash/Downloads”, apkFile);

DesiredCapabilities capabilities = new DesiredCapabilities();

//capabilities.setCapability(“automationName”, “uiautomator2”);
capabilities.setCapability(“deviceName”, “testDevice”);
capabilities.setCapability(“platformName”, “Android”);
capabilities.setCapability(“platformVersion”, androidVersion);
capabilities.setCapability(“deviceId”, udid);
capabilities.setCapability(“noReset”, “true”);
capabilities.setCapability(“fullReset”, “false”);
//capabilities.setCapability(“dontStopAppOnReset”, “false”);
capabilities.setCapability(“app”, file.getAbsolutePath());
capabilities.setCapability(“appPackage”, appPackage);
capabilities.setCapability(“appWaitActivity”, appWaitActivity);
//capabilities.setCapability(AndroidMobileCapabilityType.SYSTEM_PORT, device.getDriverPort());

appiumDriverLocalService = AppiumDriverLocalService
.buildService(new AppiumServiceBuilder()
.usingDriverExecutable(new File(“/home/trash/.nvm/versions/node/v11.4.0/bin/node”))
.withAppiumJS(new File(“/home/trash/node_modules/appium/build/lib/main.js”))
.usingAnyFreePort()
.withArgument(GeneralServerFlag.SESSION_OVERRIDE)
.withArgument(GeneralServerFlag.LOG_LEVEL, “debug”));

appiumDriverLocalService.start();
Thread.sleep(10000);

String server_URL = appiumDriverLocalService.getUrl().toString();
System.out.println(server_URL);

driver = new AndroidDriver(new URL(server_URL), capabilities);
//driver.manage().timeouts().implicitlyWait(25, TimeUnit.SECONDS);
Thread.sleep(10000);

}

Перед каждой аннотацией @test у меня поднимается новый сервер с этими параметрами. На первом все отрабатывает отлично. Какой-то путаницы с серверами вроде нет, каждый тест поднимается на новом сервере. А, и это я юзал только для одного девайса и крашится все с одним девайсом, про два или три речи и не идет. Вот с первым на 10 девайсах все отрабатывало идеально, я не разу за все время не ловил подобной ерунды.

У меня все сложнее - скоро планирую отправить в open source. Здесь упрощенная версия на примере твоего кода:

@Parameters({“platformVersion”,“deviceId”, “appPackage”, “appWaitActivity”})
@BeforeMethod
public void setup(String androidVersion, String udid, String appPackage, String appWaitActivity)
throws MalformedURLException, InterruptedException{
...
int serverPort = getOpenPort();
int webPort = getOpenPort();
int systemPort = getOpenPort();
...
capabilities.setCapability(AndroidMobileCapabilityType.SYSTEM_PORT, systemPort);
...
appiumDriverLocalService = AppiumDriverLocalService
                    .buildService(new AppiumServiceBuilder()
                    .usingDriverExecutable(new File("/home/trash/.nvm/versions/node/v11.4.0/bin/node"))
                    .withAppiumJS(new File("/home/trash/node_modules/appium/build/lib/main.js"))
                    .usingPort(serverPort)
                    .withArgument(AndroidServerFlag.CHROME_DRIVER_PORT, webPort)
                    .withArgument(AndroidServerFlag.BOOTSTRAP_PORT_NUMBER, systemPort)
                    .withArgument(GeneralServerFlag.SESSION_OVERRIDE)
                    .withArgument(GeneralServerFlag.LOG_LEVEL, "debug"));
}
private static int getOpenPort() {
        ServerSocket socket;
        int port = 0;
        try {
            socket = new ServerSocket(0);

            socket.setReuseAddress(true);
            port = socket.getLocalPort();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return port;
}
1 лайк

Да, вчера уже вечером разобрался с портами о которых Вы говорили, прокинул их, результата не дало, попробовал даже Ваш код заюзать, но результатов не дало. Все также падает с ошибкой ECONNRESET после того как не находит элемент.

Спасибо, похоже все заработало.

Чет я поковырялся добавил пару аннотаций для TestNG, переустановил аппиум, посбрасывал смарты, похоже что работает, ну по крайней мере он перестал валится после проваленного теста. Спасибо!!!

1 лайк