-
Notifications
You must be signed in to change notification settings - Fork 28
Android documentation
Данная документация описывает настройку и запуск проекта Emcee для Android-проектов. С её помощью можно развернуть Emcee в Docker или Kubernetes и запускать инструментальные тесты Android.
Целевая аудитория - разработчики и другие пользователи Emcee.
Необходимые навыки - минимальный опыт работы с Docker или Kubernetes.
Требования к железу и софту:
- OS Linux, Docker, KVM, Kubernetes (optional)
- для одного контейнера с воркером потребуется 4GB RAM, 1.15 CPU
- развернутый Artifactory. Можно использовать свой или развернуть самостоятельно (будет описано в документации ниже)
Для запуска 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:19.0.0
Скачиваем и запускаем контейнер с воркером. Таких контейнеров может быть запущено несколько, для этого каждому контейнеру нужно задать своё имя:
docker run --detach --rm --name queue-worker1 --network emcee-network --device /dev/kvm avitotech/emcee-worker:19.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.yml
version: "3.9"
services:
emcee-queue-service:
image: avitotech/emcee-queue:19.0.0
container_name: emcee-queue-service
ports:
- 41000:41000
queue-worker:
image: avitotech/emcee-worker:19.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.
Если развернуть Emcee через Docker или Docker Compose локально, то локальные адреса будут выглядеть как:
-
http://localhost:41000/
для очереди -
http://localhost:8081/
для Artifactory
Где порты соответствуют портам, указанным выше при запуске контейнеров. Для очереди это 41000
, а для Artifactory это 8082
.
Если Emcee развернута на удаленном компьютере, то доступ до него нужно настроить в зависимости от кофигурации вашей сети.
Для запуска Emcee нужно сконфигурировать и запустить ресурсы Kubernetes.
Для запуска кластера Kubernetes будет использоваться Minikube. Либо вы можете использовать свой готовый кластер Kubernetes.
После установки Minikube запускаем команду для старта кластера:
minikube start
Для запуска нам потребуется 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:19.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:19.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
Для запуска системы нужно последовательно запустить ресурсы:
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
Для получения локального адреса очереди выполняем:
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:19.0.0
Либо записать переменные окружения в файл .env
и передать файл при старте контейнера:
docker run -d --env-file ./.env \
--name queue-worker1 \
--network emcee-network avitotech/emcee-worker:19.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 плагин как jar файл. Скачать можно на странице с релизами или здесь.
Создайте директорию libs
в корне проекта и положите туда jar файл.
Для подключения плагина добавьте в root build.gradle.kts:
buildscript {
dependencies {
classpath(files("libs/gradle-plugin-0.0.2-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. user имя пользователя Artifactory. Если авторизация выключена, то поле можно оставить пустым. password пароль пользователя Artifactory. Если авторизация выключена, то поле можно оставить пустым. baseUrl url адрес Artifactory, куда будут отправляться файлы. repository репозиторий внутри Artifactory, нужно указать emcee-transport . |
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 . |
devices | Список с описанием устройств, на которых будут запускаться тесты. Требуется указать минимум один девайс. Доступные версии api: 24, 27, 29, 31. Все версии api имеют разрешение экрана 320x480 и 120dpi. |
configurations | Список конфигураций с указанием используемых таргетов, фильтров и др. Требуется указать хотя бы одну конфигурацию. Для каждой конфигурации создаётся отдельный gradle task |
targets | Список таргетов с указанием девайса и количества попыток (не используется) |
filters | Список фильтров, доступных при создании конфигурации (не используется) |
|
Пример конфигурации плагина Emcee на Kotlin DSL:
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")
}
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)
}
devices {
addDevice(24, "default")
}
}
В текущей реализации потребуется дополнительная конфигурация плагина.
Нужно добавить в build.gradle.kts модуля Application блок с кодом:
android {
//...
}
androidComponents {
beforeVariants {
if (it.name == "debug") {
it.enableUnitTest = true
it.enableAndroidTest = true
} else {
it.enable = false
}
}
}
Это включит android тесты только для билд-варианта debug.
После применения плагина будут созданы gradle задачи вида emceeTest<BuildVariant>
. Например, emceeTestDebug
.
Для отправки тестов в очередь выполните команду, где вместо Debug может быть ваш build variant:
./gradlew emceeTestDebug
Для отправки в очередь только определенных тестов можно применить фильтрацию.
Для этого нужно зарегистрировать группу фильтров, дать группе имя и указать нужные фильтры. Например:
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 файлов, прогон тестов, и отправку тестовых артефактов)
- время получения эмулятора (старт нового или переиспользование существующего)
Для Emcee нужно настроить Artifactory. В него будут отправляться apk файлы и артефакты прогонов. Artifactory может быть уже существующий или новый.
Для настройки нужно:
- создать новый репозиторий с типом Generic и с именем emcee-transport
- создать нового пользователя с правами на запись и удаление, или использовать существующего пользователя, или включить анонимный доступ в настройках
Новый репозиторий можно создать в панели Administration - Repositories - Add repository - Local repository
Анонимный доступ можно включить в панели Administration - User management - Settings. Важно, для анонимного пользователя тоже нужно выдавать права на запись/удаление.
Emcee умеет загружать артефакты прогона при условии, что Artifactory настроен и работает корректно.
Файлы будут загружены в директорию emcee_artifacts
в директории проекта. По каждому прогону будет создана директория с именем jobId.
Сейчас поддерживается загрузка файлов с логами и файлов Allure (если он присутствует в самих тестах).
Поиск файлов Allure выполняется автоматически из стандартных директорий, указанных в документации Allure Kotlin.
Если вы столкнулись с проблемой, то вы всегда можете задать вопрос разработчикам в чате в Telegram.
Здесь перечислен список известных проблем и способы их решения.
Сейчас мы не поддерживаем Parameterized тест с именованием, например @Parameterized.Parameters(name = "parameterized test name")
.
Чтобы такой тест начал работать в Emcee, нужно удалить параметр name
. Например, @Parameterized.Parameters
.
Иногда apk может не установиться по таймауту. Если увеличение таймаута не помогает, то рекомендуем использовать другую версию api для запуска тестов. Если вы столкнулись с такой ситуацией, то напишите разработчикам.
Если части тестов в отчете Allure нет, то, возможно, поможет добавление аннотации @RunWith(AllureAndroidJUnit4::class)
к тестовому классу с тестами, которых нет в отчете.