Appium: Android Virtual Device, Original error: Condition unmet after 60159 ms и костыль

By | 12/06/2018
 

Проблема: UI-тесты, запускаемые с помощью Appium, падают.

Задача: найти причину, и пофиксить.

Что бы воспроизвести проблему –  установили Android Studio на рабочую машинку и создали устройство. Теперь – можно настроить “тестовый тест”, а потом попробовать запустить наши реальные тесты.

Забегая наперёд – проблема была найдена, но решения не нашёл, потому пришлось костылить в Jenkins-джобе.

Сама проблема на билд-агенте выглядит так:

[ERROR] setUp(workoutme.subscriptions.SubscriptionTests) Time elapsed: 60.857 s <<< FAILURE!
org.openqa.selenium.WebDriverException:
It is impossible to create a new session because ‘createSession’ which takes HttpClient, InputStream and long was not found or it is not accessible
Build info: version: ‘3.13.0’, revision: ‘2f0d292’, time: ‘2018-06-25T15:24:21.231Z’
System info: host: ‘project-ci’, ip: ‘127.0.1.1’, os.name: ‘Linux’, os.arch: ‘amd64’, os.version: ‘4.15.0-39-generic’, java.version: ‘1.8.0_181’
Driver info: driver.version: AndroidDriver
Caused by: java.lang.reflect.InvocationTargetException
Caused by: org.openqa.selenium.WebDriverException:
An unknown server-side error occurred while processing the command. Original error: Error getting AVD with retry. Original error: Condition unmet after 60159 ms. Timing out.
Build info: version: ‘3.13.0’, revision: ‘2f0d292’, time: ‘2018-06-25T15:24:21.231Z’
System info: host: ‘project-ci’, ip: ‘127.0.1.1’, os.name: ‘Linux’, os.arch: ‘amd64’, os.version: ‘4.15.0-39-generic’, java.version: ‘1.8.0_181’
Driver info: driver.version: AndroidDriver
remote stacktrace: UnknownError: An unknown server-side error occurred while processing the command. Original error: Error getting AVD with retry. Original error: Condition unmet after 60159 ms. Timing out.

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

К Appium будут подключаться ноды Selenium-а (в данном случае – AVD-устройства), на которых Appium будет выполнять тесты.

Запуск тестов локально

Запуск Selenuim

Загружаем файл со страницы https://www.seleniumhq.org/download/.

Документация по запуску Selenium-хаба – тут>>>.

Запускаем его:

java -jar selenium-server-standalone-3.141.59.jar -role hub
12:43:48.190 INFO [GridLauncherV3.parse] - Selenium server version: 3.141.59, revision: e82be7d358
12:43:48.273 INFO [GridLauncherV3.lambda$buildLaunchers$5] - Launching Selenium Grid hub on port 4444
2018-11-21 12:43:48.739:INFO::main: Logging initialized @892ms to org.seleniumhq.jetty9.util.log.StdErrLog
12:43:48.890 INFO [Hub.start] - Selenium Grid hub is up and running
12:43:48.890 INFO [Hub.start] - Nodes should register to http://172.18.0.1:4444/grid/register/
12:43:48.890 INFO [Hub.start] - Clients should connect to http://172.18.0.1:4444/wd/hub

Запуск Appium

Устанавливаем его:

npm install appium

Проверяем:

~/node_modules/.bin/appium --help
usage: /home/setevoy/node_modules/.bin/appium [-h] [-v] [--shell] [--reboot]
[--ipa IPA] [-a ADDRESS]
[-p PORT] [-ca CALLBACKADDRESS]
[-cp CALLBACKPORT]
...

Создаём файл настроек для ноды, пример есть тут>>>:

{ 
  "capabilities":
      [
        {
         "deviceName": "Android Emulator",
          "version":"8.0",
          "platform":"Android"
        }
      ],
  "configuration":
  {
    "cleanUpCycle":3000,
    "timeout":30000,
    "proxy": "org.openqa.grid.selenium.proxy.DefaultRemoteProxy",
    "url":"http://:172.18.0.1:4625/wd/hub",
    "host": "172.18.0.1",
    "port": 4625,
    "maxSession": 2,
    "register": true,
    "registerCycle": 5000,
    "hubPort": 4444,
    "hubHost": "172.18.0.1"
  }
}

Запускаем Appium:

~/node_modules/.bin/appium -p 4625 --nodeconfig /home/setevoy/Temp/nexus_5_node.json
[Appium] Welcome to Appium v1.9.1
[Appium] Non-default server args:
[Appium]   port: 4625
[Appium]   nodeconfig: /home/setevoy/Temp/nexus_5_node.json
[debug] [Appium] Starting auto register thread for grid. Will try to register every 5000 ms.
[Appium] Appium REST http interface listener started on 0.0.0.0:4625
[debug] [Appium] Appium successfully registered with the grid on http://172.18.0.1:4444
[HTTP] --> GET /wd/hub/status
[HTTP] {}
[debug] [GENERIC] Calling AppiumDriver.getStatus() with args: []
[debug] [GENERIC] Responding to client with driver.getStatus() result: {"build":{"version":"1.9.1","git-sha":"f9ee7d068e14f10729f88ebd85db802c2e8ac21a","built":"2018-09-20T18:14:29Z"}}
[HTTP] <-- GET /wd/hub/status 200 5
...

Проверяем лог Selenuim:

...
12:57:58.176 WARN [BaseRemoteProxy.<init>] - Max instance not specified. Using default = 1 instance
12:57:58.182 INFO [DefaultGridRegistry.add] - Registered a node http://172.18.0.1:4625
...

Нода подключилась – хорошо, всё работает, можно тестить.

Тестирование с Appium

Пробуем запустить наши тесты, что бы воспроизвести ошибку.

Вообще задача – воспроизвести ошибку:

[INFO] Running TestSuite

An unknown server-side error occurred while processing the command. Original error: Error getting AVD with retry. Original error: Condition unmet after 60152 ms. Timing out.

Устройство и подключение к нему описаны в pom.xml тестов:

...
        <profile>
            <id>linux-emulator-8.0</id>
            <properties>
                <hub.url>http://0.0.0.0:4723/wd/hub</hub.url>
                <device.name>Android Emulator</device.name>
                <avd>Nexus_5X_API_26</avd>
                <platform.name>Android</platform.name>
                <platform.version>8.0</platform.version>
                <auto.grant.permissions>true</auto.grant.permissions>
                <full.reset>true</full.reset>
                <no.reset>false</no.reset>
                <app.path>/home/project/project/project.apk</app.path>
                <app.name>com.gen.workoutme</app.name>
                <screenshot.path>
                    ${project.basedir}/../screenShots/${platform.name}/${platform.version}/${device.name}/
                </screenshot.path>
                <automation.name>UiAutomator2</automation.name>
            </properties>
        </profile>
...

Задаём $ANDROID_HOME, и добавляем tools и platform-tools в $PATH:

...
export ANDROID_HOME=/home/setevoy/Android/Sdk
export PATH=$PATH:$GOPATH/bin:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools
...

Запускаем Appium на порту 4723, как указано в настройках ноды, в файле pom.xml:

~/node_modules/.bin/appium -p 4723 > /home/username/appium.log

Для дебага – перенаправляем вывод в  /home/username/appium.log.

И запускаем тесты с профилем linux-emulator-8.0:

Окей – локально, на моём ноутбуке, устройство запускается, всё работает.

А в чём проблема на билд-агенте? :-/

Запуск на билд-агенте

Запуск вручную

Попробуем подебажить.

Проверяем само устройство:

/android/Android/sdk/tools/bin/avdmanager list avd
...
Available Android Virtual Devices:
Name: Nexus_5X_API_26
Device: Nexus 5X (Google)
Path: /home/project/.android/avd/Nexus_5X_API_26.avd
Target: Google Play (Google Inc.)
Based on: Android 8.0 (Oreo) Tag/ABI: google_apis_playstore/x86
Skin: 1080x1920
Sdcard: 100 MB

И с помощью эмулятора:

emulator -list-avds
Nexus_5X_API_26
test

Пробуем его запустить на билд-агенте (т.к. запускаю по SSH – то с опцией -no-window):

/android/Android/sdk/tools/emulator -avd Nexus_5X_API_26 -no-window
I/O warning : failed to load external entity "/home/project/.AndroidStudio3.2/config/options/updates.xml"
Couldn't statvfs() path: No such file or directory
ERROR: Unable to access '/home/project/.emulator_console_auth_token': emulator console will not work
I/O warning : failed to load external entity "/home/project/.AndroidStudio3.2/config/options/updates.xml"
Your emulator is out of date, please update by launching Android Studio:
- Start Android Studio
- Select menu "Tools > Android > SDK Manager"
- Click "SDK Tools" tab
- Check "Android Emulator" checkbox
- Click "OK"

Окей, он есть, запускается.

Запускаем тесты:

mvn clean -Dmaven.test.failure.ignore=false test -P linux-emulator-8.0
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building project-android-auto-tests 1.0
[INFO] ------------------------------------------------------------------------
...
[INFO] Running TestSuite
...
... TestNG 6.14.3 by Cédric Beust (cedric@beust.com)
...
Nov 21, 2018 6:18:38 PM io.appium.java_client.remote.AppiumCommandExecutor$1 lambda$0
INFO: Detected dialect: W3C
...

И в логе Appium:

...
[debug] [ADB] Trying to find Nexus_5X_API_26 emulator
[debug] [ADB] Getting connected emulators
[debug] [ADB] Getting connected devices...
[debug] [ADB] 1 device(s) connected
[debug] [ADB] 1 emulator(s) connected
...

Устройство видно, Appium его находит.

Запуск из Jenkins

Значит – проблема в том, что при запуске автотестов из Jenkins – Appium не может запустить emulator, при том, что вызов avdmanager list avd и emulator -list-avds список устройств возвращает нормально:

[Pipeline] sh
+ avdmanager list avd
...
Android Virtual Devices:
Name: Nexus_5X_API_26
Device: Nexus 5X (Google)
Path: /home/project/.android/avd/Nexus_5X_API_26.avd
Target: Google Play (Google Inc.)
Based on: Android 8.0 (Oreo) Tag/ABI: google_apis_playstore/x86
Skin: 1080x1920
Sdcard: 100 MB
---------
Name: test
Path: /home/project/.android/avd/test.avd
Target: Google APIs (Google Inc.)
Based on: Android 7.1.1 (Nougat) Tag/ABI: google_apis/x86
[Pipeline] sh
+ emulator -list-avds
Nexus_5X_API_26
test

Осталось выяснить – почему Appium не может запустить девайс через эмулятор…

Ещё раз запускаем тесты без запущенного эмулятора, и смотрим лог Appium:

...
[debug] [ADB] Emulator Nexus_5X_API_26 not running
[ADB] [AVD OUTPUT] Fatal: QXcbConnection: Could not connect to display  ((null):0, (null))
[ADB] [AVD OUTPUT] INFO: QtLogger.cpp:66: Fatal: QXcbConnection: Could not connect to display  ((null):0, (null))
[ADB] Emulator avd Nexus_5X_API_26 exited with code null, signal SIGABRT
...

А из-за чего появляется:

QXcbConnection: Could not connect to display ((null):0, (null))

?

Вот, судя по всему – она и является корнем проблемы.

Т.е. проблема возникает из-за того, что при запуске тестов через билд-агент, который установлен на Ubuntu, к которой подключен монитор, и на которой вручную тесты и эмулятор запускаются – билд-агент и/или Appium не могут увидеть дисплей.

Решения так и не нашлось – не помогло ни принудительное указание $DISPLAY в переменных билд-агента, ни запуск эмулятора с опцией isHeadless для Appium в pom.xml:

...
<isHeadless>true</isHeadless>
...

Добавллял avgArgs:

...
<avgArgs>-no-window</avgArgs>

Не помогло.

Задавал вопрос на Stackoverflow – но тоже без результата.

Костыль

Пока решения так и и не нашёл – применил костыль: запускаем девайс “вручную” перед запуском Appium.

Запуск тестов в Jenkins Pipeline джобе теперь выглядит так:

node('android') {
    stage('Run UI tests') {
        ws('/home/project/ANDROID_PROEJCT_QA') {
            sh '/usr/local/bin/appium -p 4723 --session-override > /home/project/appium.log &'
            sh "emulator -avd Nexus_5X_API_26 &> /home/project/emulator.log &"
            sleep 10
            git branch: 'master', poll: false, url: 'git@github.com:project-dev/ANDROID_PROJECT_QA.git'
            sh 'mvn clean -Dmaven.test.failure.ignore=false test -P linux-emulator-8.0'
            sh 'pkill -f appium || true'
            sh "adb -e emu kill"
        }
    }
}

В строке emulator -avd Nexus_5X_API_26 &> /home/project/emulator.log & – запускаем девайс, и в конце – adb -e emu kill – убиваем его.

Так оно пока и работает.