Привет! Меня зовут Денис Веренцов, я Android-инженер из команды Emcee. Это технопродукт Авито, универсальное решение для запуска iOS и Android-тестов, с его помощью можно быстрее выкатывать новые фичи пользователям и клиентам. В этой статье я расскажу, как можно развернуть облачную инфраструктуру для запуска нативных автотестов Android-приложений на основе разработанного нами решения.

Статья будет полезна тем, кто хочет организовать инфраструктуру для запуска тестов, но не обладает подходящим для этого «железом». Материал также будет интересен тем, у кого есть желание попробовать технологию Emcee в деле.

Что внутри статьи:

Emcee и его преимущества

Emcee — это инструмент для мобильных автотестов. С его помощью можно развернуть инфраструктуру для нативных автотестов Android/iOS и запускать тесты, эффективно утилизируя ресурсы и повышая time-to-market.

Основные преимущества Emcee:

  • эффективность: тесты запускаются сразу на всех доступных ресурсах, не нужно выделять отдельные пулы ресурсов под определенные запуски тестов;

  • автоматический менеджмент жизненного цикла эмуляторов;

  • гибкая конфигурация запуска тестов: разные стратегии деления тестов, повторы упавших тестов, настройка таймаутов и так далее.

Облачная инфраструктура

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

Плюсы:

  • можно быстро получить «железо» в широком спектре конфигураций. Это бывает полезно при проведении быстрых экспериментов или тестировании новых технологий;

  • можно обратиться в техподдержку, если есть проблемы или вопросы;

  • некоторые провайдеры на первое время дают гранты или бонусные рубли — первые эксперименты можно проводить бесплатно.

Минусы:

  • пожалуй, самый главный минус — стоимость: аренда мощного сервера или виртуальной машины может быть очень дорогой. Это десятки или даже сотни тысяч рублей в месяц;

  • не у всех провайдеров есть возможность выделить машины с KVM. У каждого провайдера нужно уточнять этот момент  через техподдержку или документацию, а также проверять доступность KVM вручную;

  • нужно отдельно решать вопросы безопасности, так как без дополнительной подготовки такая инфраструктура открыта для интернета;

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

У Emcee есть ряд требований к железу, поэтому перед арендой облачных мощностей нужно убедиться, что железо соответствует требованиям.

Требования такие:

  • OS на базе Linux, Docker, KVM (Kernel-based Virtual Machine)*;

  • процессор с архитектурой x86-64;

  • достаточное количество ресурсов для запуска нескольких docker-контейнеров. Минимум 4 CPU и 8ГБ RAM.

*На данный момент наличие KVM является обязательным, так как эта технология позволяет значительно улучшить перформанс Android-эмулятора. Подробнее можно прочесть в официальной документации эмулятора.

Аренда облачных ресурсов

Для примера был выбран провайдер VK Cloud, на котором в качестве демонстрации я арендую подходящую виртуальную машину (далее ВМ).

Создадим новый инстанс ВМ. Я выбрал Ubuntu 22.04, 8 CPU и 16ГБ RAM, а также диск SSD на 100ГБ.

Обратите внимание, что изначально конфигурация NESTED-X-X не была доступна. Для её получения я написал в техподдержку и спросил, как можно получить работающий KVM или рабочую вложенную виртуализацию внутри моей ВМ.

Далее настраиваем сеть:

  1. Для доступа к ВМ я указал свой SSH-ключ. Ключ можно создать или указать свой в меню выбора ключа.

  2. Дополнительно я добавил настройку Firewall: добавил новую группу безопасности emcee, в которой указал, какой входящий трафик разрешен для моей ВМ.

  1. В группе безопасности emcee я указал порты, необходимые для работы Emcee: 8081, 8082 и 41000.

Следующим шагом предлагается настроить резервное копирование. Я отключил эту опцию и далее выбрал «Создать инстанс».

Немного ждем, пока ВМ подготовится и запустится.

После этого можно подключаться к ВМ по SSH с помощью ключа, который мы указывали при создании ВМ. Дополнительно в общей информации о ВМ описан способ подключения.

Как подготовить инфраструктуру

Подключаемся к ВМ по SSH:

ssh -i vktest ubuntu@<VM ip address>

Проверяем доступность KVM

После успешного подключения нужно проверить, что KVM доступен на данной ВМ. Для этого нужно установить утилиты cpu-checker и libvirt-clients . Можно установить что-то одно, но для примера я установлю обе.

Устанавливаем cpu-checker:

sudo apt-get install cpu-checker

И после установки вызываем в консоли команду sudo kvm-ok, которая должна показать наличие или отсутствие KVM. Вывод команды, если KVM доступен:

INFO: /dev/kvm exists
KVM acceleration can be used

Если KVM недоступен, то вывод будет такой:

INFO: Your CPU does not support KVM extensions
KVM acceleration can NOT be used

Устанавливаем libvirt-clients:

sudo apt-get update && sudo apt-get install libvirt-daemon-system libvirt-clients

После установки вызываем в консоли команду virt-host-validate qemu. Вывод команды, если KVM доступен:

QEMU: Checking for hardware virtualization                                 : PASS

  QEMU: Checking if device /dev/kvm exists                                   : PASS

  QEMU: Checking if device /dev/kvm is accessible                            : FAIL (Check /dev/kvm is world writable or you are in a group that is allowed to access it)

  QEMU: Checking if device /dev/vhost-net exists                             : PASS

  QEMU: Checking if device /dev/net/tun exists                               : PASS

  QEMU: Checking for cgroup 'cpu' controller support                         : PASS

  QEMU: Checking for cgroup 'cpuacct' controller support                     : PASS

  QEMU: Checking for cgroup 'cpuset' controller support                      : PASS

  QEMU: Checking for cgroup 'memory' controller support                      : PASS

  QEMU: Checking for cgroup 'devices' controller support                     : WARN (Enable 'devices' in kernel Kconfig file or mount/enable cgroup controller in your system)

  QEMU: Checking for cgroup 'blkio' controller support                       : PASS

  QEMU: Checking for device assignment IOMMU support                         : WARN (No ACPI DMAR table found, IOMMU either disabled in BIOS or not supported by this hardware platform)

  QEMU: Checking for secure guest support                                    : WARN (Unknown if this platform has Secure Guest support)

 Если KVM недоступен, то вывод может быть примерно таким:

QEMU: Checking for hardware virtualization                                 : FAIL (Host not compatible with KVM; HW virtualization CPU features not found. Only emulated CPUs are available; performance will be significantly limited)

  QEMU: Checking if device /dev/vhost-net exists                             : PASS

  QEMU: Checking if device /dev/net/tun exists                               : PASS

  QEMU: Checking for cgroup 'cpu' controller support                         : PASS

  QEMU: Checking for cgroup 'cpuacct' controller support                     : PASS

  QEMU: Checking for cgroup 'cpuset' controller support                      : PASS

  QEMU: Checking for cgroup 'memory' controller support                      : PASS

  QEMU: Checking for cgroup 'devices' controller support                     : PASS

  QEMU: Checking for cgroup 'blkio' controller support                       : PASS

  QEMU: Checking for device assignment IOMMU support                         : WARN (Unknown if this platform has IOMMU support)

  QEMU: Checking for secure guest support                                    : WARN (Unknown if this platform has Secure Guest support)

В случае, если после проверок обнаружилось, что KVM недоступен, то нужно узнать у техподдержки, как его включить/получить. А если такой возможности нет, то следует сменить провайдера. 

Запускаем инфраструктуру Emcee через Docker Compose

Система Emcee запускается на основе docker-контейнеров. Минимальный набор контейнеров включается в себя три контейнера с сущностями:

  1. очередь Emcee распределяет тесты по воркерам в завиcимости от стратегии распределения и повтора тестов;

  2. воркер Emcee запускает тесты и собирает их результаты, управляет жизненным циклом Android-эмуляторов, которые запускаются внутри контейнера;

  3. Artifactory — готовая система для менеджмента артефактов. Нужна для передачи файлов между воркерами и клиентами Emcee.

Так как используются docker-контейнеры, Emcee можно развернуть разными способами: через Docker или Docker Compose, а также через Kubernetes. Для простоты я выберу способ с Docker Compose, который можно установить по официальной документации.

Нам потребуется всего 2 файла, создадим docker-compose.yaml:

version: '3'

services:

  emcee-queue-service:

    image: avitotech/emcee-queue:21.5.0

    container_name: emcee-queue-service

    ports:

      - 41000:41000

  queue-worker:

    image: avitotech/emcee-worker:21.5.0

    env_file:

      - emcee-worker.env

    depends_on:

      - emcee-queue-service

    deploy:

      replicas: 2

    devices:

      - "/dev/kvm:/dev/kvm"

  emcee-artifactory:

    image: docker.bintray.io/jfrog/artifactory-oss:7.63.11

    container_name: emcee-artifactory

    ports:

      - 8081:8081

      - 8082:8082

    volumes:

      - emcee_artifactory:/var/opt/jfrog/artifactory

volumes:

  emcee_artifactory:

Создадим второй файл, где указываются переменные окружения для воркера emcee-worker.env:

EMCEE_WORKER_QUEUE_URL=http://emcee-queue-service:41000
EMCEE_WORKER_LOG_LEVEL=info

Имя хоста emcee-queue-service резолвится в локальный адрес контейнера с таким же именем. 

Далее поднимаем контейнеры командой:

docker compose up -d

И проверяем, что поднятие прошло успешно:

> docker ps -a

CONTAINER ID   IMAGE                                             COMMAND                  CREATED          STATUS          PORTS                                                           NAMES

b631f9f32fa2   avitotech/emcee-worker:21.1.0                     "./entrypoint.sh"        45 seconds ago   Up 45 seconds   41001/tcp                                                       ubuntu-queue-worker-2

600a8a769bff   avitotech/emcee-worker:21.1.0                     "./entrypoint.sh"        45 seconds ago   Up 44 seconds   41001/tcp                                                       ubuntu-queue-worker-1

6f7f5aca1fc0   docker.bintray.io/jfrog/artifactory-oss:7.63.11   "/entrypoint-artifac…"   46 seconds ago   Up 45 seconds   0.0.0.0:8081-8082->8081-8082/tcp, :::8081-8082->8081-8082/tcp   emcee-artifactory

cd2c4c1cb7b3   avitotech/emcee-queue:21.1.0                      "/usr/local/bin/entr…"   46 seconds ago   Up 45 seconds   0.0.0.0:41000->41000/tcp, :::41000->41000/tcp                   emcee-queue-service

Дополнительно можно проверить логи контейнера с воркером и увидеть, что воркер готов к работе:

> docker logs --tail 2 b631f9f32fa2

[INFO] [HttpServer] 2024-08-23 08:00:33.610: REST server at 41001 port started

[INFO] [StartWorkerCommand] 2024-08-23 08:00:33.611: Worker is ready for work

Кроме запуска контейнеров нужно настроить Artifactory. Для этого нужно:

  1. зайти по адресу <ваш ip>:8082 и пройти первоначальную настройку. Для первого входа использовать первичные данные admin и password;

  2. создать новый репозиторий с типом Generic и именем на ваш выбор;

  3. создать нового юзера, данные которого будут использоваться в клиентах Emcee и в воркерах, либо включить анонимный доступ. Здесь важно выдать новому юзеру, в том числе анонимному, права на чтение/запись/удаление. Если создан новый юзер, то в конфигурации воркера нужно задать его username/password в файле конфигурации emcee-worker.env . Подробнее про конфигурацию воркера описано здесь.

Подробнее про настройку Artifactory можно прочесть в документации Emcee.

Отмечу, что если у вас уже есть готовый и настроенный Artifactory, то можно использовать его. Главное, чтобы Artifactory был доступен и для клиентов, и для воркеров Emcee.

На этом запуск и настройка Emcee завершены, наша система готова принимать тесты.

Запускаем тесты через Emcee

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

Android-клиенты бывают двух видов: 

  • cli-утилита;

  • Gradle plugin.

Я выберу cli-утилиту, которую можно установить разными способами.

Для запуска тестов нам потребуется файл с конфигурацией, например, config.yaml:

queue:

    baseUrl: http://emcee-network-address:41000 # адрес очереди Emcee

tests:

    configurations:

        - platform: android

          appApk: ./apks/regress-debug.apk

          testApk: ./apks/regress-debug-androidTest.apk

          testTimeout: 120

          screenRecordConfiguration:

              videoRecordStrategy: record_none

          devices:

              - sdkVersion: 31 # версия Android SDK, на которой будут запущены тесты на эмуляторе

                deviceType: "default"

    outputs:

        - junit # включаю создание отчета JUnit

        - allure # включаю загрузку файлов для Allure отчета

storage:

    type: artifactory

    baseUrl: http://emcee-network-address:8081/artifactory/ # адрес настроенной Artifactory

    repository: emcee-transport

    user: "emcee_user"

    password: "emcee_password"

Здесь файлы apk с приложением и тестами я положил рядом с файлом конфига. Как показывает практика, разные команды по-разному создают apk в рамках своих конвейеров на CI. Поэтому можно указать свой путь до актуальных apk файлов.

Бинарный файл с cli-утилитой я скачал вручную и теперь мой запуск прогона тестов выглядит так:

./emcee run config.yaml --outdir=results

После прогона тестов я получаю финальный результат:

Emcee run finished.

Sent tests count: 12

Executed tests count: 12

Run status: Failed

Successful tests count: 10

Skipped tests count: 1

Skipped tests:

com.avito.emcee.regress.ExampleInstrumentedTest#assumptionFalse

Failed tests count: 1

Failed tests:

com.avito.emcee.regress.ExampleInstrumentedTest#failed

Tests results written to: /my/path/results/emcee_artifacts/c15f0e85-7f3a-4007-95cc-25101b3aa231

com.avito.emcee.client.internal.result.JobResultHasFailedTestsException: These tests have failed:

com.avito.emcee.regress.ExampleInstrumentedTest#failed

Таким образом, мы успешно запустили прогон тестов в Emcee.

Бонус: готовое облако

Для тех, кто не хочет заморачиваться с виртуальными машинами и провайдерами, можно попробовать сразу запустить тесты в нашем облаке Emcee Cloud. В Emcee Сloud не нужно платить за аренду мощностей, плата берется только за время выполнения тестов. А для всех новых клиентов мы даем бесплатную квоту в 300 минут на прогоны тестов.

Три главных факта про Emcee

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

  • Инструмент Emcee позволяет быстро развернуть масштабируемую инфраструктуру для автотестов Android (как попробовать Emcee для iOS можно почитать здесь). 

  • Для запуска Emcee нужен подходящий сервер с Docker Compose, на котором можно развернуть контейнеры с Emcee и Artifactory: Artifactory нужно настроить либо использовать готовый. 

  • Для тех, у кого нет своего железа и кто не готов платить за его аренду, мы создали сервис Emcee Cloud, где можно запускать свои тесты в облаке.

Спасибо за уделенное время для статьи! Если у вас остались вопросы и уточнения, вы можете оставить их в комментариях — буду рад прояснить.

Комментарии (2)


  1. genericuser
    15.11.2024 08:18

    Спасибо за статью! Интересен такой нюанс: как вы управляете правами доступа к /dev/kvm внутри контейнера с эмулятором?

    • Если правильно помню, прокинутый /dev/kvm залетает в докер-контейнер с id его владельца на хосте. При попытке запустить эмулятор от лица непривилегированного пользователя может не хватит прав на работу с KVM.

    • /dev/kvm доступен только при работе контейнера, при сборке самого докер-образа его еще нет, заранее права не выдать. А выдавать права во время работы контейнера в стиле `sudo chmod` тоже не хочется.


    1. d_verentsov Автор
      15.11.2024 08:18

      Спасибо за вопрос. Внутри контейнера и при сборке его образа отдельно правами не управляем.
      Вместо этого используем при запуске контейнера пользователя, у которого есть права доступа к /dev/kvm.