Привет, Хабр! Меня зовут Андрей, я SDET-специалист SimbirSoft. В практике CI/CD один из общепринятых стандартов — настройка автоматического запуска автотестов при деплое сервиса на стенды. То есть при запуске сборки мы сразу видим, как пройдут смоук-автотесты, и на основе отчета решаем, передавать сборку дальше QA-команде или дорабатывать. Это упрощает работу команды и позволяет быстрее исправлять ошибки, что критично важно для бизнеса.

Работу над иллюстрацией мы тоже отчасти автоматизировали, создав ее с помощью нейросети Midjourney.
Работу над иллюстрацией мы тоже отчасти автоматизировали, создав ее с помощью нейросети Midjourney.

Мы разберем автоматический запуск автотестов с использованием 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.

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