惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

TaoSecurity Blog
TaoSecurity Blog
T
Troy Hunt's Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Vercel News
Vercel News
T
Threatpost
G
Google Developers Blog
T
Threat Research - Cisco Blogs
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
The Exploit Database - CXSecurity.com
H
Heimdal Security Blog
Google DeepMind News
Google DeepMind News
Cyberwarzone
Cyberwarzone
T
The Blog of Author Tim Ferriss
Know Your Adversary
Know Your Adversary
Hacker News: Ask HN
Hacker News: Ask HN
www.infosecurity-magazine.com
www.infosecurity-magazine.com
S
Schneier on Security
B
Blog
V2EX - 技术
V2EX - 技术
NISL@THU
NISL@THU
C
CERT Recently Published Vulnerability Notes
W
WeLiveSecurity
C
Cybersecurity and Infrastructure Security Agency CISA
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Y
Y Combinator Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Spread Privacy
Spread Privacy
The Last Watchdog
The Last Watchdog
V
Vulnerabilities – Threatpost
N
Netflix TechBlog - Medium
Schneier on Security
Schneier on Security
F
Fortinet All Blogs
N
News | PayPal Newsroom
Attack and Defense Labs
Attack and Defense Labs
Blog — PlanetScale
Blog — PlanetScale
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Microsoft Security Blog
Microsoft Security Blog
S
Security @ Cisco Blogs
人人都是产品经理
人人都是产品经理
爱范儿
爱范儿
P
Privacy & Cybersecurity Law Blog
P
Proofpoint News Feed
Project Zero
Project Zero
I
Intezer
罗磊的独立博客
H
Hackread – Cybersecurity News, Data Breaches, AI and More
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - Franky
SecWiki News
SecWiki News
Martin Fowler
Martin Fowler

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Автотестирование пайплайнов в GitLab CI: наш опыт и практика
Олег Иванов · 2026-05-04 · via Все публикации подряд на Хабре

Средний

12 мин

8.3K

Когда речь заходит про автотесты, первыми на ум приходят проверки для UI, API или для мобильных устройств. Однако автотесты нужны не только для проверки пользовательских сценариев. Они могут решать и менее очевидные, но не менее важные задачи, например проверять работу пайплайнов. Если одни и те же пайплайны используют сотни сервисов и библиотек, любая ошибка в них быстро выходит за пределы одного проекта. У многих команд одновременно могут сломаться сборки, релизы и привычный процесс разработки. В нашем случае такие пайплайны работали примерно для 700 сервисов и более 200 библиотечных репозиториев. Чтобы гарантировать работоспособность пайплайнов, мы пришли к идее покрытия их автотестами.

В статье я расскажу, как мы в Ozon покрывали тестами работу пайплайнов в GitLab CI, какие требования нужно было учесть и как в итоге были устроены end-to-end-тесты для таких сценариев.

Введение, или Как всё устроено

Всем привет! Меня зовут Олег, я ведущий инженер по тестированию в платформенной фронтенд-команде Ozon. Общая задача команды платформы состоит в том, чтобы ускорить процесс разработки и развёртывания проектов в компании. Наша команда (я буду называть её FE) предоставляет различные инструменты для других команд фронтенд-разработки: консольную утилиту для быстрого развёртывания проектов, фреймворк для разработчиков с различными конфигами и настройками пайплайнов и много всего остального. То есть фактически нашими пользователями являются другие фронтенд-разработчики Ozon.

Для начала коротко опишу, как у нас распределена ответственность за пайплайны и где именно находится та часть, которую мы тестируем. У нас в компании есть специальная команда релиз-инженеров (назовём её RE), которая в целом отвечает за работу CI/CD в Ozon и предоставляет пайплайны для разных языков разработки и конфигураций проектов. Такие общедоступные платформенные пайплайны лежат в специальном репозитории, и их используют все разработчики в Ozon. А команда FE отвечает за пайплайны для фронтенд-проектов, которые были построены на платформенных решениях. Эти пайплайны лежат в другом репозитории, уже в нашем пространстве GitLab. Мы предоставляем следующие виды пайплайнов:

  • для проектов сервисов;

  • для микрофронтендов;

  • для библиотек;

  • для библиотек с UI-компонентами.

В каждом из вышеперечисленных пайплайнов стандартные джобы от команды RE, такие как проверка наличия ошибок или создание релиза, дополняются специализированными fe-джобами от нашей команды, уникальными для каждого типа проекта. Примерами таких джоб могут быть сборка проекта, запуск линтеров или тестов.

Общие и фронтенд джобы в пайплайне проекта

Общие и фронтенд джобы в пайплайне проекта

Мир глазами разработчика

Давайте опишем сценарий использования, который совершает наш «клиент» — фронтенд-разработчик Ozon.

  • При инициализации нового проекта он запускает платформенную утилиту и, указывая в ней нужные настройки, разворачивает проект. В нём он сразу получает все готовые конфиги и в том числе настройки пайплайнов.

  • После этого разработчик добавляет в проекте нужную бизнес-логику и отправляет эти изменения в GitLab.

  • В GitLab CI в его проекте выполняются пайплайны, в которых, помимо прочего, отрабатывает логика наших платформенных fe-джоб.

В целом звучит несложно. А теперь это надо протестировать.

И как это тестировать?

Итак, у нас есть следующие вводные:

  • хочется протестировать работу fe-джоб на реальных пайплайнах, чтобы убедиться, что всё работает как ожидалось;

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

  • пользователи не используют напрямую платформенный fe-пайплайн — он подключается внутрь пайплайна от команды RE.

Подключение пайплайнов друг в друга

Подключение пайплайнов друг в друга

Пройдёмся по всем этим пунктам.

Запуск тестов в продовом окружении

Продовым окружением в данном случае будет обычный проект в GitLab, в котором будут запускаться пайплайны. По сути, это то, как выглядит стандартная разработка на проектах, — создание feature-веток, создание релизов, деплой в различные окружения и т. д. А тесты будут представлять собой end-to-end-сценарии на проверку логики работы джоб.

Запуск тестов на свежих изменениях

При внесении изменений в репозиторий с платформенными фронтенд-пайплайнами нам необходимо проверить, что на текущих изменениях всё работает корректно. Для этого мы должны встроить тесты в пайплайн нашего fe-проекта и запускать их на той же ветке.

Способ подключения пайплайнов

Как я писал выше, разработчики не используют напрямую платформенный fe-пайплайн, так как он является составной частью итогового общедоступного пайплайна от команды RE.

# pub/ci/.fe.gitlab-ci.yml

include:
  - local: ".common.gitlab-ci.yml"
  - project: 'fe/pipeline'
    ref: 'master'
    file: '/templates/fe.yml'

Выше приведён пример того, как в итоговый файл пайплайна подключаются два пайплайна: базовый пайплайн .common.gitlab-ci.yml от команды RE и наш fe-пайплайн. Как можно видеть, в параметре ref указана ветка master. Однако нам нужно будет использовать текущую feature-ветку в проекте fe/pipeline, на которой мы и хотим запустить тесты.

Дело ещё осложняется тем, что результирующий файл пайплайна находится в другом репозитории, и это приводит к следующим моментам:

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

  2. Чтобы изменить ветку с master на feature-ветку, нам придётся создавать тестовые ветки в чужом репозитории, чего лучше избегать.

  3. Результирующий пайплайн содержит дополнительные джобы с проверками качества кода и покрытия тестами, которые в нашем случае избыточны и будут нам только мешать при прохождении тестов.

Чтобы избежать всех этих сложностей, было решено не использовать в тестах напрямую результирующий пайплайн от команды RE, а брать только нашу часть из fe-пайплайна и точечно дополнять её до минимального рабочего состояния. Таким образом, мы будем полностью управлять тем, что попадёт в пайплайн в тестовом проекте, и избежим ненужных проверок и лишних джоб.

Как устроены тесты

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

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

Данные тесты написаны на языке Typescript, они хранятся в проекте с фронтенд-пайплайнами fe/pipeline и запускаются в нём же набором джоб. Каждая такая джоба запускает скрипт со своим тестом. Так как нужно проверить разные типы пайплайнов (для проектов, библиотек и т. д.), то под каждый случай создан отдельный скрипт и отдельная джоба по запуску.

Джобы по запуску тестов на пайплайны

Джобы по запуску тестов на пайплайны

Тестовые репозитории для выполнения пайплайнов

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

Схема работы тестовой джобы

Схема работы тестовой джобы

Особенности выполнения тестов

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

Стандартная разработка в Ozon выглядит так:

  • создание feature-ветки и соответствующего ей пайплайна;

  • создание релизной ветки и релизного пайплайна;

  • создание тегового пайплайна;

  • merge в master-ветку;

  • merge в develop-ветку.

Каждый тест проходит весь сквозной цикл работы пайплайнов, начиная с feature-веток и заканчивая пайплайном с мержем в master-ветку. При таком выполнении в рамках тестового репозитория не могут одновременно работать несколько тестов, так как они будут влиять на работу друг друга и мешать выполнению шагов и проверок. Какой отсюда вывод? Так как для каждого теста подготовлен отдельный тестовый репозиторий, нужно перед началом теста проверять, не занят ли этот репозиторий каким-то другим тестом. Такой подход позволяет всем тестам на пайплайны работать параллельно друг другу, тем самым ускоряя общее время прохождения тестов.

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

Для того чтобы проверить, не выполняется ли сейчас в тестовом репозитории какой-то тест из другой ветки, мы используем специальную переменную FE_PIPELINE_TESTS_LOCK, которую добавляем в GitLab Variables тестового репозитория. Изначально эта переменная пустая, важно лишь её наличие в проекте.

Когда тест начинает своё выполнение в репозитории, он записывает в переменную сгенерированное значение — id джобы с тестом и текущий timestamp. Перед тем как тест будет запущен, он получает значение данной переменной и проверяет его. Если переменная непустая и с момента последней записи прошло не больше максимального допустимого времени (оно задаётся в тестах), то это означает, что сейчас выполняется другой тест и репозиторий занят. В таком случае тест завершится с ошибкой.

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

Проверка и установка блокировки на тестовый репозиторий

Проверка и установка блокировки на тестовый репозиторий

Снятие блокировки с репозитория

В конце каждого теста нам необходимо снять блокировку с репозитория, то есть стереть выставленное значение из переменной GitLab FE_PIPELINE_TESTS_LOCK, чтобы другие тесты могли быть запущены. Однако ещё может быть ситуация, когда в результате какой-то ошибки либо при ручной остановке джобы тест прекратил своё выполнение, но блокировка с репозитория не была снята. Чтобы другие тесты не были заблокированы и нам не пришлось менять значение переменной FE_PIPELINE_TESTS_LOCK вручную, были добавлены отдельные джобы для снятия блокировок с тестовых репозиториев.

Джобы для снятия блокировок с репозиториев

Джобы для снятия блокировок с репозиториев

Таким образом, для каждого сценария у нас есть джоба по запуску теста и джоба по снятию блокировки. На практике в большинстве случаев блокировка снимается автоматически, даже если тест завершается с ошибкой. Но всё же наличие специальных джоб помогает в нестандартных ситуациях.

Подготовка проекта

Каждый тест вначале создаёт временную директорию, в которой будет настроено содержимое проекта. Так как платформенная команда FE предоставляет разработчикам утилиту для быстрого развёртывания проектов, в тестах мы используем непосредственно её. В конфигурационном файле указываем, какие настройки должны быть переданы в утилиту, и в зависимости от этих настроек в проект будет добавлен определённый набор файлов. Например, если утилита была запущена с настройкой для обычного проекта, будет добавлен пайплайн для сервисов, если с настройкой для библиотеки — будет добавлен пайплайн для библиотек и т. д. Таким образом, в зависимости от проверяемого сценария в проекте будет сформирован различный gitlab-ci.yml и, соответственно, будет различаться логика работы пайплайнов.

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

Также мы модифицируем файл gitlab-ci.yml — подключаем базовый платформенный пайплайн от команды RE, а в нашем fe-пайплайне заменяем ветку с master на текущую ветку, с которой запускаются тесты:

// Модификация файла пайплайна в тесте

const parsed = YAML.parseDocument(content)

parsed.setIn(['include'], [
	{
		project: 'pub/ci',
		ref: '0.0.6',
		file: '.common.gitlab-ci.yml', // базовый платформенный пайплайн
	},
	{
		project: 'fe/pipeline',
		ref: pipelineRef, // текущая ветка
		file: 'templates/fe.yml', // тестируемый fe-пайплайн
	},
	...(parsed.toJS().include).slice(1),
])

После того как файлы проекта сформированы, в созданной директории необходимо инициализировать git-репозиторий, создать ветку, добавить все файлы в индекс и отправить в remote-репозиторий (это как раз тот тестовый репозиторий, который был создан заранее).

Способы формирования содержимого тестового проекта

Способы формирования содержимого тестового проекта

После этого в тестовом репозитории будет автоматически запущен пайплайн, с которым начнёт работу код теста.

Откат до начального коммита

Как видно из описания, наши тесты модифицируют тестовый репозиторий, в котором разворачивается проект: создают в нём ветки и делают коммиты. Но для стабильной работы тестов необходимо, чтобы предыдущее их выполнение не оказывало влияния на последующие проверки. 

Для этого в тестах хранится хеш Initial-коммита для каждого тестового репозитория. Перед началом теста выполняется принудительный откат к данному коммиту, что очищает репозиторий до начального состояния. Это позволяет каждому тесту выполняться с чистого листа, как если бы никаких других тестов перед этим не было запущено.

Сторонние библиотеки и собственные хелперы

Для работы с GitLab в тестах мы подключаем одну из внешних библиотек, которая использует GItLab REST API. Данная библиотека предоставляет базовые методы по взаимодействию с пайплайнами, джобами, артефактами и т. д.

Однако чтобы сделать работу с тестами проще и надёжнее, нам пришлось написать собственные функции-хелперы поверх данной библиотеки. Примерами таких хелперов могут быть поиск пайплайна по заданному условию, запуск джобы по её имени и т. д.

// Пример хелпера для поиска релизного пайплайна

/**
 * Найти и дождаться завершения пайплайна на релизной ветке
 */
export const findAndWaitReleasePipeByTag = track(async function findAndWaitReleasePipeByTag({
	tag,
	access,
}: {
	tag: string
	access: ApiAccess
}) {
	const releaseBranch = `release/${tag}`
	const releaseSha = await getLatestCommit(releaseBranch, { access })
	const releasePipeId = await findAndWaitPipe({
		sha: releaseSha,
		branch: releaseBranch,
		access,
	})

	return {
		sha: releaseSha,
		pipeId: releasePipeId,
		branchName: releaseBranch,
	}
})

Отсутствие готового фреймворка для тестов

Как, наверное, стало понятно из всего вышенаписанного, данная задача по тестированию не является типовой. Тестовые фреймворки вида vitest или playwright в данном случае не подходят, так как каждый наш тест представляет собой одну большую последовательность действий с подготовкой проекта, ожиданием пайплайнов и джоб, выполнением проверок. Такие шаги нельзя запускать параллельно. Использовать стандартные библиотеки с проверками тоже не всегда удобно. В данном случае мы выносили все проверки в отдельный набор методов, внутри которых проверяли полученные данные и при несовпадении с ожидаемым поведением пробрасывали исключение. В таком случае джоба с запущенным тестом будет завершена с ошибкой.

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

Логи джобы при выполнении теста

Логи джобы при выполнении теста

Что проверяют тесты

Проверки сильно зависят от того, какой тип пайплайна используется в тестовом проекте.

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

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

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

Так как каждый тест выполняет проверки на нескольких ветках (для develop-пайплайна, release-пайплайна и т. д.), то его прохождение требует ощутимого количества времени. Наши тесты работают в диапазоне от 5 до 20 минут каждый. В это время входит очистка тестового репозитория, подготовка проекта, ожидание пайплайнов и джоб, выполнение проверок. Поэтому в end-to-end-тестах была цель проверять только самое необходимое, чтобы оптимизировать время выполнения тестов. В каждом тестовом сценарии был выбран набор критичных джоб, которые требуется проверить детально. Для таких джоб в тестах мы валидировали их логи, артефакты и делали проверки, специфичные под каждый случай. Для менее критичных джоб мы ограничивались проверкой статуса их выполнения в пайплайне.

// Фрагмент теста c проверкой fe-джобы для пайплайна библиотеки

// Запустить джобу 'fe npm canary' на релизном пайплайне и дождаться её завершения
const feNpmCanaryJobId = await runFeNpmCanary({
	pipeId: release.pipeId,
	access,
})

// Проверить логи джобы 'fe npm canary'
const canaryVersion = await checkFeCanaryLogs({
	jobId: feNpmCanaryJobId,
	pkg: {
		name: packageName,
		version: expectedCanaryVersion,
	},
	branchName: release.branchName,
	access,
})

// Проверить, что у джобы 'fe npm canary' в артефактах есть файл published.json,
// проверить содержимое файла published.json
await checkFeNpmCanaryArtifacts({
	jobId: feNpmCanaryJobId,
	packageName,
	version: canaryVersion,
	access,
})

// Проверить добавление пакета в артифактори
await expectPackageToBePublished(packageName, canaryVersion)

Общая схема работы тестов

Ниже приведена общая схема выполнения тестов на пайплайны (с некоторыми упрощениями).

Общая схема работы тестов

Общая схема работы тестов

Заключение

В итоге мы собрали рабочий подход к автотестированию пайплайнов GitLab. С его помощью мы регулярно прогоняем тесты, когда какие-либо изменения вносятся в репозиторий с платформенными фронтенд-пайплайнами. С одной стороны, это позволяет нам обеспечивать стабильность работы платформенных решений, которыми пользуются многие команды разработки в Ozon. А с другой стороны, экономит время на ручное выполнение подобных проверок, которые занимали несколько часов у разработчиков, теперь они выполняются в 10 раз быстрее. 

Итак, на что стоит обращать внимание при разработке похожих автотестов:

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

  • Управление состоянием тестовых репозиториев. Следует предусмотреть возможность отката до эталонного состояния перед выполнением теста, а также выполнять удаление лишних тестовых артефактов — созданных веток git, деплоев и т. д.

  • Тестовая инфраструктура. Не всегда получится использовать тестовые фреймворки и библиотеки «из коробки», особенно когда дело касается специфических областей применения. Написание удобных вспомогательных методов позволит сделать тесты читаемыми и легко поддерживаемыми.

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

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