Привет, Хабр! Меня зовут Андрей, я SDET-специалист SimbirSoft. В практике CI/CD один из общепринятых стандартов — настройка автоматического запуска автотестов при деплое сервиса на стенды. То есть при запуске сборки мы сразу видим, как пройдут смоук-автотесты, и на основе отчета решаем, передавать сборку дальше QA-команде или дорабатывать. Это упрощает работу команды и позволяет быстрее исправлять ошибки, что критично важно для бизнеса.
Мы разберем автоматический запуск автотестов с использованием Downstream pipelines в GitLab CI на примере проекта с несколькими микросервисами. Они должны триггерить разные группы автотестов, а также имеют разные точки входа, то есть базовые URL. Выглядит это так:
Пайплайн сборки сервисов
Допустим, .gitlab-ci.yml в сборке микросервиса выглядит так:
stages:
- build
- deploy
- test
build job:
stage: build
script:
- echo "Build service"
deploy job:
stage: deploy
script:
- echo "Deploy service"
when: on_success
Сервис при сборке хранит в переменных среды необходимый URL, который далее станет точкой входа для автотестов (например, app.testing.com или app.staging.com). Если этого URL в переменных нет, вы можете добавить разные переменные для разных окружений в настройках этого пайплайна. Сделать это можно в UI GitLab тут Setting -> CI/CD -> Variables, например PARENT_URL для разных Environment scope.
Пойдем по пути использования одного фреймворка с автотестами для этих микросервисов. Мы хотим, чтобы фреймворк жил отдельным пайплайном и мог автономно запускаться без привязки к микросервису.
Для чего нужен автономный запуск? Когда мы написали новый тест-сьюит, и его запуск успешно прошел локально, необходимо проверить, как его прогон пройдет в CI/CD, так как там автотесты могут упасть. Это может быть связано с тем, что под капотом Selenoid автотест может работать иначе, или скорость обработки данных БД чрезмерно высока, и в неё не успевают прилетать сообщения из другого сервиса.
Чтобы автотесты запускались автоматом при деплое сервиса, и при этом сохранялась необходимая автономность, мы будем использовать Downstream pipelines.
Добавляем в .gitlab-ci.yml сборки микросервиса триггер для запуска автотестов:
testing_job:
stage: test
variables:
PARENT_MARK: "smoke_service_a" # Здесь Вы можете указать метку, которую хотите передавать в автозапуск тестов
# Для второго микросервиса здесь будет соответственно PARENT_MARK: "smoke_service_b"
PARENT_URL: "https://rickandmortyapi.com/api" # Здесь я имитирую передачу сервисом необходимого URL
trigger: ansid63/just_ci
rules:
- if: $CI_COMMIT_BRANCH == "main"
В trigger мы передаем путь к нашему проекту с автотестами в GitLab CI. Поле rules в данном случае устанавливает условие, что автотесты необходимо триггерить при мерже в ветку main.
Пайплайн проекта с автотестами
Переходим к проекту с автотестами. Я сделал небольшой проект с API тестами для проверки работы связки пайплайнов:
В проекте должен быть подключен GitLab Runner. Если вы запускаете проект на gitlab.com, возможно, вам будет достаточно Runner, предлагаемого сервисом GitLab.
В conftest.py я выдергиваю базовый URL для запуска автотестов:
from pytest import fixture
def pytest_addoption(parser):
parser.addoption(
"--url",
action="store",
default="https://rickandmortyapi.com/api")
@fixture()
def url(request):
return request.config.getoption("--url")
Dockerfile собирает контейнер с автотестами и зависимостями, в автотестах используются библиотеки pytest и requests.
FROM python:3.9.13-slim
COPY . .
RUN pip3 install -r requirements.txt --no-cache-dir
Папка tests содержит один файл с автотестами.
Давайте разберем пайплайн в .gitlab-ci.yml проекта с автотестами:
stages:
- build # Этап сборки контейнера с автотестами и зависимостями
- test # Этап запуска автотестов
variables:
TEST_MARK:
value: "smoke_service_a" # Дефолтная mark для pytest
TEST_PATH:
value: "tests"
# Т.к. мы прокидываем --url, pytest очень просит указать путь к местоположению тестов
TEST_URL:
value: "https://rickandmortyapi.com/api" # Дефолтный URL для pytest
AQA_GIT_TAG: v0.1.0 # Тэг для контейнера с автотестами
AQA_IMAGE: "${CI_REGISTRY_IMAGE}/autotests:${AQA_GIT_TAG}" # Путь к контейнеру с автотестами
.docker-registry: &docker-registry
- echo $CI_REGISTRY_PASSWORD | docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
# Шаблон для авторизации в СI registry
build_autotest_image:
# Данный этап с условием only позволяет нам собирать контейнер только при git push
# и избежать постоянной пересборки контейнера при запуске автотестов.
stage: build
image: gitlab/dind
services:
- docker:dind
before_script:
- *docker-registry # Авторизация в СI registry
script:
- docker build -t ${AQA_IMAGE} . # Собираем контейнер с автотестами и зависимостями
- docker push ${AQA_IMAGE} # Пушим контейнер в СI registry
only:
refs:
- pushes # Сборка контейнера происходит только при git push в проекте с автотестами
test job 1: # Запуск автотестов при триггере от сборки микросервиса
stage: test
image: "${AQA_IMAGE}"
script:
- pytest -m $PARENT_MARK $TEST_PATH --url $PARENT_URL # Запускаем автотесты
rules:
- if: $CI_PIPELINE_SOURCE == "pipeline"
# Согласно данному правилу, этот процесс запускается в случае, если пайплайн триггериться
test job 2: # Запуск автотестов при ручном запуске
stage: test
image: "${AQA_IMAGE}"
script:
- pytest -m $TEST_MARK $TEST_PATH --url $TEST_URL # Запускаем автотесты
rules:
- if: $TEST_FROM == "handheld"
# Запуск происходит когда в Run Pipeline передаем TEST_FROM == "handheld"
Запуск автотестов
При запуске сборки и деплоя микросервиса у нас автоматически стартуют автотесты:
Если автотесты пройдут с ошибками, билд будет обозначен как failed и подсветится красным. Таким образом команда разработки получит информацию о работоспособности данного конкретного билда системы. В случае, если вы не хотите «фейлить» деплой, а лишь подсветить, что прогон автотестов прошел с падениями, следует добавить allow_failure: true в джобу stage: test.
Если мы хотим запустить автотесты для дефолтных значений в нашем проекте с автотестами, мы переходим во вкладку CI/CD GitLab, нажимаем Run pipeline. В появившемся окне необходимо выбрать branch, а в Variables добавить TEST_FROM со значением handheld, нажать кнопку Run pipeline. В качестве результата вы получите прогон автотестов с меткой smoke_service_a и дефолтным URL https://rickandmortyapi.com/api.
Если вам нужна более гибкая настройка и нужен запуск ветки develop, метки smoke_service_b, файла с автотестами по пути tests/test_api.py::TestRickAndMortyApi и с определенным входным URL, это можно сделать так:
Нажимаете Run pipeline, получаете необходимый вам запуск автотестов. В чем плюс этого подхода — он даёт вам высокую гибкость относительно вариантов запуска.
Вместо вывода
Downstream pipelines предоставляет возможность взаимодействия нескольких проектов, а также возможность передачи необходимых переменных из одного проекта в другой, на основании чего вы можете строить необходимые вам зависимости. Вы добавляете модульности вашей системе и предоставляете готовое решение для автотестов. Для обновления схемы работы автотестов не нужно будет править несколько пайплайнов, а работать только с одним. И это сможет сделать команда автотестирования, которая отвечает за свой пайплайн.
Если вы используете один стенд для запуска автотестов, и прогон автотестов необходим при сборке одного сервиса, можно также использовать Downstream_pipelines для автономности проекта с автотестами.
Спасибо за внимание!
Полезные материалы для разработчиков мы также публикуем в наших соцсетях – ВКонтакте и Telegram.