Дымовые тесты и синтетические транзакции: проверка, что развёртывание действительно работает

Вы только что наблюдали, как ваш пайплайн позеленел. Модульные тесты пройдены, интеграционные тесты пройдены, даже сквозные тесты вернулись чистыми. Вы нажали «деплой», индикатор прогресса заполнился, и пайплайн сообщил об успехе. Но вот неприятная правда: ни один из этих тестов не выполнялся в реальной производственной среде. Все они запускались где-то ещё — на CI-раннере, на staging-сервере, на локальной машине. В тот момент, когда ваше приложение попадает на реальную инфраструктуру, всё может сломаться.

Именно для этого существуют дымовые тесты и синтетические транзакции. Они не заменяют ваш существующий набор тестов. Это отдельный слой, который отвечает на другой вопрос: не «корректен ли код?», а «сработало ли развёртывание на самом деле?»

Самая простая проверка: дымовой тест

Дымовой тест — это самое базовое, что можно сделать после развёртывания. Он отвечает на один вопрос: живо ли приложение и отвечает ли оно?

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

Для веб-приложения дымовой тест может быть одним HTTP-запросом к эндпоинту health check. Для бэкенд-сервиса — проверкой, что процесс запущен и слушает ожидаемый порт. Для мобильного приложения — проверкой, что оно запускается без краша на реальном устройстве.

Ключевые характеристики хорошего дымового теста — скорость и простота. Он должен выполняться за секунды, а не минуты. Он не должен зависеть от сложной бизнес-логики или внешних систем, которые могут быть временно недоступны. Если вашему дымовому тесту нужны подключение к БД, кеш-сервер и три сторонних API — это уже не дымовой тест, а что-то совсем другое.

Вот как выглядят практичный дымовой тест и синтетическая транзакция на bash:

# Smoke test: quick health check
curl -f -s -o /dev/null http://myapp.com/health || exit 1

echo "Smoke test passed"

# Synthetic transaction: simulate a user login and search
#!/bin/bash
set -e

BASE="http://myapp.com"

# Step 1: Load login page
curl -s -o /dev/null -w "%{http_code}" "$BASE/login" | grep -q 200 || exit 1

# Step 2: Submit login form (simulated)
curl -s -c /tmp/cookies.txt -b /tmp/cookies.txt \
  -d "username=testuser&password=testpass" \
  -o /dev/null -w "%{http_code}" "$BASE/login" | grep -q 302 || exit 1

# Step 3: Search for a product
curl -s -b /tmp/cookies.txt "$BASE/search?q=laptop" | grep -q "results" || exit 1

echo "Synthetic transaction passed"

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

Идём глубже: синтетические транзакции

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

Представьте приложение электронной коммерции. Синтетическая транзакция может:

  1. Открыть главную страницу
  2. Выполнить поиск товара
  3. Добавить товар в корзину
  4. Перейти к оформлению заказа
  5. Завершить процесс покупки

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

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

Типичный сценарий: дымовой тест проходит, потому что health check эндпоинт возвращает 200 OK. Но страница логина возвращает ошибку 500, потому что конфигурационный файл не был скопирован корректно во время развёртывания. Дымовой тест никогда не проверял страницу логина. Синтетическая транзакция поймала бы это сразу.

Где они размещаются в вашем пайплайне

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

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

Синтетическая транзакция запускается после прохождения дымового теста. Это ваша более глубокая проверка до того, как придёт пользовательский трафик. Если синтетическая транзакция не пройдена, у вас ещё есть время остановить развёртывание до того, как пользователи столкнутся с проблемой.

На практике вам не нужно много синтетических транзакций. Обычно достаточно двух-пяти сценариев, покрывающих наиболее критичные пути пользователей. Цель — не исчерпывающее тестирование (вы уже сделали это до развёртывания). Цель — подтвердить, что само развёртывание ничего не сломало.

Что эти тесты ловят, а другие пропускают

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

Дымовые тесты и синтетические транзакции запускаются в реальной производственной среде. Они ловят проблемы, которые проявляются только там:

  • Различия в конфигурации окружения между staging и продакшном
  • Отсутствующие зависимости или неверные версии в продакшне
  • Проблемы с правами доступа, существующие только в продакшн-аккаунте или кластере
  • Сетевые политики, блокирующие легитимный трафик
  • Проблемы с SSL-сертификатами
  • Неправильные конфигурации балансировщика нагрузки
  • Истощение пула соединений с БД в реальных условиях

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

Практический чек-лист

При внедрении дымовых тестов и синтетических транзакций в ваш пайплайн помните о следующем:

  • Держите дымовые тесты в пределах 10 секунд. Если они выполняются дольше, упростите их.
  • Размещайте дымовые тесты сразу после развёртывания, до маршрутизации трафика.
  • Останавливайте пайплайн при неудачном дымовом тесте. Не продолжайте.
  • Запускайте синтетические транзакции после прохождения дымовых тестов, до полного переключения трафика.
  • Ограничьте синтетические транзакции 2-5 критическими пользовательскими сценариями.
  • Не используйте синтетические транзакции для исчерпывающего тестирования. Для этого существуют ваши предварительные тесты.
  • Отслеживайте результаты синтетических транзакций с течением времени. Паттерн перемежающихся сбоев может указывать на скрытую проблему.
  • Убедитесь, что синтетические транзакции запускаются в реальной производственной среде, а не в staging-реплике.

Конкретный вывод

Ваши предварительные тесты проверяют, что ваш код корректен. Ваши дымовые тесты и синтетические транзакции проверяют, что ваше развёртывание прошло успешно. Это не одно и то же, и одно не может заменить другое. Зелёный пайплайн означает, что ваш код прошёл все проверки в контролируемой среде. Успешный дымовой тест означает, что ваше приложение действительно запущено в продакшне. Пройденная синтетическая транзакция означает, что ваши пользователи могут выполнить свои самые важные задачи. Добавьте и то, и другое в ваш пайплайн развёртывания, и вы будете ловить проблемы, которые проявляются только тогда, когда код встречается с реальностью.