Тестирование в YTsaurus Flow (C++)
Примечание
C++ воркеры на данный момент не имеют отдельного фреймворка для юнит-тестирования компьютейшенов: основной подход — запускать пайплайн целиком с конечными источниками данных. Пример теста можно найти в examples/cpp/wait_click_join. Если писать юнит тесты всё же необходимо, то можно выносить бизнес-логику из компьютейшнов в отдельные классы и писать юнит тесты уже на них.
Общие принципы написания интеграционных тестов на пайплайны:
- Тестируем конечные сценарии. То есть:
- Записываем входные/исходные данные в локальный YT.
- В спеке пайплайна отмечаем источники как
finite=%true. - Для Key-visitor-стрима, который должен работать во время теста, задаём
finite=%false. - Запускаем пайплайн.
- Когда визитор должен завершиться, вызываем метод базового класса интеграционного теста
self.ask_key_visitor_to_complete("<computation_id>", "<stream_id>"): он переключает динамический параметрfiniteэтого стрима на%true. - Ждём, пока пайплайн завершится.
- Проверяем выходные данные.
- Готовим окружение тем же кодом, что и в проде:
- Тестируем тот же бинарь пайплайна что будет работать в проде.
- Генерируем спеки пайплайна тем же кодом, что будет генерировать их для прода.
- Если входные/выходные данные нетривиально сериализуются/парсятся, то делаем эту работу общим с продом кодом.
- Используем общий тестовый фреймворк (есть
README.md). - Делаем failover тест.
- Многие ошибки вскрываются на выпадении воркеров и переподхвате их работы другими воркерами. Поэтому делаем тест с
problems=Trueи с более чем 1 воркером.
- Многие ошибки вскрываются на выпадении воркеров и переподхвате их работы другими воркерами. Поэтому делаем тест с
- Пишем стабильные тесты.
- Помним, что в CI любая часть теста может работать неожиданно долго.
- Идеальное время работы одного теста — 20 секунд при любом типе сборки.
- Для санитайзерных сборок уменьшаем количество входных данных.
- Все локальные таймауты выставляем с кратным запасом.
- Логика выполнения теста не должна значимо зависеть от текущего времени. Например, тест не должен падать, если запустился до полуночи, а завершился — после.
- Помним, что в CI любая часть теста может работать неожиданно долго.
Отладка тестов
Логи
После завершения работы теста его логи можно найти в test-results/py3test/testing_out_stuff в директории теста. Основные важные:
run.log— логи python-теста.<test_class_name>/<test_name>/Controller_<number>...— логи контроллеров (.err— это stderr процесса,.log— обычные логи, которые пишутся черезYT_LOG_...).<test_class_name>/<test_name>/Worker_<number>...— логи воркеров.<test_class_name>/<test_name>/Runner...— логи раннера.
Если что-то не работает, то имеет смысл поискать ошибки во всех этих логах. Принцип изучения логов такой же, как в рабочем пайплайне; см. логи Vanilla-операции.
Логи можно посмотреть ещё до завершения теста, для этого нужно найти временную директорию, в которой тест работает. Самый простой способ — запускать тест с флагом --keep-temps: ya make --keep-temps -ttt <target>. В этом случае ya make не удалит временную директорию по окончании теста и напечатает ссылку на неё в выводе.
Также можно воспользоваться такими bash-алиасами:
alias curtestdir="ps -f -u $USER | python3 -c \"import sys, re; drs = set(e for e in re.findall(r'[\s=](/\S*testing' + r'_out_stuff)\b', sys.stdin.read())); print('' if len(drs) == 1 else 'Select first from ' + repr(drs), file=sys.stderr); print(list(drs)[0])\""
alias cdcurtestdir='cd $(curtestdir)'
# Достать из логов ссылку на UI локального YTsaurus.
alias curlocalyt='cat $(curtestdir)/stderr 2>/dev/null | grep YT'
Тестовый фреймворк
Как настроить окружение для лучшей работы тестового фреймворка и как можно влиять на параметры тестирования можно прочитать в README.md фреймворка.
Поведение интеграционных тестов настраивается через --test-param NAME=VAL:
|
Параметр |
По умолчанию |
Значения |
Действие |
|
|
|
Уровень логирования процесса, запускающего пайплайн (runner). |
|
|
|
|
|
Зависнуть в тесте перед остановкой процессов Flow. В комбинации с |
|
|
(не задан) |
yson — см. ниже |
Запускать пайплайн на реальных внешних кластерах YTsaurus вместо локального рецепта. |
Примеры:
ya make -A --test-param RUNNER_LOG_LEVEL=Debug
ya make -A --test-disable-timeout --test-param PAUSE_BEFORE_FLOW_PROCESS_FEDERATION_TEARDOWN=1
EXTERNAL_YT_CONFIG
Локальный YTsaurus всё ещё стартует рецептом, но тест его игнорирует.
Обязательные поля, общие для всех кластеров:
path— базовая директория.tablet_cell_bundle— bundle создаваемых динамических таблиц.proxy_role— RPC proxy role.
Опционально: primary_medium (по умолчанию "default").
Список clusters — первый элемент primary. Поля записи: cluster_name (обязательно), proxy_url (по умолчанию равен cluster_name).
Авторизация: при внешнем YTsaurus YT_TOKEN/YT_USER из локального рецепта чистятся, yt-wrapper подхватывает токен из ~/.yt/token.
Изоляция: work_yt_path = path/<local-username>/<test_name>; директория path/<username> удаляется и пересоздаётся один раз на класс в setup_class.
Пример:
ya make -A --test-param 'EXTERNAL_YT_CONFIG={path="//tmp/yt_flow";tablet_cell_bundle=default;proxy_role=default;clusters=[{cluster_name=<cluster-name>};];}'