Skip to content

Android documentation

Denis Verentsov edited this page Jan 26, 2024 · 19 revisions

Важно, миграция документации

Начиная с версии Emcee 20.1.0 документация по Android переехала на новую платформу.

Intro

Данная документация описывает настройку и запуск проекта Emcee для Android-проектов. С её помощью можно развернуть Emcee в Docker или Kubernetes и запускать инструментальные тесты Android.

Целевая аудитория - разработчики и другие пользователи Emcee.

Необходимые навыки - минимальный опыт работы с Docker или Kubernetes.

Требования к железу и софту:

  • OS Linux, Docker, KVM, Kubernetes (optional)
  • для одного контейнера с воркером потребуется 4GB RAM, 1.15 CPU
  • развернутый Artifactory. Можно использовать свой или развернуть самостоятельно (будет описано в документации ниже)
  • свободное место на диске минимум 55Гб. Размер образов: воркер ~50Гб, очередь ~2.5Гб, Artifactory OSS ~2Гб

Запуск системы Emcee без Kubernetes

Ручной запуск контейнеров

Для запуска Emcee без Kubernetes потребуется создать network для Docker и запустить все необходимые контейнеры вручную.

Создаем сеть для Docker-контейнеров с любым именем. Например, emcee-network:

docker network create emcee-network

Скачиваем и запускаем контейнер с очередью и указываем сеть, в которой будет работать контейнер. Дополнительно указывается параметр --publish для маппинга порта хоста на порт контейнера и открытия внешнего доступа к контейнеру с очередью:

docker run --detach --rm --name emcee-queue-service --network emcee-network --publish 41000:41000 avitotech/emcee-queue:20.0.0

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

docker run --detach --rm --name queue-worker1 --network emcee-network --device /dev/kvm avitotech/emcee-worker:20.0.0

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

docker run --detach --network emcee-network --publish 8081:8081 --publish 8082:8082 --name emcee-artifactory-service --volume emcee_artifactory:/var/opt/jfrog/artifactory docker.bintray.io/jfrog/artifactory-oss:latest

Чтобы убедиться, что очередь запущена, можно подключиться к её контейнеру и увидеть логи:

docker logs --follow <queue_container_id>

Запуск с помощью Docker Compose

Описанный выше алгоритм ручного запуска можно упростить с помощью Docker Compose.

Сперва нужно создать файл конфигурации docker-compose.yml

version: "3.9"

services:
  emcee-queue-service:
    image: avitotech/emcee-queue:20.0.0
    container_name: emcee-queue-service
    ports:
      - 41000:41000
      
  queue-worker:
    image: avitotech/emcee-worker:20.0.0
    env_file:
      - emcee-worker.env
    depends_on:
      - emcee-queue-service
    deploy:
      replicas: 3
    devices:
      - "/dev/kvm:/dev/kvm"
      
  emcee-artifactory:
    image: docker.bintray.io/jfrog/artifactory-oss:latest
    container_name: emcee-artifactory
    ports:
      - 8081:8081
      - 8082:8082
    volumes:
      - emcee_artifactory:/var/opt/jfrog/artifactory
volumes:
  emcee_artifactory:

Рядом с docker-compose.yml нужно создать файл emcee-worker.env, в котором можно описать переменные окружения для конфигурации воркера или оставить файл пустым. См. главу Конфигурация воркера.

А потом вызвать команду docker compose up в директории, где создан файл docker-compose.yml.

Эта команда запустит очередь, 3 воркера и Artifactory.

Получение адресов очереди и Artifactory

Если развернуть Emcee через Docker или Docker Compose локально, то локальные адреса будут выглядеть как:

  • http://localhost:41000/ для очереди
  • http://localhost:8081/ для Artifactory

Где порты соответствуют портам, указанным выше при запуске контейнеров. Для очереди это 41000, а для Artifactory это 8082.

Если Emcee развернута на удаленном компьютере, то доступ до него нужно настроить в зависимости от кофигурации вашей сети.

Запуск системы Emcee в Kubernetes

Запуск системы с использованием Kubernetes и Minikube

Для запуска Emcee нужно сконфигурировать и запустить ресурсы Kubernetes.

Для запуска кластера Kubernetes будет использоваться Minikube. Либо вы можете использовать свой готовый кластер Kubernetes.

После установки Minikube запускаем команду для старта кластера:

minikube start

Конфигурация ресурсов Kubernetes

Для запуска нам потребуется Deployment для воркеров, очереди и Artifactory; Service для очереди и Artifactory.

Конфигурация файла emcee-worker-deployment.yaml с Deployment для создания 3х воркеров.

Обратите внимание что в env указываются переменные окружения для настройки воркера. См. главу Конфигурация воркера.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: emcee-worker-deployment
  labels:
    app: emcee-app
spec:
  replicas: 3
  selector:
    matchLabels:
      component: emcee-worker
  template:
    metadata:
      labels:
        component: emcee-worker
    spec:
      containers:
        - name: emcee-worker
          image: avitotech/emcee-worker:20.0.0
          imagePullPolicy: IfNotPresent
          resources:
            requests:
              cpu: "1.15"
            limits:
              memory: "4.5Gi"
              cpu: "1.3"
          volumeMounts:
            - mountPath: /dev/kvm
              name: kvm
          securityContext:
            privileged: true
          ports:
            - containerPort: 80
          args: [ "$(EMCEE_WORKER_LOG_LEVEL)" ]
          env:
            - name: EMCEE_WORKER_QUEUE_URL
              value: "http://emcee-queue-service:41000"
            - name: EMCEE_WORKER_LOG_LEVEL
              value: "info"
      volumes:
        - name: kvm
          hostPath:
            path: /dev/kvm

Конфигурация файла emcee-queue-deployment.yaml с Deployment для очереди:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: emcee-queue-deployment
  labels:
    app: emcee-app
spec:
  selector:
    matchLabels:
      component: emcee-queue
  template:
    metadata:
      labels:
        component: emcee-queue
    spec:
      containers:
        - name: emcee-queue
          image: avitotech/emcee-queue:20.0.0
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 41000

Конфигурация файла emcee-queue-service.yaml с Service для очереди:

apiVersion: v1
kind: Service
metadata:
  name: emcee-queue-service
spec:
  type: NodePort
  selector:
    component: emcee-queue
  ports:
    - name: emcee-queue-service-ports
      protocol: TCP
      port: 41000
      targetPort: 41000

Конфигурация файла emcee-artifactory-deployment.yaml с Deployment для Artifactory:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: emcee-artifactory-deployment
  labels:
    app: emcee-app
spec:
  selector:
    matchLabels:
      component: emcee-artifactory
  template:
    metadata:
      labels:
        component: emcee-artifactory
    spec:
      containers:
        - name: emcee-artifactory
          image: docker.bintray.io/jfrog/artifactory-oss:latest
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 8081
            - containerPort: 8082
          volumeMounts:
            - mountPath: /var/opt/jfrog/artifactory
              name: artifactory
      volumes:
        - name: artifactory
          emptyDir: {}

Конфигурация файла emcee-artifactory-service.yaml с Service для Artifactory:

apiVersion: v1
kind: Service
metadata:
  name: emcee-artifactory-service
spec:
  type: NodePort
  selector:
    component: emcee-artifactory
  ports:
    - name: emcee-artifactory-service-port-1
      protocol: TCP
      port: 8081
      targetPort: 8081
    - name: emcee-artifactory-service-port-2
      protocol: TCP
      port: 8082
      targetPort: 8082

Запуск ресурсов Kubernetes

Для запуска системы нужно последовательно запустить ресурсы:

kubectl apply --filename ./emcee-queue-deployment.yaml
kubectl apply --filename ./emcee-queue-service.yaml
kubectl apply --filename ./emcee-worker-deployment.yaml
kubectl apply --filename ./emcee-artifactory-deployment.yaml
kubectl apply --filename ./emcee-artifactory-service.yaml

Или запустить ресурсы сразу одной командой. Для этого ресурсы складываем в одну директорию и вызываем команду:

kubectl apply --filename ./

Для проверки что ресурсы запустились вызываем команду:

kubectl get pods

Вывод в консоли должен выглядеть примерно так:

NAME                                           READY   STATUS    RESTARTS   AGE
emcee-artifactory-deployment-db979bd5b-7fdbm   1/1     Running   0          6m5s
emcee-queue-deployment-5b49cf5884-wkmv9        1/1     Running   0          6m5s
emcee-worker-deployment-66c6b8bdb4-2kxqq       1/1     Running   0          6m5s
emcee-worker-deployment-66c6b8bdb4-96rfs       1/1     Running   0          6m5s
emcee-worker-deployment-66c6b8bdb4-pbtjv       1/1     Running   0          6m5s

Получение адресов очереди и Artifactory

Для получения локального адреса очереди выполняем:

minikube service emcee-queue-service --url

В выводе команды будет ip:port очереди, который нужно использовать в Gradle плагине Emcee в качестве адреса очереди.

Для получения локального адреса Artifactory выполняем:

minikube service emcee-artifactory-service --url

В выводе команды будет ip:port Artifactory, который нужно использовать в Gradle плагине Emcee в качестве адреса Artifactory.

Если Emcee развернута на удаленном компьютере с кластером Kubernetes, то доступ до него нужно настроить в зависимости от кофигурации вашей сети и настроек Kubernetes.

Конфигурация воркера

Воркер конфигурируется через переменные окружения Docker.

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

docker run -d --env EMCEE_WORKER_QUEUE_URL="http://localhost:41000" \ 
--name queue-worker1 \ 
--network emcee-network avitotech/emcee-worker:20.0.0

Либо записать переменные окружения в файл .env и передать файл при старте контейнера:

docker run -d --env-file ./.env \
--name queue-worker1 \
--network emcee-network avitotech/emcee-worker:20.0.0

Доступные переменные окружения для конфигурации указаны в таблице:

Переменная Описание
EMCEE_WORKER_QUEUE_URL Url адрес очереди.
EMCEE_WORKER_LOG_LEVEL Уровень логгирования воркера. Доступные варианты: "verbose", "debug", "info", "warn", "critical".
EMCEE_WORKER_ARTIFACTS_DOWNLOAD_TIMEOUT_MS Таймаут загрузки apk файлов, указывается в миллисекундах.
EMCEE_WORKER_APK_INSTALLATION_TIMEOUT_MS Таймаут при установке apk файлов, указывается в миллисекундах.
EMCEE_WORKER_GRAPHITE_IS_ENABLED Включение или выключение метрик Graphite. Например, true или false.
EMCEE_WORKER_GRAPHITE_SOCKET_ADDRESS Хост адрес Graphite. Например, graphite.metrics.com
EMCEE_WORKER_GRAPHITE_SOCKET_PORT Порт сокета Graphite. Например, 2001.
EMCEE_WORKER_GRAPHITE_METRIC_PREFIX Префикс метрик Graphite. Например, apps.mobile.metrics.awesomeapp.
EMCEE_WORKER_KIBANA_ENDPOINTS Список из адреса и порта Kibana. Например, http://app-elasticsearch.com:9200. Адресов может быть несколько, разделять значения нужно через ,.
EMCEE_WORKER_KIBANA_INDEX_PATTERN Index pattern логов Kibana. Например, awesome-android-worker.
EMCEE_WORKER_ELASTIC_API_KEY api key для Elastic, параметр опциональный. Используется для авторизации в Elastic и будет отправлен в header запроса с логами. Поддержана авторизация типа api-key-service.
EMCEE_WORKER_KIBANA_IS_ENABLED Включение или выключение логов Kibana. Например, true или false.
EMCEE_WORKER_ARTIFACTORY_USERNAME Логин для авторизации в Artifactory. Поддержана авторизация типа Basic Authentication.
EMCEE_WORKER_ARTIFACTORY_PASSWORD Пароль для авторизации в Artifactory.

Переменные с настройками для Graphite, Kibana/Elastic, Artifactory опциональны.

Подключение и настройка Gradle плагина Emcee

Ручное подключение файла плагина (временный способ)

Сейчас мы распространяем Gradle плагин как jar файл. Скачать можно на странице с релизами или здесь.

Создайте директорию libs в корне проекта и положите туда jar файл.

Для подключения плагина добавьте в root build.gradle.kts:

buildscript {
    dependencies {
        classpath(files("libs/gradle-plugin-0.0.3-all.jar"))
    }
}

И укажите id плагина в build.gradle.kts модуля Application:

plugins {
    id("com.android.application")
    id("com.avito.android.emcee")
}

Настройка плагина

Плагин настраивается через свойства расширения плагина.

Свойство Описание
queueBaseUrl Адрес очереди Emcee.
testTimeout Максимальная длительность каждого теста в секундах.
artifactory Настройки для Artifactory.
Имеет вложенные свойства: user, password, baseUrl, repository, connectionTimeout, readTimeout, writeTimeout.
user имя пользователя Artifactory. Если авторизация выключена, то поле можно оставить пустым.
password пароль пользователя Artifactory. Если авторизация выключена, то поле можно оставить пустым.
baseUrl url адрес Artifactory, куда будут отправляться файлы.
repository репозиторий внутри Artifactory.
connectionTimeout, readTimeout, writeTimeout настройки HTTP клиента для Artifactory.
job Логическая единица работы для обработки очередью. Обычно один прогон тестов равняется одной job.
Имеет вложенные свойства: id, groupId, priority, groupPriority.
id id для job. Укажите пустое значение для автоматического создания или укажите свое значение вручную.
groupId id для объединения jobs в группы.
priority приоритет для job. Чем выше значение, тем выше приоритет выполняемой работы. Допустимые значения 0..999.
groupPriority аналогично priority, только применяется для group.
retries Количество попыток перезапустить неуспешный тест.
loggerConfiguration Конфигурация логгера для плагина.
Имеет вложенные свойства:
logLevel уровень логгирования. Доступны несколько вариантов: verbose, debug, info, warning, critical.
printStackTrace определяет печатать ли stackTrace, варианты true или false.
screenRecordConfiguration (Доступно с версии Emcee 20.0.0) Конфигурация записи экрана при запусках тестов. Доступна настройка записи видео через вложенное свойство videoRecordStrategy и стратегии записи экрана ScreenRecordStrategy.RECORD_ALL, RECORD_NONE, RECORD_ON_FAIL.
devices Список с описанием устройств, на которых будут запускаться тесты. Требуется указать минимум один девайс.
Доступные версии api: 24, 27, 29, 31. Все версии api имеют разрешение экрана 320x480 и 120dpi.
configurations Список конфигураций для внутренней работы плагина. Требуется указать хотя бы одну конфигурацию. Для каждой конфигурации создаётся отдельный gradle task.

Пример конфигурации плагина Emcee на Kotlin DSL:

import com.avito.emcee.client.ScreenRecordStrategy
import java.time.Duration

plugins {
    id("com.android.application")
    id("com.avito.android.emcee")
}

android {
    //...
}

emcee {
    queueBaseUrl.set("http://localhost:41000/")
    testTimeout.set(Duration.ofMinutes(1))
    artifactory {
        user.set("Set to empty or set username if auth is enabled in Artifactory")
        password.set("Set to empty or set password if auth is enabled in Artifactory")
        baseUrl.set("http://localhost:8081/artifactory/")
        repository.set("emcee-transport")
        connectionTimeout.set(Duration.ofMinutes(1))
        readTimeout.set(Duration.ofMinutes(1))
        writeTimeout.set(Duration.ofMinutes(1))
    }
    job {
        groupId.set("Emcee Android Sample")
        groupPriority.set(1)
        id.set("Set me to empty for auto generation or set your id")
        priority.set(1)
    }
    retries.set(1)
    loggerConfiguration {
        logLevel.set("info")
        printStackTrace.set(false)
    }
    screenRecordConfiguration {
        videoRecordStrategy.set(ScreenRecordStrategy.RECORD_ON_FAIL)
    }
    devices {
        addDevice(24, "default")
    }
    configurations {
        register("default")
    }
}

Запуск тестов в Emcee

Запуск тестов с помощью Gradle plugin

После применения плагина будут созданы gradle задачи вида emceeTest<Configuration><BuildVariant>. Например, emceeTestDefaultDebug.

Для отправки тестов в очередь выполните команду, где вместо Debug может быть ваш build variant:

./gradlew emceeTestDefaultDebug

Запуск тестов с помощью CLI

Запустить тесты можно из командной строки с помощью emcee.jar (необходима java версии 11)

java -jar emcee.jar run android.emceeplan --outdir result

, где

--outdir result - директория, где будут расположены результаты тестов,

android.emceeplan - конфигурация для запуска тестов, это YAML файл в формате ниже. Смысл параметров и их возможных значений есть в таблице. Стандартные значения для опциональных параметров указаны в примере:

configuration: 
  appApk: "/path/to/app-debug.apk"  # Required. Both absolute and relative paths are acceptable
  testApk: "/path/to/app-debug-androidTest.apk"  # Required.
  testRunnerClass: "androidx.test.runner.AndroidJUnitRunner"  # Required
  devices: 
  - sdkVersion: 31  # Required
    deviceType: "default"  # Required
  screenRecordConfiguration:  # Optional
    videoRecordStrategy: record_none  # Optional
  environment:  # Optional
    key: value  # Optional
  retries: 1  # Optional
  testTimeout: 60  # Optional
artifactory: 
  user: "user"  # Required
  password: ""  # Required
  baseUrl: "https://artifactory.mydomain/"  # Required
  repository: "no-backups"  # Required
queue: 
  baseUrl: "http://queue.mydomain:41000/"  # Required

Больше информации можно найти:

java -jar emcee.jar run --help

Фильтрация тестов

Для отправки в очередь только определенных тестов можно применить фильтрацию.

Для этого нужно зарегистрировать группу фильтров, дать группе имя и указать нужные фильтры. Например:

import com.avito.emcee.client.internal.test_filter.TestFilter.AnnotationFilter
import com.avito.emcee.client.internal.test_filter.TestFilter.ClassNameFilter

emcee {
    // ...
    testsFilters {
        registerFilterGroup(
            name = "group1",
            filters = listOf(
                AnnotationFilter("FlakyTest"),
                AnnotationFilter("LargeTest"),
            )
        )
        registerFilterGroup(
            name = "group2",
            filters = listOf(
                ClassNameFilter("TestClassName")
            )
        )
    }
}

Можно зарегистрировать сразу несколько групп фильтров, в которых можно комбинировать фильтры разного типа.

Для применения фильтрации к команде отправки тестов в очередь добавляется аргумент с указанием имени группы:

./gradlew emceeTestDebug --filterGroupName group1

Доступные виды фильтров:

Фильтр Описание
AnnotationFilter Фильтр по имени аннотации тестов. Например, Flaky или LargeTest.
PackageNameFilter Фильтр по имени пакета. Например, com.example.specialtest.
ClassNameFilter Фильтр по имени класса с тестами. Например, ExampleInstrumentedTest.

Метрики и логи воркера (опционально)

Метрики и логи опциональны. Если не планируете отправлять метрики и логи, то эту главу можно пропустить.

Воркер умеет посылать логи в Kibana и метрики в Graphite. Метрики визуализируются с помощью Grafana или других инструментов, поддерживаюших работу с Graphite.

Конфигурация метрик и логов

Перед получением метрик и логов необходимо самостоятельно настроить Graphite и Kibana.

Для включения метрик и логов передайте параметры в переменные окружения (см. главу Конфигурация воркера).

Для включения метрик Graphite используйте переменные окружения:

  • EMCEE_WORKER_GRAPHITE_IS_ENABLED
  • EMCEE_WORKER_GRAPHITE_SOCKET_ADDRESS
  • EMCEE_WORKER_GRAPHITE_SOCKET_PORT
  • EMCEE_WORKER_GRAPHITE_METRIC_PREFIX

Для включения логов Kibana используйте переменные окружения:

  • EMCEE_WORKER_KIBANA_IS_ENABLED
  • EMCEE_WORKER_KIBANA_ENDPOINTS
  • EMCEE_WORKER_KIBANA_INDEX_PATTERN
  • EMCEE_WORKER_ELASTIC_API_KEY

Какие метрики и логи отправляет воркер

Воркер отправляет информацию о состоянии системы и шагах выполнения работы. Детализация логов зависит от заданного уровня логгирования (см. главу Конфигурация воркера).

Список отправляемых воркером метрик:

  • время ответа на сетевой запрос к очереди
  • время сетевого запроса к очереди
  • время загрузки apk файлов
  • факт загрузки или переиспользования apk файлов
  • время работы воркера при успешном прогоне (включая загрузку apk файлов, прогон тестов, и отправку тестовых артефактов)
  • время получения эмулятора (старт нового или переиспользование существующего)

Настройка Artifactory

Для Emcee нужно настроить Artifactory. В него будут отправляться apk файлы и артефакты прогонов. Artifactory может быть уже существующий или новый.

Для настройки нужно:

  • создать новый репозиторий с типом Generic и с именем на ваш выбор. Важно чтобы в поле repository при настройке Emcee был указан этот репозиторий (см. главу Настройка плагина). В нем потом будет создана папка emcee-transport для работы Emcee
  • создать нового пользователя с правами на запись и удаление, или использовать существующего пользователя, или включить анонимный доступ в настройках

Новый репозиторий можно создать в панели Administration - Repositories - Add repository - Local repository

Анонимный доступ можно включить в панели Administration - User management - Settings. Важно, для анонимного пользователя тоже нужно выдавать права на запись/удаление.

Артефакты прогона тестов в on-premise версии

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

Файлы будут загружены в директорию emcee_artifacts в директории проекта. По каждому прогону будет создана директория с именем jobId.

Сейчас поддерживается загрузка:

  • файлов с логами logcat
  • видео с записью экрана (если включено в настройках, см. главу Настройка плагина)
  • файлов Allure (если он присутствует в самих тестах)

Поиск файлов Allure выполняется автоматически из стандартных директорий, указанных в документации Allure Kotlin.

Known issues

Если вы столкнулись с проблемой, то вы всегда можете задать вопрос разработчикам в чате в Telegram.

Здесь перечислен список известных проблем и способы их решения.

Parameterized тест не запускается или по нему нет результатов

Сейчас мы не поддерживаем Parameterized тест с именованием, например @Parameterized.Parameters(name = "parameterized test name"). Чтобы такой тест начал работать в Emcee, нужно удалить параметр name. Например, @Parameterized.Parameters.

Не запускаются тесты на Android API 27 из-за таймаута при установке apk

Иногда apk может не установиться по таймауту. Если увеличение таймаута не помогает, то рекомендуем использовать другую версию api для запуска тестов. Если вы столкнулись с такой ситуацией, то напишите разработчикам.

Если в отчете Allure не хватает тестов

Если части тестов в отчете Allure нет, то, возможно, поможет добавление аннотации @RunWith(AllureAndroidJUnit4::class) к тестовому классу с тестами, которых нет в отчете.

Clone this wiki locally