Статьи

Запуск тестов Android в Docker

В рамках проекта, которым я сейчас занимаюсь, моя команда пишет автоматические тесты для приложения с веб-интерфейсом, а также двух мобильных приложений, одного для Android и одного для iOS. В рамках проекта мы создали конвейер автоматизации тестирования, который запускает наши тесты для нашего приложения, чтобы гарантировать, что изменения, которые мы вносим, ​​не влияют на другие тесты. Да, мы тестируем наши тесты. Одна из проблем, с которой мы столкнулись, заключалась в том, чтобы убедиться, что наши тесты на Android и iOS все еще работают своевременно. Мы попробовали несколько вариантов, включая запуск тестов на SauceLabsно это потребляло ресурсы слишком быстро, чтобы быть эффективным из-за нескольких потоков конвейера (мы решили сохранить пропускную способность SauceLabs для нашего реального тестирования). Лучшее решение, которое мы в итоге нашли, работало лучше всего — создать собственные эмуляторы внутри контейнера Docker для тестирования.

Настройка

Если вы не знакомы с Docker, ознакомьтесь с некоторыми из наших замечательных постов. Это также отлично работает для тестирования. По сути, вместо того, чтобы раскручивать веб-приложение внутри контейнера, мы хотели раскрутить эмулятор Android, запустив наше приложение. Затем мы подключаемся к контейнеру так же, как привязанное физическое устройство, локальный эмулятор или что-то в облаке. Это сделало распараллеливание нашего тестирования невероятно дешевым (и быстрым). Все, что нам нужно было сделать, это запустить несколько Docker-контейнеров, а затем подключиться с помощью ADB к каждому из них.

Dockerfile

К сожалению, создание контейнера Docker не было простым. Нам был нужен контейнер Docker с установленным Android SDK, созданная виртуальная машина Android и Appium. Поскольку все локально работало нормально (Ubuntu), я решил начать с аналогичного базового образа (maven: 3.5.2-jdk-8). Затем мы установили ADK, настроили эмулятор и установили Appium. Наконец, мы справились с APK и тестовым набором. Вскоре мы обнаружили, что на базовом образе не настроен kvm, поэтому нам нужно было это включить. Не простая задача, которая, к сожалению, потребовала ручного шага. В результате я решил разделить это на два файла Docker: новый базовый с настройкой kvm и один со всеми установками.

DockerfileKVM

Этот Docker-контейнер был относительно простым, однако не совсем простым. Я собрал его один раз, загрузил в свой локальный репозиторий Docker, а затем построил поверх него контейнер Docker Android. Все, что я сделал, это установил kvm и вручную скопировал соответствующие модули lib. Dockerfile выглядел так:


FROM maven:3.5.2-jdk-8
#debian based

RUN apt-get update -qqy \
    && apt-get -qqy install libglu1 qemu-kvm libvirt-dev virtinst bridge-utils msr-tools kmod \
    && wget -q http://security.ubuntu.com/ubuntu/pool/main/c/cpu-checker/cpu-checker_0.7-0ubuntu7_amd64.deb \
    && dpkg -i cpu-checker_0.7-0ubuntu7_amd64.deb \
    && apt-get install -f \
    && kvm-ok

Оттуда я собрал и пометил файл Docker. Затем я запустил его, вошел в систему ( -it) и скопировал модули lib моей машины ( /lib/modules). Обратите внимание, что пробег может варьироваться в зависимости от ядра и версии вашего компьютера. Затем я поместил это изображение в мой локальный репозиторий Docker.

DockerfileAndroid

В этом контейнере Docker было намного больше шагов, но в конечном итоге он не был слишком сложным. Я установил свой Android SK, загрузил эмулятор, установил Appium, скопировал наш APK и тесты. Dockerfile выглядел так:


FROM kvm:maven-3.5.2-jdk-8#tag we gave to DockerfileKVM
# debian based

ENV UDIDS=""

#=====================
# Install android sdk
#=====================
ARG ANDROID_SDK_VERSION=4333796
ENV ANDROID_SDK_VERSION=$ANDROID_SDK_VERSION
ARG ANDROID_PLATFORM="android-25"
ARG BUILD_TOOLS="26.0.0"
ENV ANDROID_PLATFORM=$ANDROID_PLATFORM
ENV BUILD_TOOLS=$BUILD_TOOLS

# install adk
RUN mkdir -p /opt/adk \
    && wget -q https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_VERSION}.zip \
    && unzip sdk-tools-linux-${ANDROID_SDK_VERSION}.zip -d /opt/adk \
    && rm sdk-tools-linux-${ANDROID_SDK_VERSION}.zip \
    && wget -q https://dl.google.com/android/repository/platform-tools-latest-linux.zip \
    && unzip platform-tools-latest-linux.zip -d /opt/adk \
    && rm platform-tools-latest-linux.zip \
    && yes | /opt/adk/tools/bin/sdkmanager --licenses \
    && /opt/adk/tools/bin/sdkmanager "emulator" "build-tools;${BUILD_TOOLS}" "platforms;${ANDROID_PLATFORM}" "system-images;${ANDROID_PLATFORM};google_apis;armeabi-v7a" \
    && echo no | /opt/adk/tools/bin/avdmanager create avd -n "Android" -k "system-images;${ANDROID_PLATFORM};google_apis;armeabi-v7a" \
    && mkdir -p ${HOME}/.android/ \
    && ln -s /root/.android/avd ${HOME}/.android/avd \
    && ln -s /opt/adk/tools/emulator /usr/bin \
    && ln -s /opt/adk/platform-tools/adb /usr/bin
ENV ANDROID_HOME /opt/adk

#====================================
# Install latest nodejs, npm, appium
#====================================
ARG NODE_VERSION=v8.11.3
ENV NODE_VERSION=$NODE_VERSION
ARG APPIUM_VERSION=1.9.1
ENV APPIUM_VERSION=$APPIUM_VERSION

# install appium
RUN wget -q https://nodejs.org/dist/${NODE_VERSION}/node-${NODE_VERSION}-linux-x64.tar.xz \
    && tar -xJf node-${NODE_VERSION}-linux-x64.tar.xz -C /opt/ \
    && ln -s /opt/node-${NODE_VERSION}-linux-x64/bin/npm /usr/bin/ \
    && ln -s /opt/node-${NODE_VERSION}-linux-x64/bin/node /usr/bin/ \
    && ln -s /opt/node-${NODE_VERSION}-linux-x64/bin/npx /usr/bin/ \
    && npm install -g appium@${APPIUM_VERSION} --allow-root --unsafe-perm=true \
    && ln -s /opt/node-${NODE_VERSION}-linux-x64/bin/appium /usr/bin/

EXPOSE [4723,2251,5555]
CMD ["docker-entrypoint.sh"]

Что вы заметите, так это последний кусочек этой головоломки, точка входа в докер, которую мы использовали для запуска эмулятора и получения всего, что связано с Appium. К счастью, это было довольно легко, когда ты знал, что делать.

docker-entrypoint.sh


#!/bin/bash

# launch the emulator
exec /opt/adk/tools/emulator -avd Android -no-audio -no-window &

# setup appium
while [ -z $udid ]; do
    udid=`adb devices | grep emulator | cut -f 1`
done
exec appium -p 4723 -bp 2251 --default-capabilities '{"udid":"'${udid}'"}' &

И это все, что нам нужно было сделать, это запустить наши тесты.

Выполнение теста

Не вдаваясь в специфику проекта, мы могли бы сделать это либо локально, либо через другой контейнер Docker, но самым простым способом был определенно локальный, используя Maven. Мы могли бы сделать это, просто указав IP-адрес Docker, так же, как если бы у вас был запущен эмулятор локально, или устройство было привязано. Обмен портов также достаточно прост.

Последние мысли

Мы столкнулись с одним последним вопросом, который пытался запустить все это в AWS. Мы стремимся к тому, чтобы наши конвейеры работали как можно быстрее, и значительная часть этого означает, что машины с динамической подготовкой в ​​AWS, когда они нам нужны, значительно увеличили нашу пропускную способность. К сожалению, машины AWS не поддерживают вложенный KVM (да, я знаю об использовании металла, но мы хотели избежать такого увеличения стоимости). К сожалению, это означало, что большая часть этого не может быть использована таким образом. Оставайтесь с нами для следующего сообщения в блоге, в котором я приступаю к решению этой проблемы.

Считаете это полезным? Застрял? Как всегда, пожалуйста, оставьте несколько комментариев ниже.