Respan Dataset Explorer

Select one behavior. Every returned turn has one binary label: Present or Absent. Source: final dense boolean release.

5,167,182physical rows
86shards
0.00%qualified row coverage
0.00%qualified cell coverage
Random row JSON API

turns-00020.parquet:55639

a1197b1cccbefb2db19dff13
turn 1/31gpt-4-0125-previewRussianRussia18866 words
degenerate_repetitionAbsentFinal dense release
USER
Ты технический писатель с опытом работы более 6 лет. твоя специализация написание документации для систем сборок: 1. Make
2. Maven
3. Gradle
4. Ant
5. CMake
6. MSBuild
7. npm / yarn
8. Gulp / Grunt
9. Webpack
10. Bazel
11. ninja
12. make
и других подобных систем.
Сейчас ты описываешь еще одну систему сборки. Вот принцип работы этой сборки:
“Базовые понятия системы сборки ya make
Что и как строится
Сборочная цель или модуль. Для того, чтобы запустить сборку надо указать какую программу, библиотеку или пакет надо собрать. Эта программа/библиотека/пакет и есть сборочная цель. Понимать сборочную цель можно двояко — это и артефакт — реальный результат сборки (собственно файл программы или библиотеки, файл или директория с файлами пакета), и описание сборки — ya.make с описанием сборки.

Примечание
Не каждая сборочная цель порождает артефакт. Строить такую цель непосредственно имеет мало смысла, но от неё можно зависеть, и эта зависимость может приносить дополнительные свойства, например сборочные флаги, в другие сборочные цели, которые от неё зависят.
В любом случае сборочная цель указывается своей директорией. В этой директории в файле ya.make описано что будет собираться и как это надо собирать. Туда же по умолчанию будут сложены символьными ссылками результаты сборки. В системе сборки ya make принято общее правило одна директория — одна сборочная цель. В каждой директории сборка описывается только в файле ya.make и каждый файл ya.make содержит описание сборки не более чем одного модуля. Это правило неявно нарушается только в двух случаях:

Часть сборочных целей является мультимодулями — специальными целями, которые могут быть разными модулями в зависимости от контекста использования.
Часть сборочных целей могут неявно добавлять для себя проверки, они не описываются явно, но будут построены как тесты вместе с модулем, если запрошен запуск тестов.
При непосредственной сборке сборочные цели указываются параметрами команды ya make <target1> <target2>. Если цель не указана явно, то ею является текущая директория.

Не запускайте ya make в корневой директории репозитория. Это приведёт к попытке построить всю Аркадию, что вряд ли получится и вряд ли нужно.
Кроме непосредственной сборки явным перечислением целей, несколько целей могут быть собраны вместе. Это достигается указанием целей в макросе семейства RECURSE в ya.make. Макрос не делает цели зависимыми, он лишь позволяет собрать несколько целей одновременно, например, все бинарные файлы сервиса или тесты вместе с библиотекой. Один ya.make может содержать и описание сборки модуля и RECURSE на другие сборочные цели, которые надо собрать вместе с этим модулем. Чтобы ограничить сборку только непосредственной служит ключ --ignore-recurses команды ya make.
Модули могут быть финальными и промежуточными. Финальные модули — программы, динамические библиотеки, тесты и т.п. могут исполняться и независимо распространяться. Промежуточные модули — библиотеки используются для сборки финальных модулей. В ya make используется статическая линковка и потому Финальные модули всегда замкнуты, т.е. их сборка вызывает сборку всех модулей, от которых они зависят по PEERDIR и их результаты самодостаточны. Даже в Java, где связывание всегда динамическое, JAVA_PROGRAM эмулирует замкнутый артефакт — в результаты сборки попадают все необходимые зависимости, а также скрипт для запуска java-программы.
Промежуточные модули могут вызывать сборку своих PEERDIR-зависимостей, но только если это необходимо для их собственной сборки. Так в Java и Go сборка пакета требует на вход собранных зависимостей. Однако в С++ и Python сборка модуля не использует результаты сборки зависимостей (хотя может использовать их свойства), и потому при сборке библиотеки в С++ и Python зависимые библиотеки не будут собираться. Они соберутся только при сборке программы или теста, которые (транзитивно) зависят от библиотеки. Все зависимости на промежуточные модули транзитивно замыкаются по PEERDIR в финальных модулях, независимо от языка этих модулей.
Подробней про значимости можно прочитать ниже
Что такое конфигурирование
Первое, что вы увидите, запустив сборку в Аркадии, будет что-то вроде
Configuring dependencies for platform default-linux-x86_64-debug
потом будет ещё
Configuring dependencies for platform tools
и только потом побежит прогресс собственно сборки. Что же такое конфигурирование в этом сообщении и что такое платформы?
Конфигурирование в нашей системе сборки — это процесс анализа зависимостей и построения графа сборочных команд. Подробнее про это можно почитать в разделе как работает система сборки, но вкратце система сборки во время конфигурирования решает 3 основные задачи:
Обнаружение изменений. Первое что надо понять системе сборки — это что изменилось со времени последней пересборки. Система сборки ya make делает это двумя разными способами и в два разных момента времени.
Сначала она в соотвествии с описаниями сборки ищет что поменялось на файловой системе. Простой и частый случай — это изменение исходного файла, более сложные случаи — это изменение ya.make или изменение состава файлов для указанного в сборке шаблона (glob-выражения). Эта информация помогает ей не делать полностью анализ зависимостей, а использовать кэш зависимостей.
В самом конце, когда уже построен граф сборочных команд, каждая команда получает уникальный идентификатор (UID), который, в частности, является ключом в кэше результатов. Таким образом даже если кэш зависимостей недоступен или явно запрошено конфигурирование без кэша, сборка всё равно будет инкрементальной — всё, что уже строилось и есть в кэше результатов перестроено не будет.
Анализ зависимостей. Наша система сборки устроена таким образом, что каждая команда ещё до своего исполнения знает всё, от чего она зависит. Это знание конденсируется в её UID. И это не только текст команды и содержимое её входных файлов. Зависимости между файлами тоже учитываются. Поэтому анализ зависимостей — это не только считывание всех нужных ya.make-файлов. Это ещё и
Анализ (парсинг) исходных файлов в поисках межфайловых зависимостей.
Хэширование всех файлов для фиксации их содержимого и обнаружения изменений при следующих сборках.
Распространение и уточнение свойств по межмодульным зависимостям (например, dependency management в Java), формирование транзитивных списков зависимостей (например, списка библиотек для линковки программ).
Расчёт влияния зависимостей на сборочные команды и вычисление UID. Уникальный идентификатор — это хэш от всего, что может повлиять на функциональный результат команды (т.е. изменить результат так, что он будет работать по-другому). Мы не стремимся к бинарной воспроизводимости результатов исполнения команд. В UID засчитывается текст команды со всеми её аргументами, имена и содержимое всех файлов, которые нужны команде, включая зависимые по include/import. Если на вход команде A подаётся результат исполнения команды B, то в UID(A) засчитывается UID(B).
Построение Графа сборочных команд или сборочного графа. Результатом процесса конфигурирования является граф сборочных команд — это граф, в узлах которого расположена информация о сборочных командах. Она включает собственно текст команд, имена результатов их работы, требования, служебную информация для отображения в процессе сборки и в CI и т.п. Связи в графе — это отношение производитель-потребитель. Узел команды-потребителя связан исходящими дугами с узлами команд-производителей, результаты которых потребитель принимает на вход. Ключом в графе является UID, поэтому зависимости в узле — это просто список UID-ов. В графе команд выделены входы — результаты исполнения этого графа (собственно сборки). Относительно этих входов граф всегда замкнут т.е. содержит всю необходимую информацию для построения результатов. Это включает как команды собственно сборки для целевой платформы, так и команды сборки инструментов для сборочной платформы, которые после будут использованы прямо в этой же сборки как части команд. Граф может быть сериализован и исполнен не там, где его строили, важно лишь, чтобы часть графа относящаяся к платформе сборки соответствовала реальной платформе, на которой его будут исполнять.
Платформы и конфигурации
Важным понятием при конфигурировании является платформа или, более точно, сборочная конфигурация.
Под словом платформа обычно понимается аппаратная конфигурация, операционная система и системное окружение на которой исполняется какой-то код. При исполнении системы сборки таких платформ может быть выделено три:
реальная платформа конфигурирования — это та платформа, где запускается собственно конфигурирование (команда ya make). Там исполняется сама система сборки как минимум при конфигурировании. Мы поддерживаем в качестве таких платформ Intel x86-64 Linux, IBM PowerPC LInux, Intel x86-64 macOS, Apple m1 macOS через Rosetta 2, Apple m1 macOS (в экспериментальном режиме), Intel x86-64 Windows.
реальная сборочная (или host) платформа — это та платформа, где исполняется сборка. На этой платформе работает часть системы сборки, отвечающая за исполнение сборочного графа а также сборочные инструменты (как загружаемые в сборку бинарно, так и строящиеся в ней же). Поскольку наш сборочный граф можно отдельно построить и отдельно исполнить, то эта платформа не обязана совпадать с предыдущей. Набор поддерживаемых платформ здесь тот же, что и выше, но поскольку инструменты загружаются или строятся в сборочном графе, при конфигурировании можно указать альтернативную предписанную сборочную платформу флагом --host-platform.
реальная целевая платформа — это та платформа, где будет исполняться собранный код. Система сборки ya make поддерживает кросс-сборку и набор целевых платформ очень широк. Более того, в рамках одной сборки можно построить код сразу под несколько предписанных целевых платформ указав несколько раз параметр --target-platform или добавив платформы в ya.conf.

Примеры:
ya make -r Собирает текущую директорию в режиме выпуска
ya make -t -j16 library Собирает и тестирует библиотеку с 16 потоками
ya make --checkout -j0 Выполняет чекаут отсутствующих директорий без сборки
”
Файл справки этой системы сборки
“
Опции:
Управление операциями Ya
-h, --help Печатает справку. Используйте -hh для большего количества опций и -hhh для ещё большего.
–rebuild Пересобрать все
-C=BUILD_TARGETS, --target=BUILD_TARGETS
Цели для сборки
-k, --keep-going Продолжать сборку насколько это возможно
-j=BUILD_THREADS, --threads=BUILD_THREADS
Количество потоков сборки (по умолчанию: 2)
–clear Очистить временные данные
Продвинутые опции
–sandboxing Запуск команды в изолированном корневом исходнике
–link-threads=LINK_THREADS
Количество потоков линковки (по умолчанию: 0)
–no-clonefile Отключить опцию clonefile
–nice=SET_NICE_VALUE
Задать значение nice для процессов сборки (по умолчанию: 10)
–warning-mode=WARN_MODE
Режим предупреждений
Экспертные опции
–fetcher-params=FETCHER_PARAMS_STR
Приоритеты и параметры фетчеров
-B=CUSTOM_BUILD_DIRECTORY, --build-dir=CUSTOM_BUILD_DIRECTORY
Пользовательская директория сборки (определяется автоматически по умолчанию)
–force-use-copy-instead-hardlink-macos-arm64
Использовать копирование вместо hardlink, когда clonefile недоступен
–no-content-uids Отключить дополнительный кеш на основе динамических uid только по содержанию
–keep-temps Не удалять временные корни сборки. Выводить рабочую директорию теста в stderr (используйте --test-stderr, чтобы убедиться, что она выводится в начале теста)
Селективный чекаут
Продвинутые опции
–prefetch Предварительно загружать директории, необходимые для сборки
–no-prefetch Не предварительно загружать директории, необходимые для сборки
Экспертные опции
–thin Чекаут минимального скелета
Выход сборки
–add-result=ADD_RESULT
Обрабатывать выбранный выход сборки как результат
–add-protobuf-result
Обрабатывать выход protobuf как результат
–add-flatbuf-result
Обрабатывать выход flatbuf как результат
–replace-result Собирать только цели --add-result
–force-build-depends
Собирать в любом случае по DEPENDS
–ignore-recurses Не собирать по RECURSES
–no-src-links Не создавать символические ссылки в исходной директории
-o=OUTPUT_ROOT, --output=OUTPUT_ROOT
Директория с результатами сборки
Продвинутые опции
-I=INSTALL_DIR, --install=INSTALL_DIR
Путь для накопления результирующих бинарников и библиотек
Экспертные опции
–add-host-result=ADD_HOST_RESULT
Обрабатывать выбранный выход сборки хоста как результат
–all-outputs-to-result
Обрабатывать все выходы ноды вместе с выбранным выходом сборки как результат
–add-modules-to-results
Обрабатывать все модули как результаты
–strip-packages-from-results
Удалять все пакеты из результатов
–no-output-for=SUPPRESS_OUTPUTS
Не создавать символические ссылки/копировать выход для файлов с данным суффиксом, они могут все равно быть сохранены в кеше как результат
–with-credits Включить генерацию файла CREDITS
Вывод
–stat Показать статистику выполнения сборки
-v, --verbose Выводить подробную информацию
-T Не перезаписывать информацию о выводе (ninja/make)
Продвинутые опции
–show-command=SHOW_COMMAND
Печатать команду для выбранного выхода сборки
–show-timings Печатать время выполнения команд
–show-extra-progress
Печатать дополнительную информацию о прогрессе
–log-file=LOG_FILE Добавить подробный журнал в указанный файл
Экспертные опции
–stat-dir=STATISTICS_OUT_DIR
Дополнительная директория вывода статистики
–no-emit-status Не выводить статус
–do-not-output-stderrs
Не выводить stderr
–mask-roots Маскировать пути к исходному и сборочному корню в stderr
–no-mask-roots Не маскировать пути к исходному и сборочному корню в stderr
–html-display=HTML_DISPLAY
Альтернативный вывод в формате html
–teamcity Генерировать дополнительную информацию для teamcity
Конфигурация платформы/сборки
-d Отладочная сборка
-r Сборка выпуска
–build=BUILD_TYPE Тип сборки (debug, release, profile, gprof, valgrind, valgrind-release, coverage, relwithdebinfo, minsizerel, debugnoasserts, fastdebug) https://docs.yandex-team.ru/ya-make/usage/ya_make/#build-type (по умолчанию: debug)
–sanitize=SANITIZE Тип санитайзера (address, memory, thread, undefined, leak)
–race Сборка проектов Go с детектором гонок
-D=FLAGS Установить переменные (имя[=значение], “yes” если значение опущено)
–host-platform-flag=HOST_PLATFORM_FLAGS
Флаг платформы хоста
–target-platform=TARGET_PLATFORMS
Целевая платформа
–target-platform-flag=TARGET_PLATFORM_FLAG
Установить флаг сборки для последней целевой платформы
Продвинутые опции
–sanitizer-flag=SANITIZER_FLAGS
Дополнительный флаг для санитайзера
–lto Сборка с LTO
–thinlto Сборка с ThinLTO
–afl Использовать AFL вместо libFuzzer
–musl Сборка с musl-libc
–hardening Сборка с усилением защиты
–cuda=CUDA_PLATFORM
Платформа CUDA (optional, required, disabled) (по умолчанию: optional)
–host-build-type=HOST_BUILD_TYPE
Тип сборки платформы хоста (debug, release, profile, gprof, valgrind, valgrind-release, coverage, relwithdebinfo, minsizerel, debugnoasserts, fastdebug) https://docs.yandex-team.ru/ya-make/usage/ya_make/#build-type (по умолчанию: release)
–host-platform=HOST_PLATFORM
Платформа хоста
–c-compiler=C_COMPILER
Указывает путь к пользовательскому компилятору для платформ хоста и цели
–cxx-compiler=CXX_COMPILER
Указывает путь к пользовательскому компилятору для платформ хоста и цели
–pgo-add Создать PGO профиль
–pgo-use=PGO_USER_PATH
Путь к PGO профилям
–pic Принудительный режим PIC
–maps-mobile Включить конфигурационный пресет mapsmobi
Экспертные опции
–sanitize-coverage=SANITIZE_COVERAGE
Включить покрытие санитайзером
–target-platform-build-type=TARGET_PLATFORM_BUILD_TYPE
Установить тип сборки для последней целевой платформы
–target-platform-release
Установить тип сборки выпуска для последней целевой платформы
–target-platform-debug
Установить отладочный тип сборки для последней целевой платформы
–target-platform-tests
Запустить тесты для последней целевой платформы
–target-platform-test-size=TARGET_PLATFORM_TEST_SIZE
Запустить тесты только с заданным размером для последней целевой платформы
–target-platform-test-type=TARGET_PLATFORM_TEST_TYPE
Запустить тесты только с заданным типом для последней целевой платформы
–target-platform-regular-tests
Запустить только тесты типов “benchmark boost_test exectest fuzz g_benchmark go_bench go_test gtest hermione java jest py2test py3test pytest unittest” для последней целевой платформы
–target-platform-c-compiler=TARGET_PLATFORM_COMPILER
Указывает путь к пользовательскому компилятору для последней целевой платформы
–target-platform-cxx-compiler=TARGET_PLATFORM_COMPILER
Указывает путь к пользовательскому компилятору для последней целевой платформы
–target-platform-target=TARGET_PLATFORM_TARGET
Цели сборки относительно корня исходного кода для последней целевой платформы
–target-platform-ignore-recurses
Не собирать по RECURSES
Локальный кеш
–cache-stat Показать статистику кеша
–gc Удалить весь кеш, кроме uid из текущего графа
–gc-symlinks Удалить все результаты символических ссылок, кроме файлов из текущего графа
Продвинутые опции
–tools-cache-size=TOOLS_CACHE_SIZE
Максимальный размер кеша инструментов (по умолчанию: 30.0GiB)
–symlinks-ttl=SYMLINKS_TTL
Срок хранения кеша результатов (по умолчанию: 168.0ч)
–cache-size=CACHE_SIZE
Максимальный размер кеша (по умолчанию: 140.04687070846558GiB)
–cache-codec=CACHE_CODEC
Кодек кеша (по умолчанию: )
–auto-clean=AUTO_CLEAN_RESULTS_CACHE
Автоматическая очистка кеша результатов (по умолчанию: True)
YT кеш
–no-yt-store Отключить хранилище YT
Продвинутые опции
–dist-cache-evict-bins
Удалить все нерабочие бинарные файлы из результатов сбоки. Работает только в режиме --bazel-remote-put
–dist-cache-evict-cached
Не собирать или не загружать результаты сборки, если они присутствуют в dist кеше
–dist-store-threads=DIST_STORE_THREADS
Максимальное количество потоков dist store (по умолчанию: 4)
–bazel-remote-store
Использовать хранилище Bazel-remote
–no-bazel-remote-store
Отключить хранилище Bazel-remote
–bazel-remote-base-uri=BAZEL_REMOTE_BASEURI
Базовый URI Bazel-remote (по умолчанию: http://[::1]:8080/)
–bazel-remote-username=BAZEL_REMOTE_USERNAME
Имя пользователя Bazel-remote
–bazel-remote-password=BAZEL_REMOTE_PASSWORD
Пароль Bazel-remote
–bazel-remote-password-file=BAZEL_REMOTE_PASSWORD_FILE
Файл с паролем Bazel-remote
–yt-store Использовать хранилище YT
–yt-store-threads=YT_STORE_THREADS
Максимальное количество потоков хранилища YT (по умолчанию: 1)
Экспертные опции
–yt-token-path=YT_TOKEN_PATH
Путь к токену YT (по умолчанию: /home/mtv2000/.yt/token)
YT кеш загрузки
Экспертные опции
–yt-put Загрузить в хранилище YT
–yt-max-store-size=YT_MAX_CACHE_SIZE
Максимальный размер хранилища YT
–yt-store-ttl=YT_STORE_TTL
Время жизни хранилища YT в часах (0 для бесконечности) (по умолчанию: 24)
–bazel-remote-put Загрузить в хранилище Bazel-remote
–yt-write-through=YT_STORE_WT
Обновлять локальный кеш при обновлении хранилища YT (по умолчанию: True)
–yt-create-tables Создать таблицы хранилища YT
–yt-store-filter=YT_CACHE_FILTER
Фильтр хранилища YT
–yt-store-codec=YT_STORE_CODEC
Кодек хранилища YT
–yt-store-exclusive
Использовать хранилище YT исключительно (прервать сборку, если требуемые данные не представлены в хранилище YT)
–yt-replace-result Собирать только цели, которые нужно загружать в хранилище YT
–yt-replace-result-add-objects
Настроить опцию yt-replace-result: добавить объектные (.o) файлы к результатам сборки. Бесполезно без --yt-replace-result
–yt-replace-result-rm-binaries
Настроить опцию yt-replace-result: удалить все нерабочие бинарные файлы из результатов сборки. Бесполезно без --yt-replace-result
–yt-replace-result-yt-upload-only
Настроить опцию yt-replace-result: добавить в результаты только узлы загрузки в YT. Бесполезно без --yt-replace-result
Функциональные флаги
Экспертные опции
–no-local-executor Использовать Popen вместо локального исполнителя
–dir-outputs-test-mode
Включить новые функции dir outputs
–disable-runner-dir-outputs
Отключить поддержку dir_outputs в исполнителе
–no-dump-debug Отключить режим дампа отладки
Тестирование
Запуск тестов
-t, --run
-tests Запустить тесты (-t запускает только SMALL тесты, -tt запускает SMALL и MEDIUM тесты, -ttt запускает SMALL, MEDIUM и FAT тесты)
-A, --run-all-tests Запустить наборы тестов всех размеров
-L, --list-tests Перечислить тесты
Продвинутые опции
–test-threads=TEST_THREADS
Ограничение на одновременные тесты (без ограничений по умолчанию) (по умолчанию: 0)
–fail-fast Прекратить после первого сбоя теста
Экспертные опции
–add-peerdirs-tests=PEERDIRS_TEST_TYPE
Типы тестов Peerdirs (none, gen, all) (по умолчанию: none)
–split-factor=TESTING_SPLIT_FACTOR
Переопределяет SPLIT_FACTOR(X) (по умолчанию: 0)
–test-prepare Не запускать тесты, только подготовить зависимости и среду для тестов
–no-src-changes Не изменять исходный код
Фильтрация
-X, --last-failed-tests
Перезапустить тесты, которые не прошли при последнем запуске для выбранной цели
-F=TESTS_FILTERS, --test-filter=TESTS_FILTERS
Запустить только тест, соответствующий <tests-filter>.
Звездочка ‘’ может быть использована в фильтре для соответствия подмножествам тестов.
Чанки также могут быть отфильтрованы с использованием шаблона, соответствующего '[] chunk’
–style Запустить только стилевые тесты и подразумевает --strip-skipped-test-deps (classpath.clash clang_tidy eslint gofmt govet java.style ktlint py2_flake8 flake8 black). Противоположность --regular-tests
–regular-tests Запустить только обычные тесты (benchmark boost_test exectest fuzz g_benchmark go_bench go_test gtest hermione java jest py2test py3test pytest unittest). Противоположность --style
Продвинутые опции
–test-size=TEST_SIZE_FILTERS
Запустить только определенный набор тестов
–test-type=TEST_TYPE_FILTERS
Запустить только определенные типы тестов
–test-tag=TEST_TAGS_FILTER
Запустить тесты с указанным тегом
–test-filename=TEST_FILES_FILTER
Запустить только тесты с указанными именами файлов (только для pytest и hermione)
–test-size-timeout=TEST_SIZE_TIMEOUTS
Установить тайм-аут теста для каждого размера (small=60, medium=600, large=3600)
Отчет в консоли
-P, --show-passed-tests
Показать пройденные тесты
Продвинутые опции
–inline-diff Отключить обрезку комментариев и печатать diff в терминале
–show-metrics Показывать метрики в консоли (Вам нужно добавить опцию “-P”, чтобы видеть метрики для пройденных тестов)
Linters
Продвинутые опции
–disable-flake8-migrations
Включить все проверки flake8
–disable-jstyle-migrations
Включить все проверки стиля java
Канонизация
-Z, --canonize-tests
Канонизировать выбранные тесты
Продвинутые опции
–canon-diff=TEST_DIFF
Показать различия канонических данных теста, допустимые значения: r<revision>, rev1:rev2, HEAD, PREV
Экспертные опции
–canonize-via-skynet
использовать skynet для загрузки больших канонических данных
–canonize-via-http использовать http для загрузки больших канонических данных
Отладка
–pdb Запустить pdb при ошибках
–gdb Запустить c++ unittests в gdb
–dlv Запустить go unittests в dlv
–test-debug Режим отладки теста (печатает pid теста после запуска и подразумевает --test-threads=1 --test-disable-timeout --retest --test-stderr)
Продвинутые опции
–dlv-args=DLV_ARGS Дополнительные аргументы командной строки dlv. Не действует, если не указан --dlv
–test-retries=TESTS_RETRIES
Запускать каждый тест указанное количество раз (по умолчанию: 1)
–test-stderr Выводить stderr теста в консоль онлайн
–test-stdout Выводить stdout теста в консоль онлайн
–test-disable-timeout
Отключить тайм-аут для тестов (только для локальных запусков, не совместимо с --cache-tests, --dist)
–test-binary-args=TEST_BINARY_ARGS
Передать аргументы в тестируемый бинарный файл
–dump-test-environment
Вывести содержимое корня сборки теста в формате дерева в файл run_test.log перед выполнением оболочки теста
Экспертные опции
–no-random-ports Использовать запрошенные порты
–disable-test-graceful-shutdown
Узел теста будет немедленно убит после тайм-аута
Среда выполнения
–test-param=TEST_PARAMS
Произвольные параметры, передаваемые тестам (name=val)
–autocheck-mode Запустить тесты локально с ограничениями autocheck (подразумевает --private-ram-drive и --private-net-ns)
Продвинутые опции
–private-ram-drive Создает частный ram диск для всех узлов тестирования, запрашивающих его
–private-net-ns Создает частное сетевое пространство имен с поддержкой localhost
Экспертные опции
–arcadia-tests-data=ARCADIA_TESTS_DATA_PATH
Пользовательский путь к arcadia_tests_data (по умолчанию: arcadia_tests_data)
Расчет uid теста
–cache-tests Использовать кеш для тестов
–retest Не использовать кеш для тестов
Зависимости тестов
-b, --build-all Собрать цели, не требуемые для запуска тестов, но доступные с RECURSE
Экспертные опции
–strip-skipped-test-deps
Не собирать зависимости пропущенных тестов
–build-only-test-deps
Собрать только цели, требуемые для запрошенных тестов
–strip-idle-build-results
Удалить все результатные узлы (включая узлы сборки), не требуемые для запуска тестов
–no-strip-idle-build-results
Не удалять все результатные узлы (включая узлы сборки), не требуемые для запуска тестов
Отчеты о файлах
–junit=JUNIT_PATH Путь к генерируемому junit отчету
Продвинутые опции
–allure=ALLURE_REPORT (устарело)
Путь к генерируемому отчету allure
Выводы тестов
Экспертные опции
–no-test-outputs Не сохранять testing_out_stuff
–no-dir-outputs (устарело)
Упаковать директорию вывода тестирования в промежуточные механизмы
–dir-outputs-in-nodes
Включить поддержку dir outputs в узлах
–keep-full-test-logs
Не укорачивать логи на distbuild
–test-node-output-limit=TEST_NODE_OUTPUT_LIMIT
Указывает ограничение на файлы вывода (в байтах)
–test-keep-symlinks
Не удалять символические ссылки из вывода теста
Тесты через YT
–run-tagged-tests-on-yt
Запускать тесты с тегом ya:yt на YT
Тесты через Sandbox
–run-tagged-tests-on-sandbox
Запускать тесты с тегом ya:force_sandbox в Sandbox
Покрытие
–python-coverage Собирать информацию о покрытии для python
–ts-coverage Собирать информацию о покрытии для ts
–go-coverage Собирать информацию о покрытии для go
–java-coverage Собирать информацию о покрытии для java
–clang-coverage Покрытие на основе исходного кода clang (автоматически увеличивает время ожидания тестов в 1,5 раза)
–coverage-report Создать HTML отчет о покрытии (использовать с --output)
–nlg-coverage Собирать информацию о покрытии для Alice NLG
Продвинутые опции
–coverage (устарело)
Собирать информацию о покрытии. (устаревший псевдоним для “–gcov --java-coverage --python-coverage --coverage-report”)
–coverage-prefix-filter=COVERAGE_PREFIX_FILTER
Исследовать только соответствующие пути
–coverage-exclude-regexp=COVERAGE_EXCLUDE_REGEXP
Исключить соответствующие пути из отчета о покрытии
–sancov Собирать информацию о покрытии санитайзером (автоматически увеличивает время ожидания тестов в 1,5 раза)
–fast-clang-coverage-merge
Объединять профили в памяти во время выполнения теста с использованием fuse
–enable-java-contrib-coverage
Добавить исходники и классы из contib/java в отчет jacoco
–enable-contrib-coverage
Собирать contrib с опциями покрытия и добавлять тесты coverage.extractor для бинарных файлов contrib
Экспертные опции
–coverage-report-path=COVERAGE_REPORT_PATH
Путь внутри директории вывода, куда сохранять отчет о покрытии gcov cpp (использовать с --output)
–merge-coverage Объединить все разрешенные файлы покрытия в один файл
–upload-coverage Загрузить собранное покрытие в YT
–coverage-verbose-resolve
Печатать отладочные логи на этапе разрешения покрытия
Fuzzing
–fuzzing Расширить корпус тестов. Подразумевает --sanitizer-flag=-fsanitize=fuzzer
–fuzz-case=FUZZ_CASE_FILENAME
Указать путь к файлу с данными для фаззинга (конфликтует с “–fuzzing”)
Продвинутые опции
–fuzz-opts=FUZZ_OPTS
Строка разделенных пробелом опций фаззинга (по умолчанию: )
–fuzz-minimization-only
Позволяет запустить минимизацию без фаззинга (должно быть использовано с “–fuzzing”)
–fuzz-local-store Не загружать в кеш mined корпус
–fuzz-runs=FUZZ_RUNS
Минимальное количество отдельных запусков тестов
–fuzz-proof=FUZZ_PROOF
Позволяет запустить дополнительный этап фаззинга на указанное количество секунд с момента последнего найденного случая, чтобы доказать, что больше ничего не будет найдено (по умолчанию: 0)
–fuzz-minimize Всегда запускать узел минимизации после этапа фаззинга
Специфика pytest
–test-log-level=TEST_LOG_LEVEL
Указывает уровень журналирования для вывода логов тестов (“critical”, “error”, “warning”, “info”, “debug”)
Продвинутые опции
–test-traceback=TEST_TRACEBACK
Стиль трассировки теста для pytests (“long”, “short”, “line”, “native”, “no”) (по умолчанию: short)
–profile-pytest Профилировать pytest (выводит cProfile в stderr и генерирует ‘pytest.profile.dot’ с использованием gprof2dot в директории testing_out_stuff)
–pytest-args=PYTEST_ARGS
Дополнительные опции командной строки pytest (по умолчанию: [])
Специфика тестов Java
Продвинутые опции
-R=PROPERTIES, --system-property=PROPERTIES
Установить системное свойство (name=val)
–system-properties-file=PROPERTIES_FILES
Загрузить системные свойства из файла
–jvm-args=JVM_ARGS Добавить аргументы jvm для запуска jvm
Специфика hermione
–hermione-config=HERMIONE_CONFIG
Путь к файлу конфигурации
–hermione-browser=HERMIONE_BROWSERS
Запустить тесты только в указанном браузере
Продвинутые опции
–hermione-grep=HERMIONE_GREP
Запустить тесты, соответствующие указанному шаблону
–hermione-test-path=HERMIONE_TEST_PATHS
Запустить тесты, находящиеся в указанных файлах (пути должны быть относительными по отношению к cwd)
–hermione-set=HERMIONE_SETS
Запустить тесты только в указанном наборе
–hermione-gui Запустить hermione в режиме графического интерфейса
–hermione-gui-auto-run
Автоматически запустить тесты в режиме графического интерфейса сразу после запуска
–hermione-gui-no-open
Не открывать окно браузера после запуска сервера в режиме графического интерфейса
–hermione-gui-hostname=HERMIONE_GUI_HOSTNAME
Хостнейм для запуска сервера в режиме графического интерфейса
–hermione-gui-port=HERMIONE_GUI_PORT
Порт для запуска сервера в режиме графического интерфейса
Специфика JUnit
Продвинутые опции
–junit-args=JUNIT_ARGS
Дополнительные опции командной строки JUnit
Продвинутое использование:
Продвинутые опции
–strict-inputs (устарело)
Включить строгий режим
Специфика Java
–sonar Анализировать код с помощью Sonar.
–maven-export Экспортировать в maven репозиторий
Продвинутые опции
–version=VERSION Версия артефактов для экспорта в maven
-J=JAVAC_FLAGS, --javac-opts=JAVAC_FLAGS
Установить общие флаги javac (имя=val)
–error-prone-flags=ERROR_PRONE_FLAGS
Установить флаги Error Prone
–disable-run-script-generation
Отключить генерацию скриптов запуска для JAVA_PROGRAM
Экспертные опции
–sonar-project-filter=SONAR_PROJECT_FILTERS
Анализировать только проекты, соответствующие любому фильтру
–sonar-default-project-filter
Установить значение по умолчанию --sonar-project-filter (цели сборки)
-N=SONAR_PROPERTIES, --sonar-property=SONAR_PROPERTIES
Свойства для анализатора Sonar (имя[=значение], “yes”, если значение опущено)
–sonar-do-not-compile
Не компилировать исходные коды Java. В этом случае свойство “-Dsonar.java.binaries” не устанавливается автоматически.
–sonar-java-args=SONAR_JAVA_ARGS
Свойства Java машины для запуска сканера Sonar
–get-deps=GET_DEPS Скомпилировать и собрать все зависимости в указанную директорию
-s, --sources Создавать также jar-файлы исходного кода
Загрузка:
Экспертные опции
–ttl=TTL Время жизни ресурса в днях (передайте ‘inf’ - чтобы пометить ресурс как неудаляемый) (по умолчанию: 14)
Загрузка в песочницу:
Продвинутые опции
–owner=RESOURCE_OWNER
Имя пользователя, которому принадлежат данные, сохраненные в песочнице. Требуется в случае бесконечного срока хранения ресурсов в mds.
–sandbox-url=SANDBOX_URL
URL песочницы для хранения канонических файлов (по умолчанию: https://sandbox.yandex-team.ru)
–task-kill-timeout=TASK_KILL_TIMEOUT
Тайм-аут в секундах для задачи загрузки в песочницу
–sandbox Загрузить в песочницу
Загрузка в mds:
Продвинутые опции
–mds Загрузить в MDS
–mds-host=MDS_HOST Хост MDS (по умолчанию: storage.yandex-team.ru)
–mds-port=MDS_PORT Порт MDS (по умолчанию: 80)
–mds-namespace=MDS_NAMESPACE
Пространство имен MDS (по умолчанию: devtools)
–mds-token=MDS_TOKEN
Токен Basic Auth MDS
Авторизация:
Продвинутые опции
–key=SSH_KEYS Путь к приватному SSH ключу для обмена на OAuth токен
–token=OAUTH_TOKEN OAuth токен
–user=USERNAME Имя пользователя для авторизации
–ssh-key=SSH_KEYS Путь к приватному SSH ключу для обмена на OAuth токен
Запуск тестов
ya make предоставляет развитые возможности запуска тестов. Основными понятиями для тестирование силами ya make являются test, chunk и suite (набор тестов).
Test - одна именованная проверка, описанная в виде кода на поддерживаемом языке программирования. В понятие теста включается не только проверка правильности работы кода, но также, например, проверки, что код соответствует рекомендуемому стандарту оформления. Любые падения/ошибки во время исполнения теста относятся непосредственно к исполняемому тесту.
Chunk - сущность, представляющая собой запуск программы с тестами (представлен в виде узла в графе команд), в рамках которой исполняются тесты. К chunk относятся все ошибки runtime исполнения за рамками тестов. Например, ошибки запуска тестирования, когда тестовая программа упала на инициализации и тесты даже не запускались, ошибки финализации тестирования, утечки памяти после тестирования, падения тестовых рецептов.
Suite - набор из нескольких тестов одного типа и имеющих один и тот же набор зависимостей. Suite содежит по крайней мере один chunk (так называемый sole chunk). Все тесты в наборе имеют общий размер, логику начала (set up) и завершения (tear down) работы, теги и так далее. Некоторые ошибки не позволяют вообще запустить тестирование - сломанные зависимости теста, когда невозможно собрать требуемую для тестирования программу, ошибки подбора хоста для LARGE тестов из-за комбинации sandbox-тегов, которым не соответствует ни один хост. Все такие ошибки относятся к suite.
Каждая suite имеет имя, размер (время, отведённое на работу), тип (используемый фреймворк), а также опциональный набор тегов. Все эти параметры могут быть использованы для фильтрации. Кроме того, каждый отдельный тест имеет имя и потому фильтрация может делаться с точностью до отдельного теста.
Примечание
Имена suite известны системе сборки заранее, а имена тестов выясняются только во время запуска chunk. Это, в частности, означает, что система сборки должна запустить chunk даже если ей надо только узнать имена тестов. Если в коде инициализации chunk есть ошибки, то такой запуск может завершиться ошибкой и система сборки не узнает, какие тесты есть в suite и даже сколько их там.
Запуск тестов
Для простого запуска тестов есть следующие ключи командной строки:
-t — запустить только SMALL тесты.
-tt — запустить SMALL и MEDIUM тесты.
-ttt, -A, --run-all-tests — запустить тесты всех размеров.
–test-param=TEST_PARAM — параметризовать тесты значениями из командной строки. TEST PARAM имеет вид name=val, доступ к параметрам зависит от используемого фреймворка.
Пример
ya make -t devtools/examples/tutorials/python
Запустит все тесты, которые найдёт по RECURSE/RECURSE_FOR_TESTS от devtools/examples/tutorials/python, включая тесты стиля и тесты импорта для Python. Использует следующие умолчания для сборки:
Платформа будет определена по реальной платформе, на которой запущена команда ya make.
Тесты будут собраны в режиме debug — он используется по умолчанию.
Кроме тестов будут собраны все остальные цели (библиотеки и программы), достижимые по RECURSE/RECURSE_FOR_TESTS от devtools/examples/tutorials/python. Это включает сборку всех необходимых зависимостей.
По умолчанию система сборки запустит все запрошенные тесты. После запуска тестов для всех упавших тестов будет выдана краткая информация о падениях (включая ссылки на более полную информацию). Для прошедших и проигнорированных (отфильтрованных) тестов будет выдан только общий короткий статус (количество тех и других).
Это поведение меняется следующими ключами:
–fail-fast — исполнять тесты до первого падения.
-P, --show-passed-tests — показывать каждый прошедший тест
–show-skipped-tests — показывать каждый пропущенный (отфильтрованный) тест
–show-metrics — показывать метрики тестов
Список тестов
Список всех тестов, которые будут запущены, можно получить опцией -L (–list-tests). Эта опция поддерживает выбор размера тестов, а также все параметры фильтрации.
Примеры
# Список всех SMALL тестов
ya make -tL devtools/examples/tutorials/python
# Список всех пользовательских тестов (без тестов стиля, импортов и подобных проверок)
ya make -AL --regular-tests devtools/examples/tutorials/python
Размер тестов
В едином репозитории в одном пулл-реквесте изменения могут вноситься в код и тесты на разных языках программирования. Важно, чтобы проверка любых пулл-реквестов проходила как можно быстрее, поэтому тесты разделены на категории по максимальному разрешённому времени исполнения, которое является значением по умолчанию:
SMALL тесты: выполняются не более 1 минуты. Сюда обычно попадает большинство unit-тестов.
MEDIUM тесты: выполняются не более 10 минут. Сюда попадают некоторые медленные unit-тесты, интеграционные и end-to-end тесты.
LARGE (ранее “FAT”) тесты: выполняются не более 1 часа. Содержит особо медленные тесты. В отличие от MEDIUM/SMALL тестов LARGE тесты могут продолжаться даже после завершения остальных проверок пулл-реквеста, потому что запускаются в отдельном процессе в Sandbox.
Примечание
Строгого соответствия между размером тестов (SMALL, MEDIUM, LARGE) и типом тестов (unit, интеграционные, end to end) нет. В первую очередь нужно ориентироваться на максимальное время исполнения каждого теста.
Размер тестов должен быть явно указан в файле ya.make при помощи макроса SIZE. Максимальное время выполнения теста можно уменьшить при помощи макроса TIMEOUT.
Параллельный запуск тестов
По умолчанию тесты внутри одной suite выполняются последовательно в рамках одного chunk (так называемого sole chunk) в виде отдельного узла графа команд ya. Тесты из разных suite (ya.make) выполняются параллельно, но последовательно в рамках одно chunk.
Во время формирования графа команда ya не может знать, сколько будет тестов в suite, так как для этого требуется сборка и листинг тестов средствами тестового фреймворка. Так как ya оперирует статическим графом команд (он не меняется по мере исполнения и целиком известен для исполнителя), то на этапе конфигурации мы только можем заранее вставить нужное количество chunk’ов, каждый из которых исполнит непересекающееся множество тестов.
Чтобы разбить выполнение тестов из suite на несколько chunk’ов, нужно воспользоваться макросами FORK_TESTS, FORK_SUBTESTS и FORK_TEST_FILES.
Каждый chunk наследует общие параметры теста из ya.make: размер, таймаут, требования на ресурсы и другие: таким образом удобно распараллелить тесты, которые из-за своего количества перестали укладываться в таймаут.
FORK_TESTS, FORK_SUBTESTS – режимы, при которых вместо sole chunk запуск suite разбивается на несколько chunk’ов, каждый из которых получает дополнительные параметры в виде общего количества chunk’ов, участвующих в разбиении и своего порядкового номера: по этим параметрам каждый chunk определяет подмножество тестов, которое надо запустить. Количество chunk’ов по умолчанию равно 10, это значение можно изменить с помощью SPLIT_FACTOR(X) (при локальной разработке SPLIT_FACTOR можно переопределить с помощью --split-factor=Х. --split-factor=1 отключает режим форков). Отличие FORK_TESTS от FORK_SUBTESTS заключается в том, что FORK_TESTS считает тесты, объединенные в классы, неделимой сущностью, в то время как FORK_SUBTESTS разбивает в том числе тестовые классы и в разных chunk’ах могут оказаться тесты, принадлежащие одному классу, что может быть нежелательно, если у классов есть тяжёлые подготовительные стадии.
FORK_TEST_FILES – разбивает прогон тестов из suite на количество chunk’ов, равное количеству файлов с тестами, перечисленных в ya.make, каждый запуск работает только с одним конкретным файлом.
FORK_TESTS, FORK_SUBTESTS принимают необязательный аргумент - SEQUENTIAL или MODULO, определяющий, как будет происходить разделение тестов по chunk’ам. SEQUENTIAL разделяет тесты равными диапазонами, предварительно их отсортировав по имени. MODULO разделяет тесты по модулю SPLIT_FACTOR, предварительно их отсортировав (т.е. при SPLIT_FACTOR(2), первый тест попадёт в первый chunk, второй тест во второй, третий в первый и т.д.) Если аргумент не указан, значение по умолчанию - SEQUENTIAL.
FORK_TEST_FILES можно комбинировать с FORK_TESTS или FORK_SUBTESTS, тогда будет дополнительное разбиение запуска тестов из каждого файла.
FORK_TEST_FILES поддержан только для pytest.

Фильтрация тестов
Suite можно фильтровать по различным свойствам:
–test-size=TEST_SIZE_FILTERS — запускать только выбранные размеры
–test-type=TEST_TYPE_FILTERS — запускать только выбранные типы тестов. Перед именами типов тестов можно использовать + для включения suite в фильтр и - для исключения. Таким образом --test-type -import_test запустит все тесты, кроме import_test. Фильтр --test-type unittest+gtest запустит только unittest и gtest.
–style — запускать только тесты стиля
–regular-tests — запускать только пользовательские тесты
–test-tag=TEST_TAGS_FILTER — запускать только сюиты с определёнными тегами. Перед именами тегов можно использовать + для включения тега в фильтр и - для исключения. Таким образом --test-tag tag1+tag2-tag3 запустит все тесты, у которых есть tag1, tag2 и нет tag3. Фильтр --test-tag -tag3 запустит все тесты без тега tag3. Фильтр --test-tag ya:anytag запустит все тесты со всеми тегами.
Помимо фильтрации suite можно фильтровать отдельные тесты:
-F=TESTS_FILTERS, --test-filter=TESTS_FILTERS — фильтрация тестов по имени. Будет запущен тест, полное имя которого строго соответствует TESTS_FILTERS. Для запуска подмножества тестов в шаблоне можно указать символ * (соответствует любому количеству символов). Каждый последующий шаблон расширяет подмножество запускаемых тестов. Например -F ‘a’ -F 'Bc’ запустит все тесты имена которых заканчиваются на a или начинаются на B и заканчиваются на c. Шаблоны взяты в одинарные кавычки для того чтобы shell не развернул фильтр в список файлов, которому может соответствовать шаблон.
-F=“[X/Y] chunk”, --test-filter=“[X/Y] chunk” — фильтрация тестов по chunk’ам. Внутри [] можно использовать * для фильтрации.
–test-filename=TEST_FILES_FILTER — запускать тесты только из выбранного исходного файла (работает только для pytest и hermione, другие тестовые фреймоврки не предоставляют такой информации).
-X, --last-failed-tests — запустить только тесты упавшие в предыдущем запуске. Указание дополнительных фильтров (например с помощью -F) расширяет множество тестов, которое будет запущено. Обычно это требуется, когда вы хотите следить за корректным статусом некоторых тестов, помимо перезапуска упавших от предыдущего прогона.
При указании флага -F можно использовать специальные символы:
ya make -t -F <file>.py::<ClassName>::
JUnit5-тесты можно фильтровать по тегам @Tag:
–junit-args ‘–junit-tags “tag1 tag2 tag3”’ - запуск всех тестов, у которых есть хотя бы один из указанных тегов (теги можно также разделять плюсом, например tag1+tag2). Подробнее можно почитать тут.
Совет
Для правильного указания параметров фильтрации воспользуйтесь опцией получения списка тестов. Её же можно использовать, чтобы проверить, что ваш фильтр работает правильно.
Канонизация (и переканонизация)
Система сборки ya make для некоторых типов тестов поддерживает сравнение с эталонными (каноническими) данными. Если эти данные нужно обновить воспользуйтесь опцией -Z (–canonize-tests). В этом режиме вместо сравнения данных с эталонными, сами эталонные данные будут заменены и при необходимости отправлены в Sandbox. В локальное рабочее пространство будут внесены все необходимые изменения.
Внимание
Не забудьте закоммитить локальные изменения, иначе новые эталонные данные не будут доступны в CI.
Типы тестов
Типом теста называется выполнение проверок с использованием одного конкретного инструмента, например, фреймворка pytest для Python или утилиты проверки форматирования кода go fmt для Golang.
Полный список типов тестов приведен :
black Проверка форматирования кода на python3 утилитой black.
classpath.clash Проверка наличия дублирующихся классов в classpath при компиляции Java проекта.
eslint Проверка стиля и типичных ошибок кода на TypeScript с использованием утилиты ESLint.
exectest Выполнение произвольной команды и проверка её кода возврата
flake8.py2 Проверка стиля кода на Python 2 c использованием утилиты Flake8
flake8.py3 Проверка стиля кода на Python 3 c использованием утилиты Flake8
fuzz Fuzzing тест
g_benchmark Выполнение бенчмарков на C++ библиотекой Google Benchmark
go_bench Выполнение бенчмарков на Go утилитой go bench
gofmt Проверка форматирования кода на Go утилитой go fmt
go_test Выполнение тестов на Go утилитой go test
govet Выполнение статического анализатора кода на Go утилитой go vet
gtest Выполнение тестов на С++ с использованием фреймворка Google Test
java Выполнение тестов на Java с использованием фреймворка JUnit
java.style Проверка форматирования кода на Java утилитой checkstyle
ktlint Проверка стиля Kotlin кода с использованием утилиты ktlint
py2test Тесты на Python 2 с использованием фреймворка pytest
py3test Тесты на Python 3 с использованием фреймворка pytest
pytest Тесты на Python любой версии с использованием фреймворка pytest
unittest Тесты на C++ с использованием фреймворка unittest
validate_resource Проверка времени жизни Sandbox ресурса

Описание тестов
В этом разделе подробно рассказано как описывать тесты в ya.make файлах. Про запуск тестов можно прочитать вот здесь
В нашей системе сборки ya make можно описать тесты для основных языков. Поддержка тестов реализована поверх фреймворков для тестирования в этих языках. Подробную информацию про устройство тестов в языке можете найти на соответствующих страницах (C++, Python, Java, Go).
Общие понятия
Два основных понятия для тестов в ya make это test и suite.
test - это конкретная именованная проверка.
suite - сущность, включающая в себя тесты в рамках описываемого модуля.
Как описывать ya.make
По умолчанию один тестовый модуль является одной suite. suite аккумулирует в себе ошибки тестирования, которые выходят за пределы определения теста, например:
ошибки получения списка тестов
ошибки инициализации тестирования (до фактического выполнения тестов)
ошибки финализации тестирования
Сьюита имеет несколько параметров:
Указание фрэймворка тестирования
Список файлов с тестами
Список зависимостей
Размер
Тэги
Требования к запуску тестов
Переменные окружения
Таймаут на запуск
Список зависимостей
Мы придерживаемся идеи герметичности тестов. Это значит, что тест должен быть зависимым только от входных данных, которые были явно задекларированы в ya.make. Чтобы обеспечить герметичность тестов, каждый запуск проходит в чистом окружении, которое содержит только указанные явно зависимости из ya.make.
Помимо сборочных зависимостей (описываются макросом PEERDIR()), для тестов нужно описывать зависимости на входные данные для запуска тестов. Они бывают двух типов:
Другие проекты из единого репозитория. Например, вам может потребоваться исполняемый файл, исходные коды которого расположены в другом проекте. Такие зависимости описываются при помощи макроса DEPENDS(). Все пути строятся относительно корня ircadii и указываются через пробел до ya.make.
Тестовые данные. Например, сюда относятся различные эталонные файлы: логи, списки, тестовые дампы баз данных. Такие файлы могут храниться как и в ircadii, так и в Sandbox. Для описания тестовых данных можно использовать макросы:
DATA()
FROM_SANDBOX()
Более полную информацию про использование данных в тестах можно прочитать здесь.
Сборка и запуск тестов
Основная задача ya make - cборка. Поэтому handler собирает все указанные цели и достижимые от них по RECURSE.
Однако, основная цель у ya test / ya make -t - запуск тестирования. Поэтому по умолчанию будут собираться только те цели, которые необходимы для запуска тестирования. Это, например, позволяет запускать конкретные типы тестов без сборки: ya test --test-type black запустит только python black линтер, без какой-либо сборки.
Примечание
Модули, достижимые по RECURSE, но не используемые в тестах или сами не являющиеся тестовыми модулями не будут собираться.
Для того чтобы ya test / ya make -t собирал все достижимые цели, нужно добавить ключ -b / --build-all.

Размер тестов
Размер тестов задается макросом SIZE(). Сейчас существуют три размера:
SIZE(SMALL) - максимальный таймаут 60s (1min). Размер по умолчанию.
SIZE(MEDIUM) - максимальный таймаут 600s (10min).
SIZE(LARGE) - максимальный таймаут 3600s (1hour).
Тэги теста
Тесты можно фильтровать по тэгам. Тэги проставляются с помощью макроса TAG().

Требования к запуску теста
Макрос REQUIREMENTS() позволяет указать требования, необходимые для запуска тестов. С помощью этого макроса можно задать:
количество ядер
необходимый объем свободного места на диске
необходимый объем оперативной памяти
необходимый объем RAM-диска
ID контейнера
ограничения сети
Все возможные описания требований указаны в разделе Общие макросы
Переменные окружения
С помощью макроса ENV(key=value) можно задать значение переменной окружения при запуске теста. Каждая переменная окружения задается отдельным макросомм.
Иерархия проекта с тестами
Предлагается в папке проекта иметь lib, bin, tests или lib/tests. Мы не рекомендуем указывать RECURSE в ya.make, содержащем описание модуля, но можно после директивы END() добавлять RECURSE_FOR_TESTS на тесты, проверяющие этот модуль. Тогда project/ya.make может состоять из
RECURSE(
project/bin
project/lib
project/lib/tests
)
В project/lib не должно быть RECURSE на tests или определение модуля тестов, однако можно поставить RECURSE_FOR_TESTS.
В этом случае при запуске ya make -t из каталога project инициируется сборка проекта с прогоном тестов. А другие проекты, желая подключать вашу библиотеку, будут писать PEERDIR(project/lib) без установления зависимости от ваших тестов.
Гранулярные тесты
Гранулярные зависимости в сборке это хорошо, тоже самое относится и к тестам. Если у вас в тестовом модуле более ~15 файлов с тестами (к java не относится) скорее всего вам нужно разбить ваш suite на несколько логических. Как правило всё множество тестов можно кластеризовать по каким-либо признакам - по тестируемым сущностям, по зависимостям, по типу тестирования, по сценариям тестирования.
Такое разбиение больших тестовых suite может значительно ускорить локальную разработку и время прохождения PR в CI:
при исправлении тестов или добавлении новых будет запускаться только целевой suite
более гранулярные зависимости позволяют запускать только те тесты, которые по настоящему зависят от них
более гранулярные зависимости ускоряют конфигурацию
ускоряется рантайм тестирования, так как ускоряется процедура дискаверинга тестов
в каждый отдельный suite может быть прописан REQUIREMENTS соответствующий действительности
логическая группировка упрощает организацию тестовых файлов
Пример антипаттерна: тестовый модуль с сотнями тестовых файлов и макросами FORK_TEST()/FORK_TEST_FILES(). Такая организация suite приводит к огромному прожиганию ресурсов впустую, так как при изменении любого файла будут вынуждены перезапуститься абсолютно все тесты в suite. Локальный запуск одного конкретного test case из такого suite может происходить очень долго.
Возможности тестов
Канонизация
У тестов есть возможность сообщить о своих результатах в виде данных, которые необходимо верифицировать с каноническими. Такие тесты необходимо первый раз канонизировать, после чего системе будут доступны референсные данные для сравнения. Канонический результат будет сохранен рядом с тестом в директорию canondata/<test name>/result.json или вынесен в ресурс Sandbox, в зависимости от переданных параметров в тесте.
Каждый фреймворк для написания тестов предоставляет свою поддержку механизма канонизации. Канонизация поддержана для всех языков, кроме C++.
Метрики
Наш CI поддерживает выгрузку пользовательских метрик из тестов. При подключении проекта к автосборке история теста с метриками будет сохраняться и отображаться в CI. При локальной сборке будет доступен отчет.
Параллельный запуск тестов
По умолчанию тесты внутри одного ya.make файла выполняются последовательно в рамках отдельной задачи сборочного графа, а тесты из разных ya.make выполняются параллельно. Для того, чтобы разбить выполнение тестов из одного ya.make на несколько параллельных запусков, можно воспользоваться макросами FORK_TESTS, FORK_SUBTESTS и FORK_TEST_FILES. Каждый запуск будет выполнен в отдельной задаче сборочного графа.
Важно отметить, что каждый подзапуск наследует общие параметры теста из ya.make, такие как размер, таймаут, требования на ресурсы и т.д. Таким образом удобно распараллелить тесты, которые из-за своего количества перестали укладываться в таймаут, но если в ya.make стоит требование cpu(4), то при большом количестве параллельных задач, локальный запуск ya make может замедлиться.
Не все FORK-макросы поддержаны для конкретного тестового фреймворка и языка: перед их использованием, уточните текущий статус в документации.

Exec-тесты
Помимо обычных тестов, которые будут описаны в специфичных для языков разделах, есть возможность писать exec-тесты. Exec-тесты позволяют выполнить произвольную команду и убедиться, что она успешно завершается. Успешным считается завершение команды с кодом возврата 0.
Подробнее про описание Exec-тестов написано здесь.
Как описывать тесты для языков
C++
Сейчас поддержаны два тестовых фреймворка:
unittest - собственная разработка
gtest - популярное решение от Google
Также есть отдельная библиотека library/cpp/testing/common, в которой находятся полезные утилиты, независящие от фреймворка.
Бенчмарки: Используется библиотека google benchmark и модуль G_BENCHMARK. Все подключенные к автосборке бенчмарки запускаются в CI по релевантным коммитам и накапливают историю метрик.
Fuzzing: Фаззинг - это техника тестирования, заключающаяся в передаче приложению на вход неправильных, неожиданных или случайных данных. Все подробности здесь.
Linting: Поддержан статический анализ файлов с помощью clang-tidy. Подробнее про подключение своего проекта к линтингу в автосборке можно прочитать здесь.
Метрики: Помимо метрик от бенчмарков также можно сообщать числовые метрики из UNITTEST() и GTEST(). Для добавления метрик используйте функцию testing::Test::RecordProperty если работаете с gtest, или макрос UNIT_ADD_METRIC если работаете с unittest.
TEST(Solver, TrivialCase) {
// …
RecordProperty(“num_iterations”, 10);
RecordProperty(“score”, “0.93”);
}
Минимальный ya.make для тестов выглядит так:
UNITTEST() | GTEST() | G_BENCHMARK()
OWNER(…)
SRCS(tests.cpp)
END()
Python
Основным фреймворком для написания тестов на Python является pytest.
Поддерживаются Python 2 (модуль PY2TEST), Python 3 (модуль PY3TEST) и модуль PY23_TEST. Все тестовые файлы перечисляются в макросе TEST_SRCS().
Для работы с файлами, внешними программами, сетью в тестах следует использовать специальную библиотеку yatest.
Метрики: Чтобы сообщить метрики из теста, необходимо использовать funcarg metrics.
def test(metrics):
metrics.set(“name1”, 12)
metrics.set(“name2”, 12.5)
Бенчмарки: Для бенчмарков следует использовать функцию yatest.common.execute_benchmark(path, budget=None, threads=None). Чтобы результаты отображались в CI, результаты нужно записывать в метрики.
Канонизация: Можно канонизировать простые типы данных, списки, словари, файлы и директории. Тест сообщает о данных, которые нужно сравнить с каноническими, через возврат их из тестовой функции командой return.
Linting: Все python файлы, используемые в сборке и тестах, подключаемые через ya.make в секциях PY_SRCS() и TEST_SRCS(), автоматически проверяются flake8 линтером.
Python imports: Для программ PY2_PROGRAM, PY3_PROGRAM, PY2TEST, PY3TEST, PY23_TEST, собранных из модулей на питоне, добавлена проверка внутренних модулей на их импортируемость - import_test. Это позволит обнаруживать на ранних стадиях конфликты между библиотеками, которые подключаются через PEERDIR, а также укажет на неперечисленные в PY_SRCS файлы (но не TEST_SRCS).
Java
Для тестов используется фреймворк JUnit версий 4.x и 5.x.
Тестовый модуль для JUnit4 описывается модулем JTEST() или JTEST_FOR(path/to/testing/module).
JTEST(): система сборки будет искать тесты в JAVA_SRCS() данного модуля.
JTEST_FOR(path/to/testing/module): система сборки будет искать тесты в тестируемом модуле.
Для включения JUnit5 вместо JTEST() необходимо использовать JUNIT5().
Содержание ya.make файла для JUNIT5() и JTEST() отличается только набором зависимостей.
Минимальный ya.make файл выглядит так:
JTEST()
JAVA_SRCS(FileTest.java)
PEERDIR(
# Сюда же необходимо добавить зависимости от исходных кодов вашего проекта
contrib/java/junit/junit/4.12 # Сам фреймворк JUnit 4
contrib/java/org/hamcrest/hamcrest-all # Можно подключить набор Hamcrest матчеров
)
END()
Java classpath clashes: Есть возможность включить автоматическую проверку на наличие нескольких одинаковых классов в Java Classpath. В проверке участвует не только имя класса, но и хэш-сумма файла с его исходным кодом, так как идентичные классы из разных библиотек проблем вызывать не должны. Для включения этого типа тестов в ya.make файл соответствующего проекта нужно добавить макрос CHECK_JAVA_DEPS(yes).
Linting: На все исходные тексты на Java, которые подключены в секции JAVA_SRCS, включён статический анализ. Для проверки используется утилита checkstyle.
Канонизация: Для работы с канонизированными данными используйте функции из devtools/jtest.
Go
Тесты работают поверх стандартного тулинга для Go. Для работы с зависимостями теста следует использовать библиотеку library/go/test/yatest.
Все тестовые файлы должны иметь суффикс test.go. Они перечисляются в макросе GO_TEST_SRCS.
Тестовый модуль описывается модулем GO_TEST() или GO_TEST_FOR(path/to/testing/module).
GO_TEST(): система сборки будет искать тесты в GO_TEST_SRCS() данного модуля.
GO_TEST_FOR(path/to/testing/module): система сборки будет искать тесты в GO_TEST_SRCS в тестируемом модуле.
Минимальные ya.make файлы выглядят так:
GO_TEST()
GO_TEST_SRCS(file_test.go)
END()
Канонизация: Для работы с такими тестами используйте library/go/test/canon. Пример.
Бенчмарки: Чтобы включить бенчмарки в проекте, нужно добавить тэг ya:run_go_benchmark в ya.make проекта. Пример.

Общие макросы
Зависимости
DEPENDS()
DEPENDS(path1 [path2…])
Указывает зависимости на другие проекты, которые нужно собрать и результаты которых должны быть доступны тесту. В параметрах перечисляются относительные пути от корня ircadii.
Параметры suite
SIZE()
SIZE(SMALL | MEDIUM | LARGE)
Задаёт размер suite. Сейчас существует три размера:
SMALL - максимальный таймаут 60s. Размер по умолчанию.
MEDIUM - максимальный таймаут 600s.
LARGE - максимальный таймаут 3600s.
Важно
Если в ya.make листе указаны несколько значений макроса SIZE(), например, через вложенный INCLUDE, то последнее значение переопределяет все предыдущие.
TIMEOUT()
TIMEOUT(time)
Устанавливает таймаут на запуск всей сьюиты. По умолчанию равен:
60s (1min) для SMALL тестов;
600s (10min) для MEDIUM тестов;
3600s (1hour) для LARGE тестов.
Примечание
Таймаут не может быть больше, чем максимальная длительность теста данного размера.
Если запуск сьюиты разбит на части (FORK_TEST_FILES()/FORK_TESTS()/FORK_SUBTESTS()), то указанный таймаут ограничивает время работы каждого запуска в отдельности.
TAG()
TAG(tag1 [tag2…])
Позволяет задать пользовательские теги, по которым можно фильтровать запуск suite в ya test, см. опцию --test-tag.
Ниже представлен список специальных системных тегов, которые могут менять поведение тестов.
Запуск тестов:
ya:always_minimize: приводит к постоянной минимизации корпуса после фаззинга, см подробности в документации к fuzzing.
ya:manual: тест не будет запускаться, если явно не указано запускать тесты с таким тегом
ya:norestart: тест не будет перезапускаться при определенных ошибках
ya:not_autocheck: не запускать тест при проверке pull requests
Логирование:
ya:full_logs: приводит к падению сьюиты, если размер логов привысил 100Мб
ya:huge_logs: увеличивает ограничение на размер логов теста с 100Мб до 1Гб
ya:sys_info: добавляет вывод системной информации в лог до и после выполнения всех рецептов и тестов
ya:trace_output: включает логирование создаваемых файлов и их размеров при помощи системного вызова ptrace. Работает только под Linux. Может замедлять тестирование
ya:dump_node_env: печатает дерево директорий относительно build_root узла сразу после его запуска в лог test-results/<suite>/run_test.log. Позволяет узнать чистое окружение тестового узла, которое приехало по зависимостям
ya:dump_test_env: печатает дерево директорий относительно build_root узла непосредственно перед запуском враппера тестов в лог test-results/<suite>/run_test.log. Позволяет узнать окружение в котором будут запускаться тесты (после запуска рецептов). Не работает вместе с ya:dirty, так как привело бы к полному обходу ircadii.
large-тесты:
ya:fat: помечает тест как LARGE
ya:force_distbuild: запускает тест в distbuild вне зависимости от его размера
ya:force_sandbox: запускает тест в Sandbox. Используется только вместе с тегом ya:fat
ya:noretries: тесты с таким тегом не будут запускаться в автосборке повторно
ya:privileged: запускает тесты в Sandbox в контейнере от имени root
ya:sandbox_coverage: включает LARGE тесты в подсчет покрытия. Нужно использовать вместе с ya:force_sandbox
ya:relwithdebinfo: тесты с таким тэгом будут собираться с флагом --build relwithdebinfo - релизная сборка с включенными ассертами для C++. Тесты, собранные с --build relwithdebinfo, могут исполняться медленне, чем для релизной сборки, но ассерты могут дать больше полезной информации.
Управление окружением:
ya:copydata: Пути, указанные в макросе DATA() подключаются в тестовое окружение не симлинками, а рекурсивно копируются, при этом всем файлам и каталогам выставляются права на запись пользователя и группы
ya:copydataro: Аналогично ya:copydata, но наоборот, всем файлам и каталогам запрещается запись для пользователя, группы и других
Остальные:
ya:external: уведомляет систему, что тест использует внешние системы (сеть, внешние базы данных). Это значит, что такой тест потенциально нестабильный. Уведомления о поломках таких тестов будут приходить только владельцам теста и не будут приходить авторам комита, на котором тест сломался
ya:no_graceful_shutdown: завершает выполнение процесса с тестами при помощи сигнала SIGQUIT вместо SIGTERM. Это позволяет, например, поймать стектрейс состояния, в котором находится тест
ya:notags: используется для фильтрации тестов, не имеющих тегов
Sandbox-теги:
sb:XXXX: позволяет задать набор тегов для выбора агента Sandbox. При указании нескольких тегов sb:, они соединяются через логическое ИЛИ
sb:ttl=inf: позволяет задать TTL в днях для создаваемого в таске YA_MAKE ресурса BUILD_OUTPUT. Тег следует использовать, если автозапуск LARGE тестов от лица вашего робота потребляет много дисковой квоты из-за больших выходных данных в этом ресурсе. TTL по умолчанию равен 14 дней
sb:logs_ttl=14: позволяет задать TTL в днях для создаваемого в таске YA_MAKE ресурса TASK_LOGS. Тег следует использовать, если автозапуск LARGE тестов от лица вашего робота потребляет много дисковой квоты из-за больших выходных данных в этом ресурсе. TTL по умолчанию равен 14 дней
sb:store_output_binaries: сохраняет собранные бинари large-тестов в ресурсах типа BUILD_OUTPUT таски YA_MAKE
REQUIREMENTS()
REQUIREMENTS(
[cpu:<count>]
[disk_usage:<size>]
[ram:<size>]
[ram_disk:<size>]
[container:<id>]
[network:<restricted|full>]
[dns:<default|local|dns64>])
[yav:<ENV_NAME>=<value|file>:<owner>:<vault key>]
)
Позволяет настроить требования к окружению, в котором будет выполняться тест. Large-тесты в основном запускаются под Sandbox, поэтому всё, что связано с Sandbox, можно смело соотносить с Large-тестами (кроме случаев когда large-тесты запускаются на YT).
Name Default Values Applicability Description
container - <sbr-res-id> Sandbox ID Sandbox контейнера, в котором будет выполняться тест
cpu 1 1… / all Local / Distbuild / Sandbox Количество процессорных ядер, необходимых тестам для корректной работы. Конечное значение рассчитывается как min(требуемое, количество_ядер_на_хосте). При указании all тестовый узел будет работать монопольно, в этом случае если у suite есть несколько chunk, то запуск выстроится в цепочку запуска chunk
disk_usage 100 1… Sandbox Необходимый объём свободного места на файловой системе в Gb. Для Large теста превращается в требование disk_usage у Sandbox таски.
dns default default / local / dns64 Sandbox Настраивает использование NAT64 в Sandbox.
default - доступ в интернет по IPv4 невозможен,
local - используются настройки из файла /etc/resolv.conf.local. Имеет смысл только для кастомных контейнеров, в которых этот файл существует.
dns64 - доступ в Интернет по IPv4 возможен. Весь резолвинг имён происходит через ферму ns64-cache.yandex.net
network restricted restricted / full Local / Distbuild Определяет тип доступа к сети.
full - есть доступ во внешнюю сеть.
restricted - можно использовать только localhost.
Локально учитывается только на linux при указании ключа --private-ns-drive (или --autocheck-mode).
ram - 1… Distbuild / Sandbox Необходимый объём оперативной памяти в Gb.
ram_disk - 1… Local* / Sandbox / Distbuild Необходимый объём RAM диска в Gb.
На Distbuild выделяется для каждого узла.
На Sandbox выдяляется один на всю suite - заказывается в виде требования у Sandbox таски.
Локально учитывается только на linux при указании ключа --private-ram-drive (или --autocheck-mode). Тест может узнать путь к созданому для него RAM диску через API взаимодействия с тестовым окружением: Java, Python
yav - см. описание Sandbox Ключ из секретницы в виде шаблона <ENV_NAME>=<value/file>:<sec-id>:<key>, который получит тест через указанную переменную окружения, где
<ENV_NAME> - имя переменной,
<value/file> тип передачи секрета (value - значение секрета будет записано в указанный ENV_NAME, file - секрет будет записан во временный файл и до путь до него будет передан через ENV_NAME),
<sec-id> - id yav секрета,
<key> - имя ключа из секрета
Мы крайне не рекомендуем использовать секреты и предлагаем стараться обходиться без них, используя моки или другие техники тестирования.
Использование секрета ломает воспроизводимость теста и не позволяет его запускать разработчикам без доступа до него. Так же появляется стейт за границами репозитория и статуc теста начинает зависеть от комплементарности системы использующей секрет и самого секрета в yav.
При использовании секретов suite автоматически получает тег ya:external, т.е. падения такого тестa в CI будут видны только владельцам теста.
sb_vault - см. описание Sandbox Deprecated, используйте yav .
Ключ из sandbox-vault. Должен соответствовать паттерну <ENV_NAME>=<value/file>:<owner>:<vault key>.
Для доступа из Large-тестов секрет должен быть пошарен (Shared with) с группой REVIEW-CHECK-FAT.
При использовании секретов suite автоматически получает тег ya:external, т.е. падения такого тестa в CI будут видны только владельцам теста.
Примечание
Параметры disk_usage и container работают только для LARGE тестов.
Параметр container позволяет запускать тесты в заранее подготовленном окружении в виде образа LXC или Porto контейнера.
Поскольку RAM-диск использует оперативную память, суммарное значение полей ram и ram_disk не может превышать максимально возможное значение размера оперативной памяти для тестов данного размера.
Актуальные требования можно посмотреть вот тут, словарь TestSize.DefaultRequirements.
Requirement SMALL MEDIUM LARGE
CPU 1 … 4 1 … 4 1 … 4
RAM 8 … 32 8 … 32 8 … 32
RAM disk 0 … 4 0 … 4 0 … 4
Требования для LARGE учитываются только при запуске на Distbuild - для тестов размеченных с помощью тега TAG(ya:force_distbuild). По умолчанию LARGE тесты сейчас запускаются в Sandbox, где нет этих ограничений.
ENV()
ENV(key=[value])
Задает значение переменной окружения key значение value при запуске теста.
Параллельный запуск тестов
FORK_TESTS()
FORK_TESTS(mode)
Разбивает запуск suite на несколько chunk’ов. По умолчанию количество chunk’ов равно 10. Это значение можно изменить с помощью макроса SPLIT_FACTOR(x). В отличие от FORK_SUBTESTS считает тесты, объединенные в один класс, неделимой сущностью.
Каждый chunk наследует общие параметры теста из ya.make: размер, таймаут, требования на ресурсы. Поэтому этот макрос удобно использовать, чтобы распараллелить тесты, которые не укладываются в таймаут.
Параметр mode определяет, каким образом будет происходить распределение тестов по chunk’ам. Может быть равен SEQUENTIAL или MODULO. Если аргумент не указан, то по умолчанию равен SEQUENTIAL. SEQUENTIAL распределяет тесты равными диапозонами, предварительно отсортировав их по имени. MODULO разделяет тесты по модулю, предварительно их отсортировав.
FORK_SUBTESTS()
FORK_SUBTESTS(mode)
Разбивает запуск suite на несколько chunk’ов. По умолчанию количество chunk’ов равно 10. Это значение можно изменить с помощью макроса SPLIT_FACTOR(x). В отличие от FORK_TESTS может разбивать тесты, объединенные в один класс, в разные chunk’и. Нежелательно использовать, если у классов есть тяжелые подготовительные стадии.
Каждый chunk наследует общие параметры теста из ya.make: размер, таймаут, требования на ресурсы. Поэтому этот макрос удобно использовать, чтобы распараллелить тесты, которые не укладываютсмя в таймаут.
Параметр mode определяет, каким образом будет происходить распределение тестов по chunk’ам. Может быть равен SEQUENTIAL или MODULO. Если аргумент не указан, то по умолчанию равен SEQUENTIAL. SEQUENTIAL распределяет тесты равными диапозонами, предварительно отсортировав их по имени. MODULO разделяет тесты по модулю, предварительно их отсортировав.
FORK_TEST_FILES()
FORK_TEST_FILES()
Разбивает прогон тестов из suite на количество chunk’ов, равное количеству файлов с тестами, перечисленных в ya.make. Каждый запуск работает только с одним конкретным файлом.
Можно комбинировать вместе с FORK_TESTS() и FORK_SUBTESTS(). В этом режиме будет происходить дополнительное разбиение тестов для каждого файла.
Важно
Поддержан только для pytest.
SPLIT_FACTOR()
SPLIT_FACTOR(x)
Изменяет количество chunk’ов при параллельном запуске тестов. Можно использовать только с FORK_TESTS() и FORK_SUBTESTS().
Специфичные макросы
USE_RECIPE()
USE_RECIPE(path [arg1 arg2…])
Подключает рецепт для настройки тестового окружения к тесту. Если тест описан с использованием макросов FORK_TEST() / FORK_SUBTESTS(), то рецепт будет подготавливать отдельное окружение для каждого запуска.
SKIP_TEST()
SKIP_TEST(Reason)
Отключает тесты для всей модульной сьюиты. Параметром указывается причина отключения.
NO_LINT()
NO_LINT()
Отключает codestyle проверки для java и python.
Важно
Использование NO_LINT() разрешено только в contrib.

Канонизация
У тестов есть возможность сообщить о своих результатах в виде данных, которые необходимо сравнить с каноническими.
Чтобы система имела доступ к каноническим данным, их нужно в первый раз канонизировать.
Необходимо отметить, что сравнение с каноническими значениями происходит на стороне ya, следовательно, чтобы иметь возможность верифицировать такие тесты, их надо запускать через ya make.
Каждый фреймворк для написания тестов предоставляет свою поддержку механизма канонизации, описанную в соответствующих разделах.
Канонизация в C++
Важно
На данный момент нативная канонизация в C++ тестах не поддержана.
DEVTOOLS-1467
Ниже описано несколько альтернативных способов автоматически обновлять канонические данные для C++ тестов, помимо нативной канонизации.
Матчер в gtest
Матчер NGTest::GoldenFileEq(filename), доступный в модуле GTEST, умеет сравнивать тестируемые данные с содержимым указанного файла и обновлять этот файл при запуске теста с аргументом --test-param GTEST_UPDATE_GOLDEN=1:
TEST(Suite, Name) {
std::string data = RenderSomeTextData();
EXPECT_THAT(data, NGTest::GoldenFileEq(SRC(“golden/data.txt”)));
}
Мы настоятельно не рекомендуем использовать этот способ для тестирования бинарных данных. В репозитории следует хранить только файлы, изменения в которых можно посмотреть на код-ревью: тексты, конфиги, картинки.
Дополнительный EXECTEST
Можно канонизировать вывод от тестов или выходные файлы с помощью отдельного ya.make с EXECTEST(), который будет зависеть от теста и запускать вручную указанные тесты. Документация про EXECTEST. Также см. пример.
Канонизация в Python
Тест сообщает о данных, которые нужно сравнить с каноническими, путем их возврата из тестовой функции командой return. На данный момент поддерживаются все простые типы данных, списки, словари и файлы:
def test():
return [1, 2.0, True]
Канонизация файлов
Для того, чтобы вернуть файл, необходимо воспользоваться функцией
yatest.common.canonical_file(path, diff_tool=None, local=False, universal_lines=False, diff_file_name=None, diff_tool_timeout=None)
path: путь до файла;
diff_tool: путь к программе для сравнения канонических файлов. По умолчанию используется diff. Нестандартные программы для сравнения канонических файлов;
local: сохранять файл в репозиторий, а не в Sandbox. Мы настоятельно не рекомендуем хранить бинарные канонические файлы в репозитории;
universal_lines: нормализует EOL;
diff_file_name: название для файла с дифом. По умолчанию - <имя сравниваемого файла>.diff);
diff_tool_timeout: таймаут на запуск diff tool.
Для канонизации нескольких файлов, необходимо вернуть список или словарь с объектами canonical_file.
def test1():
return [yatest.common.canonical_file(output_path1), yatest.common.canonical_file(output_path2)]
def test2():
return {
“path1_description”: yatest.common.canonical_file(output_path1),
“path2_description”: yatest.common.canonical_file(output_path2)
}
Канонизация директорий
Для того, чтобы канонизировать содержимое директории, необходимо воспользоваться функцией
yatest.common.canonical_dir(path, diff_tool=None, diff_file_name=None, diff_tool_timeout=None)
path: путь до директории;
diff_tool: путь к программе для сравнения канонических файлов. По умолчанию используется diff. Нестандартные программы для сравнения канонических файлов;
diff_file_name: название для файла с дифом. По умолчанию - <имя сравниваемой директории>.diff);
diff_tool_timeout: таймаут на запуск diff tool.
Важно
Все директории загружаются в sandbox, их нельзя сохранять локально в canondata, в отличие от canonical_file.

Канонизация запуска программы
Для того, чтобы канонизировать stdout программы нужно воспользоваться функцией
yatest.common.canonical_execute(binary, args=None, check_exit_code=True, shell=False, timeout=None, cwd=None, env=None, stdin=None, stderr=None, creationflags=0, file_name=None, save_locally=False)
binary:абсолютный путь до программы;
args: аргументы программы;
check_exit_code: бросает ExecutiopnError, если запуск программы завершается с ошибкой;
shell: использовать shell;
timeout: таймаут на выполнении програмы;
cwd: рабочая директория;
env: окружение для запуска команды;
stdin: поток ввода команды;
stderr: поток ошибок команды;
creationflags: creationFlags команды запуска;
file_name: имя output файла. По умолчанию используется имя программы binary. Конечное название файла будет <file_name>.out.txt
save_locally: сохранять файл в репозиторий, а не в Sandbox. Мы настоятельно не рекомендуем хранить бинарные канонические файлы в репозитории;
diff_tool: путь к программе для сравнения канонических файлов. По умолчанию используется diff. Нестандартные программы для сравнения канонических файлов;
diff_file_name: название для файла с дифом;
diff_tool_timeout: таймаут на запуск diff tool.
Для канонизации stdout запуска python-скриптов можно воспользоваться функцией
yatest.common.canonical_py_execute(script_path, args=None, check_exit_code=True, shell=False, timeout=None, cwd=None, env=None, stdin=None, stderr=None, creationflags=0, file_name=None)
Если нужно канонизировать вывод нескольких программ, то результат canonical_execute можно сохранять в переменные, а в тесте вернуть словарь:
res1 = yatest.common.canonical_execute(binary1)
res2 = yatest.common.canonical_execute(binary2)
return {“stand_initializer”: res1, “prog2”: res2}
Канонизация stdout программы
Канонизация stdout python script
Ожидаемое несоответствие канонизации
В pytest поддерживается механизм xfail (expected to fail), которым размечают тесты, которые падают ожидаемо. Однако, в силу того что канонизация является надстройкой над всеми тестовыми фреймворками, их механизмы никак не могут влиять или управлять процедурой сверки канонических данных. Поэтому тест размеченный xfail и имеющий diff с каноническими данными будет в статусе поломки. Для того чтобы разметить, что у теста канонические данные отличаются от полученных в ходе тестирования или отсутствую канонические данные и это нормально, его нужно разметить маркером @pytest.mark.xfaildiff. В этом случае:
Если тест упадёт он будет в статусе FAIL
Если тест успешно отработает и вернёт канонические данные, но их не с чем будет сравнить (канонизации ещё не было и вы не хотите канонизировать неверные данные) или они будут отличаться, то статус теста будет XFAIL
Если тест успешно отработает и канонические данные совпадут, тест упадёт со статусом XPASS
При канонизации (-Z/–canonize-tests) тесты рамечанные xfaildiff НЕ канонизируются.
xfaildiff в качестве pytest.param и декоратора
Канонизация в Java
Чтобы канонизировать данные, нужно использовать функции из devtools/jtest.
Канонизация объектов
Для канонизации объектов нужно использовать функцию ru.yandex.devtools.test.Canonizer.canonize(Object). Важно помнить, что объект будет сериализован с помощью new Gson().toJson(obj).
Важно
На каждый тест может быть только один вызов ru.yandex.devtools.test.Canonizer.canonize(Object): если их будет несколько, последний перетрет изменения всех предыдущих.

Канонизация файлов
Для того, чтобы канонизировать файл, нужно использовать ru.yandex.devtools.test.CanonicalFile.
По умолчанию все файлы загружаются в Sandbox. Чтобы сохранить локально, нужно задать параметр local в true. Мы настоятельно не рекомендуем хранить бинарные канонические файлы в репозитории.
Помимо обычного diff, можо использовать кастомный diff_tool. Подробнее, как правильно его оформлять, описано здесь.
Если в качестве diff_tool используется JAVA_PROGRAM, то в таком варианте путь к ней необходимо передавать вместе с путем до java.
Использование JAVA_PROGRAM как diff tool
Канонизация в Go
Для канонизации данных нужно использовать library/go/test/canon.
Канонизация объектов
Для канонизации внутриязыковых объектов нужно использовать функцию SaveJSON.
Пример
Канонизация внутреязыковых объектов
Канонизация файлов
Для того, чтобы канонизировать файл, нужно использовать SaveFile.
По умолчанию все канонизированные файлы загружаются в mds/sandbox.Чтобы сохранять эти файлы локально, нужно в фукнцию SaveFile передать аргумент canon.WithLocal(true).
Помимо обычного diff, можо использовать кастомный diff_tool. Подробнее, как правильно его оформлять, описано здесь.

Канонизация с нестандартным diff tool
Diff tool для сравнения канонических файлов и директорий
По умолчанию, во всех фреймворках для сравнения канонизированных данных используется diff, но для каждого языка есть возможность использовать кастомный diff tool.
Для того, чтобы переопределить программу для сравнения канонических файлов, нужно:
Добавить в секцию DEPENDS теста путь к ya.make программы, которая удовлетворяет следующим условиям (аналогично системному diff):
Принимает на вход два неименованных аргумента - пути к файлам, которые надо сравнить;
В случае, если файлы одинаковые возвращает 0, если разные, то код возврата равен 1 и в stdout выведена информация, которая указывает на различия.
В тестах в соответствующих функциях для канонизации файла или директории передать путь к програме.
Примечание
Программа сравнения вызывается только в случае расхождения чек-суммы полученного тестом файла с каноническим: это надо учитывать при отладке diff tool.
Как канонизировать
Для того, чтобы канонизировать результат теста, нужно воспользоваться опцией -Z, --canonize-tests:
ya make -tF <test name> --canonize-tests [–owner <owner> --token <sandbox token>]
Канонический результат будет сохранен рядом с тестом в репозитории в директорию canondata/<test name>/result.json или вынесен в ресурс Sandbox, в зависимости от переданных параметров в тесте. Все созданные/удаленные файлы в процессе канонизации заносятся в репозиторий, но не коммитятся сразу, таким образом, одним коммитом можно послать тест и его канонический результат.
Важно
Не меняйте руками никакие данные внутри директории canondata - это приведёт к тому, что тест будет работать некорректно, потому что до сверки канонических данных ya make проверяет чек-суммы из canondata/result.json, и если они расходятся, то только в этом случае строит diff. Поэтому ручное изменение канонических данных не приведёт к обнаружению diff’а. Всегда переканонизируйте результаты с помощью ya make -AZ.
Внимание
Нам известно, что иногда при переканонизации тестов возникает ошибка, когда тест не может достать данные для канонизации из кэша. Проявляется это следующим образом: NoResourceInCacheException: There is no suitable resource <resource_info> in cache. При возникновении у вас такой проблемы, пожалуйста, обратитесь в DEVTOOLSSUPPORT с приложенной информацией о падении, для этого:
Добавьте в ya.make падающих тестов следующие тэги: TAG(ya:dump_node_env ya:dump_test_env)
Запустите ваши тесты еще раз и загрузите получившуюся директорию test-results в sandbox: ya upload test-results
Создайте тикет в devtoolsupport https://forms.ypurdomen.xx/surveys/devtools/ c описанием проблемы и приложите ссылку на полученный в предыдущем пункте ресурс
Чтобы починить эту проблему, нужно удалить кэш ya. Для этого можно вызвать следующую команду: ya gc cache --size-limit 0
Канонизация в Sandbox
Канонизировать результаты тестов можно с помощью sandbox задач YA_MAKE и YA_MAKE_2.
Для этого нужно:
в поле Targets указать путь до теста;
выбрать Run tests;
выбрать Canonize tests.
Дополнительные опции канонизации
–owner: имя владельца ресурса с каноническими данными в Sandbox. По умолчанию, имя текущего пользователя;
–user: имя пользователя для авторизации в Sandbox. По умолчанию, имя текущего пользователя;
–token: токен для авторизации в Sandbox. Необходимо получить на странице в Sandbox. Если токен не передан, будет произведена попытка авторизации по SSH-ключам (поддерживаются rsa/dsa-ключи), которые ожидаются или в ~/.ssh, или в SSH-агенте. Публичная часть ключа должна быть загружена на Стафф;
–key: путь к приватной части rsa/dsa-ключа для авторизации в Sandbox. Публичная часть этого ключа должна быть загружена на Стафф;
Если протокол загрузки канонических данных в Sandbox не задан, то предпочтение будет отдано http. Протокол можно задать явно:
–canonize-via-skynet: загрузка только через протокол skynet: на канонические данные, которые нужно загрузить в Sandbox, делается sky share, потом rbtorrent-ссылка используется для загрузки;
–canonize-via-http: загрузка только через протокол http.
Просмотр ретроспективы канонического результата теста
Для того, чтобы посмотреть, как менялся канонический результат теста, нужно прогнать конкретный тест в режиме --canon-diff ya make -t --canon-diff PREV.
Можно передать имя теста через параметр -F(–test-filter), для этого можно сначала вывести список тестов в текущей папке ( ircadii/ya make -t --canon-diff HEAD -L);
В качестве аргумента --canon-diff можно передать PREV, HEAD, <rev1>:<rev2>. Данным режимом удобно пользоваться, когда результат частично или целиком был загружен в Sandbox, и svn diff не очень помогает.
Скачивание канонических данных из разных хранилищ
Данный режим может быть полезен, если ваши тесты могут запускаться как внутренними, так и внешними людьми без доступов к аркадийным сервисам. Такой сценарий может возникнуть, например, если ваш проект живет одновремменно и в ИРАКАДИИ и в opensource.
Канонизация с указанием backend
Чтобы результаты канонизации могли быть переиспользованы разными backend-ами, нужно при канонизации тестов добавить --canonization-backend=“storage.ypurdomen.xx/get-devtools”. При таком запуске, результаты канонизации будут загружены в mds-хранилище, но backend в canondata будет записан в виде шаблона, который может резолвиться в canonization-backend.
Параметризация backend
Чтобы подменить backend при запуске тестов с канонизацией, нужно указать --canonization-backend=”<custom_backend>“, где custom_backend - это http-хранилище, куда вы сами загрузили результаты канонизации.
Если тесты канонизировались с использованием бэкенда, но --canonization-backend при запуске тестов не был указан, то будет использоваться storage.ypurdomen.xx/get-devtools
Параметризация протокола
При запуске тестов с указанием кастомного бэкенда, вы можете сами выбрать протокол для скачивания канонических данных с помощью опции --canonization-scheme. Если этот параметр не указан, будет использоваться https.
Формат
После канонизации, рядом с тестом появляется файл canondata/result.json внутри него лежат ссылки, куда были загружены канонические данные. В случае запуска канонизации без дополнительных опций, канонизационные backend’ы в этих ссылках будут указаны явно. При указании --canonization-backend, в ссылках вместо явного укзаания бэкенда, будет присутствовать место для его подстановки.
Внутри canondata/result.json нас будет интересовать поле uri у канонических данных. Внутри этого поля лежат ссылки для скачивания канонических данных.
Без --canonization-backend:
uri: https://storage.ypurdomen.xx/get-devtools/1936842/8e0725ae6bf6a51c5b510adf7ab5b65a0a685a8f/resource.tar.gz#exectest.run_hello_world/stdout.out
С --canonization-backend
uri: https://{canondata_backend}/1809005/61174eb05585f2f1c67e0387c436e184f0ccc131/resource.tar.gz#exectest.run_hello_world0_/stdout.out
рассмотри подробнее формат uri:
схема - https
бэкенд - storage.ypurdomen.xx/get-devtools
путь до архива в mds-storage - 1936842/8e0725ae6bf6a51c5b510adf7ab5b65a0a685a8f/resource.tar.gz
путь до файла внутри архива - exectest.run_hello_world_/stdout.out
При загрузке данных в пользовательский storage, нужно сохранить формат uri, изменив только бэкенд и, возможно протокол, чтобы после подстановки вашего backend в uri получалась валидная ссылка.
Проверки кода и корректности данных
Система сборки поддерживает разнообразные проверки стиля и кода. Большинство из них является opt-out, т.е. подключаются автоматически, с возможностью отключения. ya test / ya make -t поддерживает ключ --style, который запускает только style-тесты и легковесные проверки, к которым не относятся регулярные тесты.
Если запускаемые проверки не зависят от сборки, то ya test --style запустит только линтеры, без сборки.
Примечание
Все style-тесты по умолчанию кешируются, что эквивалентно команде ya test --cache-tests. Это значит, что при перезапуске ya test без изменения исходного кода style-тесты не будут перезапускаться, а вернут результат из кеша. Это сделано для ускорения локального прогона style-тестов, которые являются быстрыми и стабильными. Для принудительного перезапуска тестов нужно добавить ключ --retest.
python
flake8
Все python-файлы, используемые в сборке и тестах, подключаемые через ya.make в секциях PY_SRCS и TEST_SRCS, автоматически проверяются линтером flake8.
Допустимая длина строки установлена в 200 символов.
В редких случаях можно игнорировать конкретные строки целиком, указывая конкретные коды ошибок, добавляя к нужной строке комментарий # noqa или # noqa: E101.
Внутри init.py можно подавлять только ошибку F401 Module imported but unused с помощью комментария # flake8 noqa: F401 в начале файла.
Примечание
Только для директории contrib допустимо отключение проверки стиля макросом NO_LINT().
В ИРАКАДИИ используется единый конфиг, через который включаются некоторые плагины. Изменения в конфиге должны быть согласованы с python-com@.
Важно
Если локально у вас есть ошибки flake8, которых нет в Автосборке/CI, скорей всего вы столкнулись с вашим техдолгом, см. документацию о миграциях.
Для временного отключения подобных ошибок используйте запуск YA_TEST_DISABLE_FLAKE8_MIGRATIONS=0 ya test и запланируйте починку.
Коды ошибок описаны на следующих страницах:

flake8rules.com
pypi.org/project/flake8-commas
pydocstyle.org
bandit.readthedocs.io
black
Для проектов на python3 можно добавить макрос STYLE_PYTHON(), который будет генерировать тест, проверяющий соответствие кода в модуле аркадийному style guide. В качестве линтера использует black c минимальным конфигом, который применяется в ya style.
Примечание
Макрос STYLE_PYTHON() можно указывать только для типов модулей PY3* и PY23*.
Быстро добавить макрос в проект можно командой:
cd <project>
ya project macro add STYLE_PYTHON --recursive --quiet --after PY3_LIBRARY --after PY23_LIBRARY --after PY3TEST --after PY23_TEST --after PY3_PROGRAM
Для запуска только black тестов внутри проекта используйте команду ya test --test-type black.
Для автоматического применения ya style в PyCharm см. заметку от srg91.
python imports
Для программ PY2_PROGRAM, PY3_PROGRAM, PY2TEST, PY3TEST, PY23_TEST, собранных из модулей на Python, есть проверка внутренних модулей на их импортируемость - import_test. Импорт-тесты не являются style-тестами и не входят в множество тестов --style, так как требуют сборку. Импорт-тесты обнаруживают на ранних стадиях конфликты между библиотеками, которые подключаются через PEERDIR, а также указывают на неперечисленные в PY_SRCS файлы (но TEST_SRCS не проверяется).
Проверять герметичность каждого модуля python достаточно дорого - требуется сборка python и его компоновка с целевым модулем только для одного теста, поэтому проверка импортируемости добавляется только для исполняемых программ, которые будут работать в таком виде на production. По этой причине проверяются только модули, подключаемые к сборке через PY_SRCS, но не через TEST_SRCS.
Проверку можно отключить c помощью макроса NO_CHECK_IMPORTS. Он принимает список масок модулей, которые не нужно проверять:
NO_CHECK_IMPORTS(
devtools.pylibrary.
)
В программах можно написать NO_CHECK_IMPORTS() без параметров, чтобы полностью отключить проверку импортов.
Бывает, что в общих библиотеках импорты происходят по условию, например в psutil:
if sys.platform.startswith(“win32”):
import psutil._psmswindows as _psplatform
При этом сама библиотека остаётся работоспособной, но импорт-тест будет падать, потому что проверяет все модули, влинкованные в бинарник, а у psutil._psmswindows есть зависимость от Windows. В таком случае надо написать:

NO_CHECK_IMPORTS(
psutil.psmswindows
)
Примечание
Информацию о времени загрузки импортированных модулей после исполнения импорт-теста записывается в файл .import_test.out соответсвующего теста. В конце файла можно найти список самых медленных импортов, исполненных в тесте.
Примечание
Если информации о времени исполнения импортов недостаточно и хочется получить больше деталей о причинах медленной загрузки модулей, то можно отпрофилировать основную точку входа импорт-теста, используя ваш любимы профайлер (например cProfile).
java
java style
На все исходные тексты на Java, которые подключены через ya.make в секции JAVA_SRCS, запускаются автоматические проверки java codestyle. Проверки осуществляются при помощи утилиты [checkstyle](http://checkstyle.sourceforge.net checkstyle) версии 7.6.1.
Мы поддерживаем 2 уровня “строгости” - обычный и строгий (большее количество проверок). Строгий уровень включается макросом LINT(strict) в ya.make.
Конфигурационные файлы checkstyle для обычных и строгих проверок находятся в директории resource, табличка с описанием находится тут.
java classpath clashes
Есть опциональная проверка дублирующихся классов в classpath при компиляции java проекта. Проверяется имя класса и хэш файла с его исходным кодом, то есть идентичные классы из разных библиотек проблем вызывать не должны. Проверка включается макросом CHECK_JAVA_DEPS(yes) в ya.make.
kotlin
ktlint
Автоматически добавляется к проектам на Kotlin, которые используют нашу систему сборки. Подробнее про утилиту можно узнать тут.
Для отключения ktlint достаточно в ya.make файле модуля написать NO_LINT(ktlint).
При запусках ktlint использует корневой .editorconfig.
Исключения ktlint
Для проекта можно настроить временные исключения из правил.
Применять исключения нужно крайне редко в сложных случаях, например, при миграциях на новый ktlint и при наличии множества ошибок, которые нельзя исправить автоматически после выполнения команды ktlint -F.
В случае применения исключений разработчик обязан создать тикет на исправление всех ошибок в исключении и запланировать его выполнение.
Как добавить исключения в проверки:
Создать файл с исключениями путем выполнения команды из корня ircadii ya tool ktlint {path-to-project} --baseline={path-to-project}/{path-to-file}.
Создать тикет в очередь проекта на исправление всех ошибок в исключении.
Добавить в ya.make проекта макрос с указанием относительного пути до файла с исключениями и ссылку на тикет с исправлениями. Например, KTLINT_BASELINE_FILE(ktlint-baseline.xml “https://st.ypurdomen.xx/REMOVE-BASELINE-1”)
go
gofmt
Автоматически добавляется к проектам на go, является проверкой стиля. Подробнее см. документацию к gofmt.
govet
Автоматически добавляется к проектам на go, является статической проверкой, позволяющей находить подозрительные конструкции и плохие практики. Подробнее см. документацию.
cpp
clang tidy
Clang-tidy запускается с помощью ya test -DTIDY, так как требует полностью другой граф сборки. Подробнее см. отдельный раздел про clang tidy.
frontend
eslint
Автоматически добавляется к проектам на TypeScript, использует ESLint. Проверяет стиль кода и типичные ошибки. Набор правил лежит здесь. Для отключения eslint достаточно в ya.make файле модуля написать NO_LINT().
external resources
sandbox resource
Не является style-тестом. В тестах можно использовать Sandbox-ресурсы в виде зависимостей. Такие ресурсы должны иметь ttl = inf, чтобы тесты сохраняли свою работоспособность даже после того, как новая версия теста начнёт использовать другую версию ресурса. Поэтому ко всем suite, использующим Sandbox-ресурсы, добавляется автоматический тест validate_resource, который проверяет ttl ресурса.
Так как тест обязан кешироваться, то он зависит исключительно от номера ресурса, в противном случае на каждый коммит в Аркадию все такие тесты пришлось бы перезапускать, тратя ресурсы и создавая нагрузку на Sandbox.
Поэтому в случае обнаружения ошибки в PR и исправления ttl у ресурса, в новых итерациях он не перестанет падать. Для этого в ya.make с падающих тестов нужно добавить вызов макроса VALIDATE_DATA_RESTART(Х), где в качестве X указать текущую head-ревизию репозитория. Это значение добавится к расчёту uid теста и в новой итерации в PR тест будет перезапущен.
Подробней о VALIDATE_DATA_RESTART см в документации к макросу DATA.
Проверку можно отключить макросом DISABLE_DATA_VALIDATION().
clang tidy
Для C++ поддержан линтинг исходного кода, из LIBRARY, PROGRAM, DLL, G_BENCHMARK, UNITTEST, GTEST с помощью clang-tidy. Для запуска линтинга нужно вызвать ya make -t -DTIDY.
Примечание
При запуске ya make с флагом -DTIDY, вместо узлов компиляции запускается clang-tidy для соответствующих исходников. В этом режиме сборки не происходит, так как граф строится в другой конфигурации, хотя и генерируются все необходимые зависимости для тайдинга. Поэтому clang-tidy тесты, и только они могут быть запущены при указании -DTIDY.
По умолчанию clang-tidy использует базовый аркадийный конфиг. Изменения в этом конфиге должны быть согласованы с cpp-com@.
Чтобы подключить свой проект к линтингу в автосборке, укажите нужный путь в этом файле.
Некоторые ошибки, обнаруженные с помощью проверок в clang-tidy, могут быть автоматически исправлены. В этом случае в сниппете suite будет написана команда для их автоматического исправления с помощью ya clang-tidy --fix.
Кастомные конфиги для clang-tidy
Если ваш проект уже подключен к тайдингу в автосборке и вам хочется расширить множество проверок, вы можете воспользоваться механизмом проектных конфигов для clang-tidy
Немного терминологии
Базовый конфиг - Конфиг, описывающий основные проверки и их опции для проверок clang-tidy. Конфиг декларируется тут. При создании нового базового конфига, туда заносятся только те проверки и опции, который конфликтуют с ircadii style guide. Если ваш проект использует аркадийный стиль, вам не нужно создавать свой базовый конфиг!
Базовый общеаркадийный конфиг - конфиг, по умолчанию являющийся базовым. в этом конфиге описываются основные опции и проверки из ircadii style guide.
Проектный конфиг - конфиг, относящийся к отдельному проекту. Создается авторами проектов, декларируется тут. Этот конфиг будет объединен с базовым конфигом, который используется в вашем проекте.
Ограничения, накладываемые на проектный конфиг
Конфиг не должен противоречить ircadii-style-guide.
Проверки из конфига не должны сильно замедлять тайдинг.
Для выполнения этих требований мы завели whitelist доступных проверок и их опций. Проверки, не перечисленные в whitelist, будут удалены из конфига. Любые изменения whitelist должны быть одобрены cpp-com@.
Создание своего конфига
clang-tidy конфиг - это yaml файл, в котором перечислены проверки и их опции. Список доступных проверок можно найти тут. Список опций для проверки можно найти на странице проверки. пример готового конфига.
Подключение проектного конфига к автосборке
Чтобы в автосборке начал работать ваш конфиг, достаточно добавить ваш проект в словарь. В этом словаре ключ - это префикс относительно корня ircadii, к которому будет применяться ваш конфиг, а значение - путь до конфига относительно корня ircadii.
Конфиги для проектов, не соответствующих аркадийному style-guide
Если ваш проект использует стиль, отличный от аркадийного, вам нужно создать свой базовый конфиг. Чтобы задекларировать ваш базовый конфиг в системе сборки, вы должны добавить этот конфиг в словарь, по аналогии с проектным конфигом. Сам конфиг стоит положить в директорию, где лежат другие базовые конфиги.
В новом базовом конфиге должны содержаться только проверки и опции, которые конфликтуют с ircadii-style-guide.
Остальная часть конфига должна быть вынесена в ваш проектный конфиг.
Создание и изменение вашего базового конфига должно быть согласовано с cpp-com@
С каким конфигом будет запускаться проверка?
Итоговый конфиг будет сконструирован из вашего проектного конфига и базового конфига. Вот как это будет происходить:
Отфильтруются все проверки и опции из проектного конфига, в соответствии с whitelist.
В итоговый конфиг добавятся оставшиеся проверки из проектного конфига.
В итоговый конфиг добавятся проверки из базового конфига.
В итоговый конфиг добавятся все опции из базового и проектного конфигов, при возникновении конфликтов побеждает проектный конфиг.
схема получения конфига
Из-за фильтрации проектного конфига и дальнейшего объединения с базовым, может быть непонятно, с каким конфигом запускается clang-tidy в автосборке. Чтобы решить эту проблему, в хендлере ya clang-tidy поддержана опция --show-autocheck-config, которая выведет финальный автосборочный конфиг на экран.
Локальный запуск с проектным конфигом
ya make -A -DTIDY - запустит ваши clang-tidy тесты “как в автосборке”
ya clang-tidy --use-autocheck-config - Вариант, аналогичный предыдущему.
ya clang-tidy --use-autocheck-config --fix - попытается починить обнаруженные проблемы. Если перед этим запускался вариант (2), то результаты тайдинга возьмутся из кэша.
ya clang-tidy - запустит проверку с вашим проектным конфигом, игнорируя whitelist и базовый конфиг
Включение tidy в CLion
Для того чтобы CLion подхватил Аркадийный конфиг clang-tidy нужно сгенерировать проект, добавив опцию --setup-tidy.
Для того чтобы не нужно было постоянно указывать ключ, его можно указать в конфиге ya, добавив секцию вида:
[ide.clion]
setup_tidy = true
Подробней о настройке CLion проекта можно почитать в документации ya ide clion.
Включение tidy в VS Code
Для того чтобы VS Code подхватил Аркадийный конфиг clang-tidy нужно:
установить clang-tidy plugin
сгенерировать VS Code проект, выполнив ya ide vscode-clangd --setup-tidy в директории нужного проекта
Для того чтобы не нужно было постоянно указывать ключ, его можно указать в конфиге ya, добавив секцию вида:
[ide.vscode-clangd]
setup_tidy = true

Тесты : запуск произвольных программ
Данный тип тестов позволяет выполнить произвольную команду и убедиться, что она успешно завершается.
Примечание
Примеры exec-тестов можно найти здесь.
Успешным считается завершение команды с кодом возврата 0.
Стандартные программы unix и команды shell не доступны, некоторые аналоги можно подключить через DEPENDS.
Простое описание теста в ya.make выглядит так:
OWNER(g:some-group)
EXECTEST() # Объявляем Exec-тест

RUN( # Команда, которую хотим выполнить
cat input.txt
)
DATA( # Тестовые данные (здесь лежит input.txt)
ircadii/devtools/ya/test/tests/exectest/data
)
DEPENDS( # Зависимость от других проектов (здесь лежат исходные коды cat)
devtools/dummy_ircadii/cat
)
# Текущий каталог для теста (каталог с input.txt)
TEST_CWD(devtools/ya/test/tests/exectest/data)
END()
В общем случае в одном ya.make можно объявить несколько разных команд:
OWNER(g:some-group)
EXECTEST()
RUN( # Первый тест
NAME test-1 # Явное объявление имени теста
echo “1”
)
RUN( # Второй тест
NAME test-hello-world
echo “Hello, world!”
)
END()
Каждое объявление макроса RUN - это отдельный тест. Тесты выполняются в том порядке, в котором перечислены в файле.
Важно
При параллельном запуске тестов в каждый из параллельно выполняемых потоков попадает только часть команд, указанных в ya.make. Поэтому не рекомендуется писать команды, результаты выполнения которых зависят от выполнения команд из вышестоящих макросов RUN.
В общем виде макрос RUN предоставляет множество других возможностей:
OWNER(g:some-group)
EXECTEST()
RUN(
NAME my-test # Имя теста
ENV TZ=Europe/Moscow
ENV LANG=ru_RU.UTF-8 # Переменные окружения
echo “1” # Команда и ее флаги
STDIN {IRCADII_ROOT}/my-project/filename.txt # Файл, который подается с stdin команде
STDOUT {TEST_CASE_ROOT}/test.out # Куда сохранить stdout команды
STDERR {TEST_CASE_ROOT}/test.err # Куда сохранить stderr команды
CWD {IRCADII_BUILD_ROOT}/my-project # Рабочий каталог теста
CANONIZE {TEST_CASE_ROOT}/test.out # Путь до файла с эталонными данными (будет сохранен в Sandbox)
CANONIZE_LOCALLY {TEST_CASE_ROOT}/test.out # Путь до файла с эталонными данными (будет сохранен в подкаталог canondata)
CANONIZE_DIR {TEST_CASE_ROOT}/dir # Путь до директории с эталонными данными (будет сохранён в Sandbox)
CANONIZE_DIR_LOCALLY {TEST_CASE_ROOT}/dir # Путь до директории с эталонными данными (будет сохранен в подкаталог canondata)
DIFF_TOOL my-project/tools/my-difftool/my-difftool # Путь до исполняемого файла, используемого для сравнения вывода теста с эталонными данными
DIFF_TOOL_TIMEOUT # Таймаут на запуск diff_tool
)
DEPENDS(
my-project/tools/my-difftool
)
END()
Для указания путей доступны следующие переменные:
Переменная Описание
{IRCADII_BUILD_ROOT} Корень сборочной директории
{IRCADII_ROOT} Корень единого репозитория
{TEST_SOURCE_ROOT} Путь к каталогу, в котором находится ya.make-файл текущего теста
{TEST_CASE_ROOT} Путь к каталогу с результатами текущего теста
{TEST_WORK_ROOT} Путь к рабочему каталогу теста
{TEST_OUT_ROOT} Путь к каталогу с результатами прохождения всех тестов (результаты каждого теста лежат во вложенном каталоге)
Внимание
Программы, подключенные по DEPENDS не складываются в Аркадию, после исполнения теста там может оказаться симлинк, но во время исполнения теста программы там нет. Не используйте {IRCADII_ROOT} для указания пути до запускаемой программы. Бинари обычно доступны вообще без указания пути, но путь от корня Ircadii (без указания корня) тоже сработает.
Полезные программы
not - инвертирует выходной код нормально завершившейся программы. Иногда нужно проверить, что тестируемая программа при нужных условиях завершается с ненулевым кодом (но не падает и не выходит по сигналу). Не стоит злоупотреблять такими тестами. Пример:
RUN(
NAME “my_program fails with wrong arguments”
not my_program wrong arguments
)
DEPENDS(
my_project/my_program
tools/not
)
Тесты
Unit-тесты в Ircadii оформляются в виде отдельных целей со своим ya.make. Для их запуска используется команда ya make -t. Подробности есть в документации ya; см. также: RECURSE_FOR_TESTS.
Для написания тестов у нас имеется два фреймворка: unittest (наша собственная разработка) и gtest (популярное решение от Google). Также есть библиотека library/cpp/testing/common, в которой находятся полезные утилиты, не зависящие от фреймворка.
Поддержка gtest в Ircadii появилась недавно, поэтому фреймворк не очень распространен. Тем не менее, у него есть ряд преимуществ по сравнению с unittest:
очень подробно выводится контекст, когда ломается тест;
два семейства макросов для сравнения: ASSERT останавливает тест, EXPECT отмечает тест как проваленный, но не останавливает его, давая возможность выполнить остальные проверки;
возможность расширять фреймворк с помощью механизма матчеров;
можно использовать gmock (справедливости ради заметим, что gmock можно использовать и в unittest; однако в gtest он проинтегрирован лучше, а проекты уже давно объединены);
можно сравнивать некоторые типы — и даже получать относительно понятное сообщение об ошибке — даже если не реализован operator<<;
интеграция почти с любой IDE из коробки;
фреймворк известен во внешнем мире, новичкам не нужно объяснять, как писать тесты;
есть поддержка fixtures (в unittest тоже есть, но имеет существенные недостатки реализации);
есть поддержка параметрических тестов (один и тот же тест можно запускать с разными значениями входного параметра);
можно использовать в open-source проектах.
К недостаткам gtest можно отнести:
отсутствие поддержки аркадийных стримов. Впрочем, для популярных типов из util мы сделали собственные реализации PrintTo;
отсутствие макроса, проверяющего, что код бросает ошибку с данным сообщением. Мы сделали такой макрос сами, а также добавили несколько полезных матчеров;
Четких рекомендаций по выбору фреймворка для тестирования нет — руководствуйтесь здравым смыслом, обсудите с командой, взвесьте все «за» и «против». Учитывайте, что при смене типа тестов с unittest на gtest потеряется история запуска тестов в CI. Впрочем, если ваши тесты не мигают (а мы очень на это надеемся), история вам и не нужна.
Gtest
Подробная документация по gtest доступна в официальном репозитории gtest и gmock. Этот раздел дает лишь базовое представление о фреймворке, а также описывает интеграцию gtest в Аркадию.
Для написания тестов с этим фреймворком используйте цель типа GTEST. Минимальный ya.make выглядит так:
GTEST()
OWNER(…)
SRCS(test.cpp …)
END()
Поддерживаются стандартные для Ircadii настройки тестов: TIMEOUT, FORK_TESTS и прочие. Подробнее про это написано в документации ya.
Внутри cpp файлов с тестами импортируйте library/cpp/testing/gtest/gtest.h. Этот заголовочный файл подключит gtest и наши расширения для него. Для объявления тестов используйте макрос TEST. Он принимает два параметра: название группы тестов (test suite) и название конкретного теста.
Примечание
В ircadii своя реализация функции main, реализовывать ее не нужно. Для кастомизации своих тестов можно воспользоваться хуками из library/cpp/testing/hook.
Пример минимального cpp файла с тестами:
#include <library/cpp/testing/gtest/gtest.h>

TEST(BasicMath, Addition) {
EXPECT_EQ(2 + 2, 4);
}

TEST(BasicMath, Multiplication) {
EXPECT_EQ(2 * 2, 4);
}
Для выполнения проверок в теле теста используйте специальные макросы. Они, в отличие от стандартных Y_ASSERT и Y_ABORT_UNLESS, умеют печатать развернутые сообщения об ошибках. Например, ASSERT_EQ(a, b) проверит, что два значения равны; в случае, если это не так, макрос отметит тест как проваленный и остановит его.

Каждый макрос для проверки имеет два варианта: ASSERT останавливает тест, EXPECT — нет. По-умолчанию используйте EXPECT, так вы получите больше информации после запуска тестов. Используйте ASSERT только если проверяете условие, от которого зависит корректность дальнейшего кода теста:

TEST(EtheriaHeart, Activate) {
auto result = NEtheria::Activate();

// Если указатель нулевой, последующие проверки приведут к UB.
ASSERT_NE(result, nullptr);

EXPECT_EQ(result->Code, 0);
EXPECT_EQ(result->ConnectedCrystals, 5);
EXPECT_GE(result->MaxPower, 1.5e+44);
}
Полный список доступных макросов есть в официальной документации и документации по продвинутым возможностям gtest.
Также gtest позволяет добавить к каждой проверке пояснение. Оно будет напечатано если проверка провалится. Для форматирования пояснений используется std::ostream:
TEST(LotrPlot, Consistency) {
EXPECT_GE(RingIsDestroyed() - FrodoLeftHobbiton(), TDuration::Days(183))
<< no, eagles were not an option because << Reasons();
}
Для более сложных проверок предусмотрен механизм матчеров. Например, проверим, что контейнер содержит элемент, удовлетворяющий определенному условию:
TEST(GtestMatchers, SetElements) {
THashSet<TString> elements{“water”, “air”, “earth”, “fire”};
EXPECT_THAT(elements, testing::Contains(“air”));
EXPECT_THAT(elements, testing::Contains(testing::StrCaseEq(“Fire”)));
}
Наши расширения добавляют макрос для проверки сообщений в исключениях:
TEST(YException, Message) {
EXPECT_THROW_MESSAGE_HAS_SUBSTR(
ythrow yexception() << “black garnet is not active”,
yexception,
“not active”);
Для тестирования кода, прекращающего выполнение приложения (например, выполняющего Y_ASSERT или Y_ABORT_UNLESS), используйте макросы EXPECT_DEATH, EXPECT_DEBUG_DEATH, ASSERT_DEATH, ASSERT_DEBUG_DEATH:
TEST(Vector, AccessBoundsCheck) {
TVector<int> empty{};
EXPECT_DEBUG_DEATH(empty[0], “out of bounds”);
}
Матчер NGTest::GoldenFileEq(filename) описан в разделе канонизация.
Unittest
Для написания тестов с этим фреймворком используйте цель типа UNITTEST. Минимальный ya.make выглядит так:
UNITTEST()
OWNER(…)
SRCS(test.cpp …)
END()
Поддерживаются стандартные для Ircadii настройки тестов: TIMEOUT, FORK_TESTS и прочие. Подробнее про это написано в документации ya.
Внутри cpp файлов с тестами подключите library/cpp/testing/unittest/registar.h.
Важно

Не подключайте файл library/cpp/testing/unittest/gtest.h — это deprecated интерфейс unittest, который пытается выглядеть как gtest.
Для объявления группы тестов используйте макрос Y_UNIT_TEST_SUITE. Для объявления тестов внутри группы используйте макрос Y_UNIT_TEST.
Пример минимального cpp файла с тестами:
#include <library/cpp/testing/unittest/registar.h>

Y_UNIT_TEST_SUITE(BasicMath) {
Y_UNIT_TEST(Addition) {
UNIT_ASSERT_VALUES_EQUAL(2 + 2, 4);
}

Y_UNIT_TEST(Multiplication) {
UNIT_ASSERT_VALUES_EQUAL(2 * 2, 4);
}
}
Для выполнения проверок в теле теста используйте специальные макросы:
Макрос Описание
UNIT_FAIL(M) Отметить тест как проваленный и остановить его.
UNIT_FAIL_NONFATAL(M) Отметить тест как проваленный но не останавливать его.
UNIT_ASSERT(A) Проверить, что условие A выполняется.
UNIT_ASSERT_EQUAL(A, B) Проверить, что A равно B.
UNIT_ASSERT_UNEQUAL(A, B) Проверить, что A не равно B.
UNIT_ASSERT_LT(A, B) Проверить, что A меньше B.
UNIT_ASSERT_LE(A, B) Проверить, что A меньше или равно B.
UNIT_ASSERT_GT(A, B) Проверить, что A больше B.
UNIT_ASSERT_GE(A, B) Проверить, что A больше или равно B.
UNIT_ASSERT_VALUES_EQUAL(A, B) Проверить, что A равно B. В отличие от UNIT_ASSERT_EQUAL, воспринимает char как null-terminated строку, а также печатает значения переменных с помощью IOutputStream при провале проверки.
UNIT_ASSERT_VALUES_UNEQUAL(A, B) Проверить, что A не равно B. В отличие от UNIT_ASSERT_UNEQUAL, воспринимает char* как null-terminated строку, а также печатает значения переменных с помощью IOutputStream при провале проверки.
UNIT_ASSERT_DOUBLES_EQUAL(E, A, D) Проверить, что E и A равны с точностью D.
UNIT_ASSERT_STRINGS_EQUAL(A, B) Проверить, что строки A и B равны. В отличие от UNIT_ASSERT_EQUAL, воспринимает char* как null-terminated строку.
UNIT_ASSERT_STRINGS_UNEQUAL(A, B) Проверить, что строки A и B не равны. В отличие от UNIT_ASSERT_UNEQUAL, воспринимает char* как null-terminated строку.
UNIT_ASSERT_STRING_CONTAINS(A, B) Проверить, что строка B является подстрокой в A.
UNIT_ASSERT_NO_DIFF(A, B) Проверить, что строки A и B равны. Печатает цветной diff строк при провале проверки.
UNIT_ASSERT_EXCEPTION(A, E) Проверить, что выражение A выбрасывает исключение типа E.
UNIT_ASSERT_NO_EXCEPTION(A) Проверить, что выражение A не выбрасывает исключение.
UNIT_ASSERT_EXCEPTION_CONTAINS(A, E, M) Проверить, что выражение A выбрасывает исключение типа E, сообщение которого содержит подстроку M.
У каждого макроса UNIT_ASSERT есть версия UNIT_ASSERT_C, позволяющая передать пояснение к проверке. Например:
UNIT_ASSERT_C(success, “call should be successful”);
UNIT_ASSERT_GT_C(rps, 500, “should generate at least 500 rps”);
Mock
Для реализации mock-объектов мы используем gmock. Если вы используете gtest, gmock подключен автоматически. Если вы используете unittest, для подключения gmock нужно добавить PEERDIR на library/cpp/testing/gmock_in_unittest и импортировать файл library/cpp/testing/gmock_in_unittest/gmock.h.
Доступ к зависимостям
Если вы используете в своем ya.make зависимости, то обращаться к таким данным в коде теста нужно, используя библиотеку library/cpp/testing:
#include <library/cpp/testing/common/env.h>
void ReadDependency() {
// Путь до файла/директории из репозитория, описанных с помощью макроса DATA(“ircadii/devtools/dummy_ircadii/cat/main.cpp”)
TString testFilePath = ArcadiaSourceRoot() + “/devtools/dummy_ircadii/cat/main.cpp”;

// Путь до Sandbox-ресурса, описанного макросом DATA(sbr://53558626) # test.txt
TString sandboxResourcePath = GetWorkPath() + “/test.txt”;

// Путь до файла из DEPENDS(“devtools/dummy_ircadii/cat”)
// Обратите внимание: путь в DEPENDS указывает до сборочной цели, а BinaryPath требует указания пути до файла
TString binaryFilePath = BinaryPath(“devtools/dummy_ircadii/cat/cat”);
}
Утилиты для тестирования
Все функции и утилиты, которые не зависят от тестового фреймворка распологаются в директории common
Получение сетевых портов в тестах: Для получения сетевого порта в тестах необходимо использовать функцию NTesting::GetFreePort() из network.h, которая вернет объект - владелец для порта. Порт будет считаться занятым до тех пор, пока владелец жив. Во избежание гонок с выделением портов необходимо держать объект-владелец в течении всей жизни теста, или по крайней мере пока в тесте не запустится сервис, который вызовет bind на этом порту.
Пример использования:
#include <library/cpp/testing/common/network.h>
TEST(HttpServerTest, Ping) {
auto port = NTesting::GetFreePort();
auto httpServer = StartHttpServer(“localhost:” + ToString(port));
auto client = CreateHttpClient(“localhost:” + ToString(port));
EXPECT_EQ(200, client.Get(”/ping").GetStatus());
}
Функции для получения путей для корня ircadii и до корня билд директории в тестах. Все функции расположены в файле env.h с описанием.
Хуки для тестов
Хуки позволяют выполнять различные действия при старте или остановке тестовой программы. Подробнее про использование можно прочитать в README.md
Тесты с канонизацией вывода
Тесты с канонизацией вывода используются для регрессионного тестирования. При первом запуске теста вывод тестируемой программы сохраняется, при последующих запусках система проверяет, что вывод не изменился.
К сожалению, в C++ такие тесты в данный момент не поддерживаются.
За состоянием поддержки этой возможности можно следить в задаче DEVTOOLS-1467.
Параметры теста
Поведение тестов можно настраивать, передавая в них параметры.
При запуске тестов, используйте ключ --test-param чтобы передать в тест пару ключ-значение. Например: ya make -t --test-param db_endpoint=localhost:1234.
Для доступа к параметру из теста используйте функцию GetTestParam:
TEST(Database, Connect) {
auto endpoint = GetTestParam(“db_endpoint”, “localhost:8080”);
// …
}
Метрики теста
Наш CI поддерживает возможность выгрузки из теста пользовательских метрик. У каждой метрики есть название и значение — число с плавающей точкой. CI покажет график значений метрик на странице теста.
Для добавления метрик используйте функцию testing::Test::RecordProperty если работаете с gtest, или макрос UNIT_ADD_METRIC если работаете с unittest. Например, создадим метрики num_iterations и score:
TEST(Solver, TrivialCase) {
// …
RecordProperty(“num_iterations”, 10);
RecordProperty(“score”, “0.93”);
}
Важно
RecordProperty принимает на вход целые числа и строки. Наш CI не умеет работать со строковыми значениями метрик, поэтому каждую строку он будет воспринимать как число. В случае, если строку не удастся преобразовать в число, тест упадет.
Бенчмарки
Для написания бенчмарков мы используем библиотеку google benchmark и цель G_BENCHMARK в ya.make файле — пример.
G_BENCHMARK поддержан на уровне ya make -t / ya test
Все подключенные к автосборке G_BENCHMARK запускаются в CI по релевантным коммитам и накапливают историю метрик, которая может быть полезна для поиска регрессий.
Для G_BENCHMARK доступно:
Листинг бенчмарков: ya test -rL - выведет список доступных бенчмарков
Вывод метрик на консоль: ya test -r -P --show-metrics
Фильтрация: ya test -rF <fnmatch expression> - запустит все бенчмарки, удовлетворяющие <fnmatch expression>
Сбор корок в случае таймаута или падения бенчмарка по сигналу
Graceful обработка таймаута - при таймаутах мы сохраняем весь текущий прогресс и строим итоговый отчет о тестировании, основываясь на этой информации.
Сбор метрик для успешно завершившихся бенчмарков. При запуске в автосборке, эти метрики можно будет увидеть на странице теста в CI.
Для G_BENCHMARK недоступно:

FORK(SUB)TESTS: предполагается, что G_BENCHMARK это микробенчмарки и в параллельном запуске нет необходимости.
Дополнительные опции для benchmark
C помощью макроса BENCHMARK_OPTS() можно передать дополнительные параметры в запуск benchmark. Например
BENCHMARK_OPTS(
–benchmark_min_time=2
–benchmark_min_iters=1
)
Тесты с Sanitizer
ya make -t --sanitize X позволяет собирать инструментированные программы с санитайзерами. Сейчас поддерживаются: address, memory, thread, undefined, leak. Можно указывать только один санитайзер за раз.
Параметризация опций санитайзеров
Локальный запуск ya make -t --sanitize X учитывает стандартные опции для санитайзеров переданные через переменные окружения. По умолчанию тестовая машинерия добавляет всем санитайзерам опцию exitcode=100 для специальной обработки падений тестов в этой конфигурации. В UBSAN_OPTIONS дополнительно выставляются опции print_stacktrace=1,halt_on_error=1. Вы можете зафиксировать опции санитайзеров для конкретных тестов через макрос ENV() в ya.make, например: ENV(ASAN_OPTIONS=detect_stack_use_after_return=1)
Cборка с санитайзером в Sandbox
Для сборки следует использовать задачу YA_MAKE/YA_MAKE2, в которой можно выбрать требуемый санитайзер в поле Build with specified sanitizer
Запуск тестов c санитайзером в Автосборке
В автосборке подключены 2 типа cанитайзеров: memory и address, так как они достаточно легковесны и стабильны. Для подключения проекта ко всем типам cанитайзеров следует добавить свой проект в autocheck/linux/sanitizer_common_targets.inc Если требуется только memory санитайзер, то в autocheck/linux/sanitizer_memory_targets.inc Если требуется только address санитайзер, то в autocheck/linux/sanitizer_address_targets.inc
Отключение тестов от сборки с санитайзерами
Вы можете сделать проект не достижимым по рекурсам для санитайзеров, подключив проекты более гранулярно. См. предыдущий абзац.
Вы можете сделать проект не достижимым по рекурсам для санитайзеров, например:
IF (NOT SANITIZER_TYPE)
RECURSE_FOR_TESTS(
test
)
ENDIF()
Отключить конкретный тест с помощью тега ya:not_autocheck, например:
IF (SANITIZER_TYPE)
TAG(ya:not_autocheck)
ENDIF()
Отключить инструментирование конкретной библиотеки c помощью макроса NO_SANITIZE()
С помощью макроса SUPPRESSIONS() можно указать файл содержащий правила для подавления ошибок в стандартной нотации с поддержкой комментариев начинающихся с #. Механизм поддерживается для address, leak и thread санитайзеров. Пример для protobuf: ya.make tsan.supp
Важно
Добавлять исключения следует только если вы переносите известные исключения из контриба или отчётливо понимаете, что сообщение от санитайзеров ложноположительное (скорей всего нет и вам следует внимательней разобраться в проблеме). Каждое обновление кода или компилятора должно приводить к пересмотру suppression списка.
Отладка тестов санитайзера
Для отладки падающих тестов нужно собрать библиотеку с включённым санитайзером. Для этого в ya make нужно передать дополнительный флаг --sanitize=memory (на примере санитайзера памяти, см. выше). Возможно, для воспроизведения потребуется также повторить настройки оптимизации --build=release.
Для перехвата исключения под отладчиком нужно добавить точку останова: br __msan_warning_with_origin_noreturn (если не сработает, см. другие варианты тут и тут).
Под отладчиком же можно посмотреть, что санитайзер думает про каждый бит используемой памяти: call (void)__msan_print_shadow(&myVar, sizeof(myVar)) (в vscode перед командой нужно добавить -exec, вводить в окне Debug Console, а результаты смотреть в Terminal). Согласно документации единичные биты обозначают неинициализированную память.
Fuzzing
Fuzzing это техника тестирования, заключающаяся в передаче приложению на вход неправильных, неожиданных или случайных данных, совокупность которых называют корпусом. Предметом интереса являются падения и зависания, нарушения внутренней логики и проверок в коде приложения, утечки памяти, вызванные такими данными на входе.

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

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

Сборка с libFuzzer
Для сборки FUZZ модуля с libFuzzer достаточно дополнительно указать санитайзер и подсчёт sanitize покрытия - для того чтобы fuzzer понимал, смогли ли текущие входные данные привести к попаданию в новую трассу выполнения:

ya make -A --sanitize=address --sanitize-coverage=trace-div,trace-gep
На выходе получается исполняемый файл, который и есть драйвер. Тип санитайзера и тип покрытия можно менять, подробнее можно почитать в документации llvm.

Сборка c AFL
Для сборки FUZZ модуля с AFL нужно запускать сборку с sanitize-coverage=trace-pc

ya make --afl --sanitize=undefined --sanitize-coverage=trace-pc%%
В отличие от libFuzzer, для AFL нужен внешний драйвер - afl-fuzz:

ya tool afl-fuzz -i INPUT -o OUTPUT – /path/to/binary%%
Concept
Мы разделяем fuzzing и прогон корпуса - fuzzy test.

Fuzzing - процесс поиска примеров для расширения корпуса. Корпус состоит из двух частей - пользовательской и автоматически сгенерированной. Пользовательские примеры должны лежать в директории corpus, рядом с ya.make, в виде отдельных файлов (имена не имеют значения). Эти примеры должны быть малочисленны и составлены вручную, они помогут fuzzer в поиске новых интересных случаев.

Автоматически сгенерированные данные сохраняются в виде Sandbox ресурсов и прикрепляются к проектам через специальный файл corpus.json в директории проекта в arcadia/fuzzing. Это поведение можно отключить с помощью опции --fuzz-local-store, намайненные данные будут находится в <project_path>/test-results/fuzz/<binname>/mined_corpus.tar.

Пример локального запуска фаззинга (расширения корпуса):

ya make -r --sanitize=address --sanitize-coverage=trace-div,trace-gep -A --fuzzing
Fuzzy тест - это только прогон имеющегося корпуса (пользовательского и автоматического). Fuzzy тесты запускаются автоматически в Автосборке CI на все релевантные изменения в репозитории, которые влияют на сборку FUZZ модуля. Это позволяет проверять вносимые изменения на предмет ошибок/утечек на основе корпуса.

Пример локального запуска fuzzy теста:

ya make -r --sanitize=address --sanitize-coverage=trace-div,trace-gep -A
Регулярный fuzzing
Автосборка запускает все fuzzy тесты достижимые от корня Аркадии аналогично обычным тестам.
Для автоматического фаззинга (расширения корпуса) для FUZZ модуля нужно завести ci-шедулер, который будет запускать сендбокс задачу FUZZ_YA_MAKE_TASK_2. Минимальный пример можно посмотреть в этом a.yaml.
Задача запустит фаззинг на 2 часа --fuzz-opts=“-max_total_time=7200” и закоммитит найденные интересные случаи в корпус соответствующего проекта. Актуальные дефолтные параметры задачи можно посмотреть в run_fuzzing.yaml.
Таким образом, если еженощный процесс расширения корпуса найдёт данные, которые будут приводить к падению/утечке, этот проект будет падать в автосборке CI при запуске соответствующего fuzzy теста.
Когда количество автоматически намайненных данных в corpus.json достигает 6, тестовая машинерия запускает процедуру минимизации корпуса, объединяя все части в один, убирая избыточные и более нерелевантные кейсы. Если у теста выставлен макрос TAG(ya:always_minimize), то минимизация инициируется каждый раз после фаззинга.
Фазинг тесты, которые раньше запускались в testenv, были смигрированы на сi-шедулеры. Посмотреть полный список смигрированных фазингов можно в этом a.yaml. Эти тесты запускаются ночью в сендбокс квоте AUTOCHECK. В будущем эти шедулеры планируется раздать овнерам тестов.
Длительность регулярного фаззинга
По-умолчанию фаззинг запускается на 2 часа. Время выполнения фаззинга можно увеличить поправив в соответсвующем a.yaml’е параметры задачи:
max_total_time=X, где вместо X указываются секунды определяющие время фаззинга (являясь эквивалентом --fuzz-opts=“-max_total_time=Х”)
ya_timeout - таймаут на выполнение команды ya make
kill-timeout - таймаут на выполнение самой задачи FUZZ_YA_MAKE_TASK_2
Максимально допустимое значение - 20h, если указывается больше, оно уменьшается до указанного лимита.
Отладка
Прогон конкретного кейса
Для прогона одного конкретного кейса следует воспользоваться опцией --fuzz-case:
ya make -r --sanitize=address --sanitize-coverage=trace-div,trace-gep -A --fuzz-case=abs_path
Кейc можно скачать с CI - baseunit в плашке файлов после раскрытия snippet или отдельно сохранить после локального прогона fuzzy теста.
Ручная минимизация корпуса
Если автоматическая минимизация не успевает выполниться (например из-за того, что роботы заливают слишком много данных в корпус или скорость прогона кейсов крайне мала), минимизацию можно произвести самостоятельно на разработческой машине:
ya make -r --sanitize=address --sanitize-coverage=trace-div,trace-gep -A --fuzzing --fuzz-minimization-only
После чего полученный корпус необходимо закоммитить.
Если корпус расширяется слишком быстро и минимизация постоянно не укладывается в таймаут, следует добавить тег в ya.make файл ya:always_minimize. В этом случае корпус будет минимизироваться после каждого запуска фаззинга. Этого же эффекта можно достичь с помощью ключа --fuzz-minimize.
Метрики
ya make собирает следующие метрики во время fuzzing, доступные при локальном прогоне при указании -P --show-metrics и в CI у fuzz:test теста:
corpus_size - зарегистрированный fuzzer’ом размер корпуса
fuzz_iterations_per_second - количество итераций в секунду. Если тест таймаутится, до повышения его размера, следует посмотреть на эту метрику, возможно в код была добавлена регрессия, которая замедлила целевую функцию
number_of_executed_units - количество проверенных кейсов
mined_corpus_size - количество новых кейсов, которые нашёл fuzzer (расширение корпуса)
peak_rss_mb - пиковое потребление rss во время fuzzing/прогона fuzzy теста
slowest_unit_time_sec - время самого медленного из запущенных кейсов
Опции по умолчанию
Для fuzzing и прогона fuzzy тестов выставляются дополнительные параметры:
Опции для libFuzzer:
-max_total_time=600
-rss_limit_mb=4096
-timeout=600
Переменные окружения *SAN_OPTIONS:
coverage=1
allocator_may_return_null=1
FUZZ_OPTS
В запуск ya make можно передать опции для fuzzing/fuzzy теста с помощью опции --fuzz-opts. Например так можно переопределить время fuzzing’a:
ya make -r --sanitize=address --sanitize-coverage=trace-div,trace-gep --fuzzing -A --fuzz-opts=“-max_total_time=300”
Некоторые опции хочется фиксировать, чтобы fuzzing в автосборке/еженощно запускался с ними. Для этого следует использовать макрос FUZZ_OPTS, в котором следует перечислить требуемые опции через пробел. Например:
FUZZ_OPTS(
-max_len=1024
-only_ascii=1
-rss_limit_mb=2048
)
С помощью FUZZ_OPTS не следует переопределять -max_total_time, так как в этом случае фаззинг может начать падать - это значение не задаёт лимит на время работы Sandbox таски и она форсированно завершится через 3 часа.
FUZZ_DICTS
Для libFuzzer можно указать пути относительно корня Аркадии до файлов-словарей, каждый из которых содержит на каждой строке - один case, от которого может отталкиваться fuzzer движок для мутаций и поиска новых интересных входных данных. Пример такого словаря
Пример использования макроса:

FUZZ_DICTS(
devtools/test_tool/run_fuzz/tests/data/sample_with_dict/dict.txt
devtools/test_tool/run_fuzz/tests/data/sample_with_several_dicts/dict.txt
)
Fuzz proof
Для подтверждения высокого уровня покрытия кода имеющимся корпусом, можно воспользоваться режимом --fuzz-proof X, где X время в секундах, которое требуется дополнительно фаззить с момента обнаружения последнего найденного кейса в текущем запуске. Если в течении X секунд с момента обнаружения последнего кейса (или с начала фаззинга, если не было найдено ни одного нового кейса в текущем запуске) будет найден хотя бы один новый - это приведёт к завершению фаззинга с ошибкой. Все найденные кейсы будут сохранены в корпусе.
Режим следует комбинировать с ограничением по времени или по суммарному количеству итераций.
ya make -r --sanitize=address --sanitize-coverage=trace-div,trace-gep --fuzzing -A --fuzz-opts=“-max_total_time=3600” --fuzz-proof=1800
В этом случае будет запущена стандартная процедура расширения корпуса с ограничением времени фаззинга в 1 час (3600с). После её успешного окончания, ищется самый свежий кейс в полученном корпусе.
Если машинерия фаззинга обнаружит последний найденный кейс более 30 минут (1800с) назад, то считается что proof состоялся и фаззинг успешно завершается.
Если последний кейс был обнаружен 10 минут назад (для примера), то фаззинг будет перезапущен на дополнительные 20 минут в режиме fuzz proof с использованием всего текущего корпуса (включая новые найденные данные). Если тестовая машинерия обнаружит новый кейс во время работы в этом режиме, процесс фаззинга будет прерван, а все найденные кейсы сохранены - proof не состоялся, об этом сообщит ошибка в тесте.
ya make -r --sanitize=address --sanitize-coverage=trace-div,trace-gep --fuzzing -A --fuzz-runs=1000000 --fuzz-proof=3600
Аналогично работает fuzz proof режим при запуске фаззинга с ограничением суммарного количества прогонов целевой функции.

Опции фаззинга ya make -t
Опция Описание
–fuzzing Запускает фаззинг (режим расширения корпуса), см. concept
–fuzz-opts OPTS Задаёт опции для libFuzzer, см fuzz-opts
–fuzz-case PATH Позволяет указать путь до конкретного кейса, который следует проверить, см fuzz-case
–fuzz-local-store Отключает автоматическое сохранение и загрузку расширения корпуса (новые намайненные данные) в Sandbox
–fuzz-runs X По умолчанию fuzzing запускается в режиме ограничения по времени, см max_total_time, --fuzz-runs позволяет ограничивать количество запусков целевой функции.
–fuzz-minimize Всегда минимизировать корпус после фаззинга, см minimization
–fuzz-minimization-only Запустить процедуру минимизации корпуса без фаззинга, см minimization
–fuzz-proof X Позволяет задать Х секунд, которое требуется дополнительно фаззить после последнего найденного кейса для корректного завершения фаззинга, см fuzz-proof
Ручное расширение корпуса
Если вы каким-то образом уже намайнили корпус и хотите его подключить к автоматике, вам следует:
Залить его в Sandbox с помощью ya upload --tar path-to-dir-with-corpus
Добавить в corpus.json проекта в arcadia/fuzzing. Если его нет - создать новый вида:

{
“corpus_parts”: [
<SANDBOX_RESOURCE_ID>
]
}
Проверить, что ya make находит корпус и корректно его прогоняет:

ya make --sanitize=address --sanitize-coverage=trace-div,trace-gep -A -P --show-metrics
Метрика corpus_size у теста fuzz::test должна отображать ожидаемое количество примеров из корпуса.
Зафиксировать изменение в corpus.json файле в репозитории.
Пользовательская автоматизация в Sandbox для расширения корпуса
Иногда может быть полезна возможность расширять корпус самостоятельно, добавляя интересные случаи в корпус до того как до него дойдёт фаззинг.
Тесты на Java
Для Java поддерживаются JUnit версий 4.х и 5.х.

Тесты на JUnit 4
Запуск тестов на JUnit 4 описывается макросом JTEST():

OWNER(g:my-group)

JTEST() # Используем JUnit 4

JAVA_SRCS(SRCDIR java **/*) # Где искать исходные коды тестов
JAVA_SRCS(SRCDIR resources **/*)

PEERDIR(
    # Сюда же необходимо добавить зависимости от исходных кодов вашего проекта
    contrib/java/junit/junit/4.12 # Сам фреймворк Junit 4
    contrib/java/org/hamcrest/hamcrest-all # Можно подключить набор Hamcrest матчеров
)

JVM_ARGS( # Необязательный набор флагов, передаваемых JVM
    -Djava.net.preferIPv6Addresses=true
    -Djava.security.egd=file:///dev/urandom
    -Xms128m
    -Xmx256m
)

SYSTEM_PROPERTIES( # Необязательный набор значений, которые нужно положить в Java system properties. Эти значения переопределяют те, что были переданы в JVM_ARGS при помощи -D.
    key1 val1
    key2 val2
    FILE app.properties # Положить содержимое *.properties или *.xml файла
    FILE config.xml
)


END()
Примечание

Примеры продвинутой работы с Java system properties можно посмотреть здесь. Поддерживаются различные {name} подстановки и загрузка данных из XML файлов.

Код тестов совершенно стандартный, например:
package ru.yandex.devtools.test;
import org.junit.Test;
import static org.junit.Assert.assertEquals;

public class MathsTest {

    @Test
    public void testMultiply() {
        assertEquals(2 * 2, 4);
    }

}
Тесты на JUnit 5
Запуск тестов на JUnit 5 отличается только набором зависимостей и используемым макросом JUNIT5:

OWNER(g:my-group)

JUNIT5() # Используем JUnit 5
JAVA_SRCS(SRCDIR java **/*)
JAVA_SRCS(SRCDIR resources **/*)
SIZE(MEDIUM)
INCLUDE({ARCADIA_ROOT}/contrib/java/org/junit/junit-bom/5.7.1/ya.dependency_management.inc)
PEERDIR(
    # Сюда же необходимо добавить зависимости от исходных кодов вашего проекта
    contrib/java/org/junit/jupiter/junit-jupiter # Сам фреймворк Junit 5
    contrib/java/org/hamcrest/hamcrest-all # Набор Hamcrest матчеров
)

END()
Пример теста:
package ru.yandex.devtools.test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;

class MathsTest {

    @Test
    void multiplication() {
        assertEquals(2 * 2, 4);
    }

}
Доступ к зависимостям
Если вы используете в своем ya.make зависимости, то обращаться к таким данным в коде теста нужно, используя библиотеку devtools/test/Paths:
package ru.yandex.devtools.test;

import org.junit.jupiter.api.Test;
import ru.yandex.devtools.test.Paths;

class ReadFileTest {

    @Test
    void read() {
        // Путь до файла/директории из репозитория, описанных с помощью макроса DATA("arcadia/devtools/dummy_arcadia/cat/main.cpp")
        String testFilePath = Paths.getSourcePath(
            "devtools/dummy_arcadia/cat/main.cpp"
        );

        // Путь до Sandbox-ресурса, описанного макросом DATA(sbr://53558626) # test.txt
        String sandboxResourcePath = Paths.getSandboxResourcesRoot() + "/test.txt";

        // Путь до файла из DEPENDS("devtools/dummy_arcadia/cat")
        // Обратите внимание: путь в DEPENDS указывает до сборочной цели, а BinaryPath требует указания пути до файла
        String binaryFilePath = Paths.getBuildPath(
            "devtools/dummy_arcadia/cat/cat"
        );

        // ...
    }

}
Запуск JAVA_PROGRAM из теста
Если из теста есть необходимость запустить java-код, то можно воспользоваться следующим способом:

Добавить в ya.make теста конструкцию вида:
PEERDIR(
    build/platform/java/jdk/jdk21
    {JDK_RESOURCE_PEERDIR}
)
Непосредственно в коде теста можно получить путь до JDK примерно так:
import yatest.common.runtime as runtime

class DummyTest:
    def __init__(self, ...):
        self.jdkPath = runtime.global_resources()['JDK21_RESOURCE_GLOBAL']
Конечно, вместо JDK21 здесь и в предыдущем пункте можно подставить JDK нужной версии.
Полученный путь перед запуском jar-ника нужно выставить в переменную окружения JAVA_HOME:
os.environ["JAVA_HOME"] = self.jdkPath
Директории доступные тесту
Помимо доступа к зависимостям бибилотека devtools/test/Paths позволяет узнать правильные пути до:

getWorkPath() - Возвращает путь до рабочей директории теста, где можно сохранять временные данные.
getTestOutputsRoot() - Возвращает путь до директории testing_out_stuff. Данные сохранённые внутри неё будут доступны после тестирования.
getRamDrivePath() - путь к RAM drive заказаному тестом через REQUIREMENTS
getYtHddPath() - путь к HDD диску доступному для записи временных данных для тестов запускаемых в YT
Фильтрация по тегам
Тесты JUnit5 можно фильтровать по тегам. Например:

package ru.yandex.devtools.test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;

class MathsTest {

    @Test
    @Tag("mult")
    void multiplication() {
        assertEquals(2 * 2, 4);
    }

    @Test
    @Tag("sum")
    void sum() {
        assertEquals(2 + 2, 4);
    }

}
Запустить только тест multiplcation возможно с помощью

ya make -t --junit-args '--junit-tags mult'
Доступ к параметрам
Для того, чтобы получить в коде значения параметров:
package ru.yandex.devtools.test;

import org.junit.jupiter.api.Test;
import ru.yandex.devtools.test.Params;

class ReadParametersTest {

    @Test
    void read() {
        // Значение параметра my-param
        String myParamValue = Params.params.get("my-param");

        // ...
    }

}
Проверка classpath
Для тестов на Java возможно включить автоматическую проверку на наличие нескольких одинаковых классов в Java Classpath. В проверке участвует не только имя класса, но и хэш-сумма файла с его исходным кодом, так как идентичные классы из разных библиотек проблем вызывать не должны. Для включения этого типа тестов в ya.make файл соответствующего проекта нужно добавить макрос CHECK_JAVA_DEPS(yes|no|strict) (docs):

OWNER(g:my-group)
JTEST()
JAVA_SRCS(SRCDIR java **/*)
JAVA_SRCS(SRCDIR resources **/*)
CHECK_JAVA_DEPS(yes) # Включаем проверку classpath
END()

Статический анализ
На все исходные тексты на Java, которые подключены в секции JAVA_SRCS файла ya.make, включён статический анализ. Для проверки используется утилита checkstyle. Поддерживается два уровня проверок: обычный и расширенный (extended). В расширенном режиме выполняется большее количество проверок. Есть возможность полностью отключить статический анализ.

OWNER(g:my-group)
JTEST()
JAVA_SRCS(SRCDIR java **/*)
JAVA_SRCS(SRCDIR resources **/*)

# Используйте один из следующих макросов:
LINT() # Включить статический анализатор
LINT(extended) # Включить статический анализатор в расширенном режиме (больше проверок)
NO_LINT() # Отключить статический анализатор

END()
Примечание
Конфигурационные файлы для статического анализа расположены здесь.
To be documented
JTEST/JUNIT5

Тесты
Unit-тесты в Аркадии оформляются в виде отдельных целей со своим ya.make. Для их запуска используется команда ya make -t. Подробности есть в документации ya; см. также: RECURSE_FOR_TESTS.

Для написания тестов у нас имеется два фреймворка: unittest (наша собственная разработка) и gtest (популярное решение от Google). Также есть библиотека library/cpp/testing/common, в которой находятся полезные утилиты, не зависящие от фреймворка.

Поддержка gtest в Аркадии появилась недавно, поэтому фреймворк не очень распространен. Тем не менее, у него есть ряд преимуществ по сравнению с unittest:

очень подробно выводится контекст, когда ломается тест;
два семейства макросов для сравнения: ASSERT останавливает тест, EXPECT отмечает тест как проваленный, но не останавливает его, давая возможность выполнить остальные проверки;
возможность расширять фреймворк с помощью механизма матчеров;
можно использовать gmock (справедливости ради заметим, что gmock можно использовать и в unittest; однако в gtest он проинтегрирован лучше, а проекты уже давно объединены);
можно сравнивать некоторые типы — и даже получать относительно понятное сообщение об ошибке — даже если не реализован operator<<;
интеграция почти с любой IDE из коробки;
фреймворк известен во внешнем мире, новичкам не нужно объяснять, как писать тесты;
есть поддержка fixtures (в unittest тоже есть, но имеет существенные недостатки реализации);
есть поддержка параметрических тестов (один и тот же тест можно запускать с разными значениями входного параметра);
можно использовать в open-source проектах.
К недостаткам gtest можно отнести:

отсутствие поддержки аркадийных стримов. Впрочем, для популярных типов из util мы сделали собственные реализации PrintTo;
отсутствие макроса, проверяющего, что код бросает ошибку с данным сообщением. Мы сделали такой макрос сами, а также добавили несколько полезных матчеров;
Четких рекомендаций по выбору фреймворка для тестирования нет — руководствуйтесь здравым смыслом, обсудите с командой, взвесьте все «за» и «против». Учитывайте, что при смене типа тестов с unittest на gtest потеряется история запуска тестов в CI. Впрочем, если ваши тесты не мигают (а мы очень на это надеемся), история вам и не нужна.

Gtest
Подробная документация по gtest доступна в официальном репозитории gtest и gmock. Этот раздел дает лишь базовое представление о фреймворке, а также описывает интеграцию gtest в Аркадию.

Для написания тестов с этим фреймворком используйте цель типа GTEST. Минимальный ya.make выглядит так:

GTEST()

OWNER(...)

SRCS(test.cpp ...)

END()
Поддерживаются стандартные для Аркадии настройки тестов: TIMEOUT, FORK_TESTS и прочие. Подробнее про это написано в документации ya.

Внутри cpp файлов с тестами импортируйте library/cpp/testing/gtest/gtest.h. Этот заголовочный файл подключит gtest и наши расширения для него. Для объявления тестов используйте макрос TEST. Он принимает два параметра: название группы тестов (test suite) и название конкретного теста.

Примечание

В аркадии своя реализация функции main, реализовывать ее не нужно. Для кастомизации своих тестов можно воспользоваться хуками из library/cpp/testing/hook.

Пример минимального cpp файла с тестами:

#include <library/cpp/testing/gtest/gtest.h>

TEST(BasicMath, Addition) {
    EXPECT_EQ(2 + 2, 4);
}

TEST(BasicMath, Multiplication) {
    EXPECT_EQ(2 * 2, 4);
}
Для выполнения проверок в теле теста используйте специальные макросы. Они, в отличие от стандартных Y_ASSERT и Y_ABORT_UNLESS, умеют печатать развернутые сообщения об ошибках. Например, ASSERT_EQ(a, b) проверит, что два значения равны; в случае, если это не так, макрос отметит тест как проваленный и остановит его.

Каждый макрос для проверки имеет два варианта: ASSERT останавливает тест, EXPECT — нет. По-умолчанию используйте EXPECT, так вы получите больше информации после запуска тестов. Используйте ASSERT только если проверяете условие, от которого зависит корректность дальнейшего кода теста:

TEST(EtheriaHeart, Activate) {
    auto* result = NEtheria::Activate();

    // Если указатель нулевой, последующие проверки приведут к UB.
    ASSERT_NE(result, nullptr);

    EXPECT_EQ(result->Code, 0);
    EXPECT_EQ(result->ConnectedCrystals, 5);
    EXPECT_GE(result->MaxPower, 1.5e+44);
}
Полный список доступных макросов есть в официальной документации и документации по продвинутым возможностям gtest.

Также gtest позволяет добавить к каждой проверке пояснение. Оно будет напечатано если проверка провалится. Для форматирования пояснений используется std::ostream:

TEST(LotrPlot, Consistency) {
    EXPECT_GE(RingIsDestroyed() - FrodoLeftHobbiton(), TDuration::Days(183))
        << "no, eagles were not an option because " << Reasons();
}
Для более сложных проверок предусмотрен механизм матчеров. Например, проверим, что контейнер содержит элемент, удовлетворяющий определенному условию:

TEST(GtestMatchers, SetElements) {
    THashSet<TString> elements{"water", "air", "earth", "fire"};
    EXPECT_THAT(elements, testing::Contains("air"));
    EXPECT_THAT(elements, testing::Contains(testing::StrCaseEq("Fire")));
}
Наши расширения добавляют макрос для проверки сообщений в исключениях:

TEST(YException, Message) {
    EXPECT_THROW_MESSAGE_HAS_SUBSTR(
        ythrow yexception() << "black garnet is not active",
        yexception,
        "not active");
Для тестирования кода, прекращающего выполнение приложения (например, выполняющего Y_ASSERT или Y_ABORT_UNLESS), используйте макросы EXPECT_DEATH, EXPECT_DEBUG_DEATH, ASSERT_DEATH, ASSERT_DEBUG_DEATH:

TEST(Vector, AccessBoundsCheck) {
    TVector<int> empty{};
    EXPECT_DEBUG_DEATH(empty[0], "out of bounds");
}
Матчер NGTest::GoldenFileEq(filename) описан в разделе канонизация.

Unittest
Для написания тестов с этим фреймворком используйте цель типа UNITTEST. Минимальный ya.make выглядит так:

UNITTEST()
OWNER(...)
SRCS(test.cpp ...)
END()
Поддерживаются стандартные для Аркадии настройки тестов: TIMEOUT, FORK_TESTS и прочие. Подробнее про это написано в документации ya.

Внутри cpp файлов с тестами подключите library/cpp/testing/unittest/registar.h.
Важно
Не подключайте файл library/cpp/testing/unittest/gtest.h — это deprecated интерфейс unittest, который пытается выглядеть как gtest.
Для объявления группы тестов используйте макрос Y_UNIT_TEST_SUITE. Для объявления тестов внутри группы используйте макрос Y_UNIT_TEST.

Пример минимального cpp файла с тестами:
#include <library/cpp/testing/unittest/registar.h>
Y_UNIT_TEST_SUITE(BasicMath) {
    Y_UNIT_TEST(Addition) {
        UNIT_ASSERT_VALUES_EQUAL(2 + 2, 4);
    }

    Y_UNIT_TEST(Multiplication) {
        UNIT_ASSERT_VALUES_EQUAL(2 * 2, 4);
    }
}
Для выполнения проверок в теле теста используйте специальные макросы:
Макрос	Описание
UNIT_FAIL(M)	Отметить тест как проваленный и остановить его.
UNIT_FAIL_NONFATAL(M)	Отметить тест как проваленный но не останавливать его.
UNIT_ASSERT(A)	Проверить, что условие A выполняется.
UNIT_ASSERT_EQUAL(A, B)	Проверить, что A равно B.
UNIT_ASSERT_UNEQUAL(A, B)	Проверить, что A не равно B.
UNIT_ASSERT_LT(A, B)	Проверить, что A меньше B.
UNIT_ASSERT_LE(A, B)	Проверить, что A меньше или равно B.
UNIT_ASSERT_GT(A, B)	Проверить, что A больше B.
UNIT_ASSERT_GE(A, B)	Проверить, что A больше или равно B.
UNIT_ASSERT_VALUES_EQUAL(A, B)	Проверить, что A равно B. В отличие от UNIT_ASSERT_EQUAL, воспринимает char* как null-terminated строку, а также печатает значения переменных с помощью IOutputStream при провале проверки.
UNIT_ASSERT_VALUES_UNEQUAL(A, B)	Проверить, что A не равно B. В отличие от UNIT_ASSERT_UNEQUAL, воспринимает char* как null-terminated строку, а также печатает значения переменных с помощью IOutputStream при провале проверки.
UNIT_ASSERT_DOUBLES_EQUAL(E, A, D)	Проверить, что E и A равны с точностью D.
UNIT_ASSERT_STRINGS_EQUAL(A, B)	Проверить, что строки A и B равны. В отличие от UNIT_ASSERT_EQUAL, воспринимает char* как null-terminated строку.
UNIT_ASSERT_STRINGS_UNEQUAL(A, B)	Проверить, что строки A и B не равны. В отличие от UNIT_ASSERT_UNEQUAL, воспринимает char* как null-terminated строку.
UNIT_ASSERT_STRING_CONTAINS(A, B)	Проверить, что строка B является подстрокой в A.
UNIT_ASSERT_NO_DIFF(A, B)	Проверить, что строки A и B равны. Печатает цветной diff строк при провале проверки.
UNIT_ASSERT_EXCEPTION(A, E)	Проверить, что выражение A выбрасывает исключение типа E.
UNIT_ASSERT_NO_EXCEPTION(A)	Проверить, что выражение A не выбрасывает исключение.
UNIT_ASSERT_EXCEPTION_CONTAINS(A, E, M)	Проверить, что выражение A выбрасывает исключение типа E, сообщение которого содержит подстроку M.
У каждого макроса UNIT_ASSERT есть версия UNIT_ASSERT_C, позволяющая передать пояснение к проверке. Например:

UNIT_ASSERT_C(success, "call should be successful");
UNIT_ASSERT_GT_C(rps, 500, "should generate at least 500 rps");
Mock
Для реализации mock-объектов мы используем gmock. Если вы используете gtest, gmock подключен автоматически. Если вы используете unittest, для подключения gmock нужно добавить PEERDIR на library/cpp/testing/gmock_in_unittest и импортировать файл library/cpp/testing/gmock_in_unittest/gmock.h.
Доступ к зависимостям
Если вы используете в своем ya.make зависимости, то обращаться к таким данным в коде теста нужно, используя библиотеку library/cpp/testing:

#include <library/cpp/testing/common/env.h>

void ReadDependency() {
    // Путь до файла/директории из репозитория, описанных с помощью макроса DATA("arcadia/devtools/dummy_arcadia/cat/main.cpp")
    TString testFilePath = ArcadiaSourceRoot() + "/devtools/dummy_arcadia/cat/main.cpp";

    // Путь до Sandbox-ресурса, описанного макросом DATA(sbr://53558626) # test.txt
    TString sandboxResourcePath = GetWorkPath() + "/test.txt";

    // Путь до файла из DEPENDS("devtools/dummy_arcadia/cat")
    // Обратите внимание: путь в DEPENDS указывает до сборочной цели, а BinaryPath требует указания пути до файла
    TString binaryFilePath = BinaryPath("devtools/dummy_arcadia/cat/cat");
}
Утилиты для тестирования
Все функции и утилиты, которые не зависят от тестового фреймворка распологаются в директории common
Получение сетевых портов в тестах: Для получения сетевого порта в тестах необходимо использовать функцию NTesting::GetFreePort() из network.h, которая вернет объект - владелец для порта. Порт будет считаться занятым до тех пор, пока владелец жив. Во избежание гонок с выделением портов необходимо держать объект-владелец в течении всей жизни теста, или по крайней мере пока в тесте не запустится сервис, который вызовет bind на этом порту.
Пример использования:

#include <library/cpp/testing/common/network.h>

TEST(HttpServerTest, Ping) {
    auto port = NTesting::GetFreePort();
    auto httpServer = StartHttpServer("localhost:" + ToString(port));
    auto client = CreateHttpClient("localhost:" + ToString(port));
    EXPECT_EQ(200, client.Get("/ping").GetStatus());
}
Функции для получения путей для корня аркадии и до корня билд директории в тестах. Все функции расположены в файле env.h с описанием.
Хуки для тестов
Хуки позволяют выполнять различные действия при старте или остановке тестовой программы. Подробнее про использование можно прочитать в README.md
Тесты с канонизацией вывода
Тесты с канонизацией вывода используются для регрессионного тестирования. При первом запуске теста вывод тестируемой программы сохраняется, при последующих запусках система проверяет, что вывод не изменился.
К сожалению, в C++ такие тесты в данный момент не поддерживаются.
За состоянием поддержки этой возможности можно следить в задаче DEVTOOLS-1467.
Параметры теста
Поведение тестов можно настраивать, передавая в них параметры.
При запуске тестов, используйте ключ --test-param чтобы передать в тест пару ключ-значение. Например: ya make -t --test-param db_endpoint=localhost:1234.
Для доступа к параметру из теста используйте функцию GetTestParam:
TEST(Database, Connect) {
    auto endpoint = GetTestParam("db_endpoint", "localhost:8080");
    // ...
}
Метрики теста
Наш CI поддерживает возможность выгрузки из теста пользовательских метрик. У каждой метрики есть название и значение — число с плавающей точкой. CI покажет график значений метрик на странице теста.
Для добавления метрик используйте функцию testing::Test::RecordProperty если работаете с gtest, или макрос UNIT_ADD_METRIC если работаете с unittest. Например, создадим метрики num_iterations и score:

TEST(Solver, TrivialCase) {
    // ...
    RecordProperty("num_iterations", 10);
    RecordProperty("score", "0.93");
}
Важно

RecordProperty принимает на вход целые числа и строки. Наш CI не умеет работать со строковыми значениями метрик, поэтому каждую строку он будет воспринимать как число. В случае, если строку не удастся преобразовать в число, тест упадет.
Бенчмарки
Для написания бенчмарков мы используем библиотеку google benchmark и цель G_BENCHMARK в ya.make файле — пример.

G_BENCHMARK поддержан на уровне ya make -t / ya test

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

Для G_BENCHMARK доступно:

Листинг бенчмарков: ya test -rL - выведет список доступных бенчмарков
Вывод метрик на консоль: ya test -r -P --show-metrics
Фильтрация: ya test -rF <fnmatch expression> - запустит все бенчмарки, удовлетворяющие <fnmatch expression>
Сбор корок в случае таймаута или падения бенчмарка по сигналу
Graceful обработка таймаута - при таймаутах мы сохраняем весь текущий прогресс и строим итоговый отчет о тестировании, основываясь на этой информации.
Сбор метрик для успешно завершившихся бенчмарков. При запуске в автосборке, эти метрики можно будет увидеть на странице теста в CI.
Для G_BENCHMARK недоступно:

FORK_(SUB)TESTS: предполагается, что G_BENCHMARK это микробенчмарки и в параллельном запуске нет необходимости.
Дополнительные опции для benchmark
C помощью макроса BENCHMARK_OPTS() можно передать дополнительные параметры в запуск benchmark. Например

BENCHMARK_OPTS(
    --benchmark_min_time=2
    --benchmark_min_iters=1
)
"
Напиши “Готов писать документацию”, после изучения информации.
ASSISTANT
Готов писать документацию

turns-00020.parquet:55640

a753ea70c63e51e86578747d
turn 2/31gpt-4-0125-previewRussianRussia265 words
degenerate_repetitionAbsentFinal dense release
USER
подробно с объяснениями опиши опцию --system-property=PROPERTIES
Установить системное свойство (name=val)
ASSISTANT
Опция `--system-property=PROPERTIES` (или в сокращенной форме `-R=PROPERTIES`) используется в контексте запуска Java-приложений и тестов, чтобы установить одно или несколько системных свойств JVM (Java Virtual Machine) перед выполнением приложения или теста. Системные свойства в Java — это ключевые значения, которые можно использовать для конфигурации поведения JVM и приложения. Они могут влиять на работу стандартных классов Java и могут быть использованы для передачи конфигурационной информации в ваше приложение.

Формат опции:
```
--system-property=PROPERTIES
```
или
```
-R=PROPERTIES
```
где `PROPERTIES` — это пары ключ-значение в формате `name=value`. Если требуется передать несколько системных свойств, опция может быть указана несколько раз с разными парами ключ-значение.

Пример использования:
```
--system-property=my.prop1=val1 --system-property=my.prop2=val2
```
или с использованием сокращенной формы:
```
-R=my.prop1=val1 -R=my.prop2=val2
```
В этом примере перед запуском Java-приложения или теста устанавливаются два системных свойства: `my.prop1` со значением `val1` и `my.prop2` со значением `val2`.

Зачем это нужно:
- **Конфигурация приложения**: Системные свойства могут использоваться для конфигурирования различных аспектов работы приложения, например, для указания путей к файлам конфигурации, настройки логирования и т.д.
- **Тестирование**: В контексте тестирования, системные свойства могут использоваться для изменения поведения тестов, например, для включения или отключения определенных тестовых случаев на основе конфигурации или для указания различных параметров тестового окружения.
- **Настройка JVM**: Системные свойства также могут использоваться для настройки работы самой JVM, например, для установки максимального размера кучи или настройки сборщика мусора.

Важно понимать, что системные свойства, установленные таким образом, будут доступны во всем приложении через вызов `System.getProperty("name")`, где `"name"` — это ключ системного свойства. Это делает их удобным средством для передачи конфигурационной информации в приложение в момент его запуска.

turns-00020.parquet:55641

15feb76863582d0ab30129be
turn 3/31gpt-4-0125-previewRussianRussia269 words
degenerate_repetitionAbsentFinal dense release
USER
подробно с объяснениями опиши опцию --system-properties-file=PROPERTIES_FILES
Загрузить системные свойства из файла
ASSISTANT
Опция `--system-properties-file=PROPERTIES_FILES` представляет собой механизм, используемый при запуске Java-приложений или тестов, для загрузки и установки системных свойств JVM из внешнего файла. Эта возможность особенно полезна, когда необходимо установить большое количество системных свойств или когда значения этих свойств должны быть легко изменяемы без перекомпиляции кода или перезапуска среды разработки.

**Формат опции:**
```
--system-properties-file=PROPERTIES_FILES
```
где `PROPERTIES_FILES` указывает на путь к файлу, содержащему системные свойства.

**Формат файла свойств:**
Файл, из которого загружаются системные свойства, обычно имеет простой текстовый формат, где каждая строка содержит одно свойство в формате `ключ=значение`. Комментарии могут быть добавлены, начиная строку с символа `#`. Например:
```
# Это комментарий
property1=value1
property2=value2
```

**Пример использования:**
Предположим, у вас есть файл `app.properties` со следующим содержимым:
```
app.config.path=/path/to/config
app.logging.level=DEBUG
```
Чтобы загрузить эти свойства при запуске приложения, используйте опцию:
```
--system-properties-file=app.properties
```

**Зачем это нужно:**
- **Централизованная конфигурация**: Управление системными свойствами через внешний файл позволяет централизованно изменять конфигурацию приложения без необходимости изменения кода или команды запуска.
- **Упрощение команды запуска**: Вместо того, чтобы указывать множество системных свойств через командную строку с использованием `-Dkey=value`, можно указать один файл, что делает команду запуска более читаемой и удобной для восприятия.
- **Динамическая конфигурация**: Файл свойств может быть легко изменен администраторами системы или разработчиками для тонкой настройки поведения приложения в зависимости от среды выполнения, не требуя пересборки или перезапуска приложения.

**Важные моменты:**
- При использовании этой опции важно убедиться, что файл свойств доступен по указанному пути в момент запуска приложения.
- Системные свойства, загруженные из файла, будут доступны во всем приложении через `System.getProperty("key")`, что делает их удобным способом для передачи конфигурационной информации в приложение.

turns-00020.parquet:55642

d6355f667fe62554555ee8a8
turn 4/31gpt-4-0125-previewRussianRussia316 words
degenerate_repetitionAbsentFinal dense release
USER
подробно с объяснениями опиши опцию системы сборки --jvm-args=JVM_ARGS Добавить аргументы JVM для запуска JVM
ASSISTANT
Опция `--jvm-args=JVM_ARGS` используется в системах сборки и исполнения, связанных с Java-приложениями, для передачи дополнительных аргументов непосредственно виртуальной машине Java (JVM) при её запуске. Эти аргументы позволяют настроить работу JVM, влияя на производительность, поведение сборщика мусора, использование памяти и другие важные аспекты исполнения Java-приложений.

**Формат опции:**
```
--jvm-args=JVM_ARGS
```
где `JVM_ARGS` — это строка, содержащая один или несколько аргументов, которые должны быть переданы JVM. Аргументы разделяются пробелами и могут включать в себя как стандартные опции JVM, так и специфичные для конкретной реализации JVM.

**Пример использования:**
```
--jvm-args="-Xmx1024m -Xms512m -XX:+UseG1GC"
```
В данном примере:
- `-Xmx1024m` устанавливает максимальный размер кучи (heap) в 1024 мегабайта. Это предел, до которого может вырасти куча в процессе работы приложения.
- `-Xms512m` задает начальный размер кучи в 512 мегабайт. JVM будет стартовать с кучей данного размера.
- `-XX:+UseG1GC` включает использование сборщика мусора G1 (Garbage-First), который подходит для приложений с большим объемом памяти и требующих предсказуемого времени паузы на сборку мусора.

**Зачем это нужно:**
- **Настройка производительности**: Оптимизация использования памяти и выбор подходящего сборщика мусора могут существенно повлиять на производительность Java-приложения.
- **Отладка и профилирование**: Некоторые аргументы JVM активируют режимы отладки или профилирования, позволяя разработчикам анализировать выполнение приложения.
- **Настройка безопасности**: Через аргументы JVM можно настроить параметры безопасности, например, ограничить доступ к определенным функциям.
- **Управление ресурсами**: Указание ограничений на использование памяти предотвращает чрезмерное потребление ресурсов системы.

**Важные моменты:**
- Необходимо с осторожностью использовать аргументы JVM, так как неправильные настройки могут привести к снижению производительности или даже к ошибкам в работе приложения.
- Доступные аргументы и их эффекты могут различаться в зависимости от версии и реализации JVM. Следует ознакомиться с документацией конкретной версии JVM, которая используется в вашем проекте.
- В контексте систем сборки, таких как Maven или Gradle, аргументы JVM часто передаются через конфигурационные файлы или специальные параметры командной строки, предназначенные для управления средой исполнения тестов или запускаемых приложений.

turns-00020.parquet:55643

4eae893aa1f47e317ffda9e3
turn 5/31gpt-4-0125-previewRussianRussia317 words
degenerate_repetitionAbsentFinal dense release
USER
подробно с объяснениями опиши для системы сборки ya make опцию  --hermione-config=HERMIONE_CONFIG Путь к файлу конфигурации
ASSISTANT
Опция `--hermione-config=HERMIONE_CONFIG` в системе сборки `ya make` используется для указания пути к файлу конфигурации для запуска тестов, использующих Hermione — инструмент для автоматизированного тестирования веб-приложений с помощью Selenium. Эта опция позволяет тонко настроить процесс тестирования, указав различные параметры исполнения тестов, включая настройки браузеров, таймауты, пути к тестам и многое другое.

**Hermione** — это популярный инструмент для автоматизации тестирования веб-приложений, который позволяет писать тесты на высоком уровне абстракции. Тесты, написанные для Hermione, могут выполняться в различных браузерах, позволяя разработчикам убедиться, что их веб-приложение работает корректно в разных средах.

**Формат опции:**
```
--hermione-config=путь/к/файлу/конфигурации
```

**Пример использования:**
```
ya make --hermione-config=./configs/hermione.conf.js
```
В этом примере команда `ya make` запустит тесты Hermione, используя конфигурационный файл `hermione.conf.js`, расположенный в директории `configs`.

**Содержание файла конфигурации:**
Файл конфигурации Hermione обычно представляет собой JavaScript файл, который экспортирует объект с настройками. В нем можно указать:

- **browsers**: конфигурации для браузеров, в которых будут запускаться тесты;
- **baseUrl**: базовый URL тестируемого веб-приложения;
- **gridUrl**: URL Selenium Grid, через который будут запускаться браузеры;
- **timeout**: таймауты для тестов;
- **retry**: количество попыток перезапуска тестов в случае их неудачного выполнения;
- **plugins**: настройки плагинов, расширяющих функциональность Hermione.

**Зачем это нужно:**
- **Гибкость настроек**: Опция позволяет указать конкретный файл конфигурации для запуска тестов, что дает возможность иметь несколько разных конфигураций для разных сред или целей тестирования.
- **Удобство управления**: Централизованное управление настройками тестирования через один файл конфигурации упрощает поддержку и обновление параметров тестирования.
- **Множественные среды тестирования**: Можно легко переключаться между различными конфигурациями для запуска тестов в разных средах (разработка, тестирование, продакшн) без изменения кода тестов.

**Важные моменты:**
- При использовании этой опции убедитесь, что указанный путь к файлу конфигурации корректен и файл доступен в момент запуска `ya make`.
- Возможности и параметры конфигурации могут изменяться в зависимости от версии Hermione и подключенных плагинов, поэтому рекомендуется ознакомиться с документацией Hermione для понимания всех доступных настроек.

turns-00020.parquet:55644

d40b6787ec78eecdb8894bb6
turn 6/31gpt-4-0125-previewRussianRussia314 words
degenerate_repetitionAbsentFinal dense release
USER
подробно с объяснениями опиши опцию --hermione-browser=HERMIONE_BROWSERS
Запустить тесты только в указанном браузере
ASSISTANT
Опция `--hermione-browser=HERMIONE_BROWSERS` предназначена для использования в контексте запуска автоматизированных тестов веб-приложений с помощью инструмента Hermione. Эта опция позволяет ограничить выполнение тестов только выбранными браузерами, что полезно при необходимости запустить тесты в конкретной среде или при отладке проблем, связанных с определенным браузером.

**Hermione** — это инструмент для автоматизации тестирования веб-приложений, работающий поверх WebDriver и Selenium. Он позволяет писать тесты на JavaScript, которые могут выполняться в различных браузерах, имитируя действия пользователя.

### Формат опции:
```
--hermione-browser=HERMIONE_BROWSERS
```
где `HERMIONE_BROWSERS` — это строка, содержащая имя браузера или список имен браузеров, разделенных запятыми, в которых должны выполняться тесты.

### Пример использования:
```
ya make --hermione-browser=chrome
```
Эта команда запустит Hermione тесты только в браузере Chrome.

Если требуется запустить тесты в нескольких браузерах, можно указать их через запятую:
```
ya make --hermione-browser=chrome,firefox
```
Эта команда запустит тесты в браузерах Chrome и Firefox.

### Зачем это нужно:
1. **Фокусировка на конкретном браузере**: При разработке веб-приложений часто возникают ситуации, когда функционал нужно протестировать в конкретном браузере из-за его специфики или известных проблем совместимости.
2. **Экономия времени**: Запуск тестов только в одном или нескольких целевых браузерах может существенно сократить время, необходимое для прохождения тестового набора, особенно когда полный прогон всех тестов во всех поддерживаемых браузерах занимает много времени.
3. **Отладка**: При поиске и исправлении ошибок, специфичных для определенного браузера, возможность запустить тесты только в этом браузере упрощает и ускоряет процесс отладки.

### Важные моменты:
- Убедитесь, что указанные браузеры настроены в конфигурационном файле Hermione и доступны для запуска тестов. Конфигурация браузеров включает в себя не только их названия, но и параметры запуска, версии и пути к драйверам.
- Использование этой опции может потребовать дополнительных настроек инфраструктуры для запуска браузеров, особенно если тесты запускаются в изолированной среде или CI/CD пайплайне.
- Для эффективного использования этой опции важно иметь хорошо структурированные тесты, способные корректно выполняться в различных браузерах с учетом их особенностей.

turns-00020.parquet:55645

d81fec0ed905bb998150102b
turn 7/31gpt-4-0125-previewRussianRussia286 words
degenerate_repetitionAbsentFinal dense release
USER
подробно с объяснениями опиши опцию --hermione-grep=HERMIONE_GREP
Запустить тесты, соответствующие указанному шаблону
ASSISTANT
Опция `--hermione-grep=HERMIONE_GREP` используется в контексте запуска автоматизированных тестов с помощью инструмента Hermione, который предназначен для тестирования веб-приложений. Эта опция позволяет запускать только те тесты, названия которых соответствуют указанному шаблону, используя механизм фильтрации посредством регулярных выражений или подстрок.

**Hermione** — это инструмент для автоматизации тестирования веб-приложений на основе Selenium WebDriver. Он позволяет писать тесты на JavaScript, которые могут взаимодействовать с веб-страницами так же, как это делает пользователь, обеспечивая тем самым высокую точность тестирования пользовательского интерфейса.

### Формат опции:
```
--hermione-grep=HERMIONE_GREP
```
где `HERMIONE_GREP` — это шаблон (регулярное выражение или просто подстрока), по которому будет производиться поиск среди названий тестов или групп тестов (тестовых сценариев).

### Пример использования:
```
ya make --hermione-grep="Логин"
```
Эта команда запустит все тесты Hermione, в названиях которых содержится слово "Логин".

Если требуется более специфичный отбор тестов, можно использовать регулярные выражения:
```
ya make --hermione-grep="^Логин.*успех$"
```
Эта команда запустит тесты, названия которых начинаются со слова "Логин" и заканчиваются словом "успех".

### Зачем это нужно:
- **Фокусировка на конкретных тестах**: Позволяет запускать только те тесты, которые соответствуют определенному критерию, что особенно полезно при разработке или отладке тестов.
- **Экономия времени**: Запуск только релевантных тестов экономит время, особенно когда общее количество тестов велико, а необходимо проверить только определенную функциональность.
- **Упрощение интеграции с CI/CD**: Можно настроить разные пайплайны для запуска разных групп тестов в зависимости от контекста изменений в коде.

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

turns-00020.parquet:55646

08c52da990af6570f10dfb47
turn 8/31gpt-4-0125-previewRussianRussia302 words
degenerate_repetitionAbsentFinal dense release
USER
подробно с объяснениями опиши опцию --hermione-test-path=HERMIONE_TEST_PATHS
Запустить тесты, находящиеся в указанных файлах (пути должны быть относительны к cwd)
ASSISTANT
Опция `--hermione-test-path=HERMIONE_TEST_PATHS` предназначена для запуска автоматизированных тестов веб-приложений с использованием инструмента Hermione, ограничивая выполнение тестов только теми, что расположены в указанных файлах. Это позволяет более гибко управлять процессом тестирования, запуская тесты из конкретных файлов, что особенно удобно при разработке новых тестов или при необходимости провести тестирование только определенной части приложения.

**Hermione** — это инструмент для автоматизации тестирования веб-приложений, работающий на основе Selenium WebDriver. Он позволяет создавать тесты на JavaScript, имитирующие действия пользователя и взаимодействие с веб-страницами.

### Формат опции:
```
--hermione-test-path=HERMIONE_TEST_PATHS
```
где `HERMIONE_TEST_PATHS` — это один путь или список путей к файлам с тестами, разделенных запятыми. Пути должны быть указаны относительно текущей рабочей директории (cwd - current working directory).

### Пример использования:
```
ya make --hermione-test-path=./tests/loginTest.js
```
Эта команда запустит выполнение тестов, расположенных в файле `loginTest.js`, который находится в директории `tests` относительно текущей рабочей директории.

Если необходимо запустить тесты из нескольких файлов, пути к этим файлам перечисляются через запятую:
```
ya make --hermione-test-path=./tests/loginTest.js,./tests/registrationTest.js
```
В этом случае будут выполнены тесты из двух файлов: `loginTest.js` и `registrationTest.js`.

### Зачем это нужно:
- **Точечное тестирование**: Позволяет запускать тесты из конкретных файлов, что удобно при разработке новых тестов или при отладке существующих.
- **Экономия времени**: Запуск только определенных тестов экономит время, особенно когда полный прогон всех тестов занимает значительное количество времени.
- **Гибкость**: Дает возможность гибко настраивать запуск тестов в зависимости от потребностей разработки или тестирования.

### Важные моменты:
- Важно убедиться, что указанные пути к файлам корректны и файлы доступны из текущей рабочей директории.
- При использовании этой опции следует быть внимательным, чтобы не пропустить запуск важных тестов, которые могут быть расположены в других файлах.
- Эта опция особенно полезна в сочетании с другими фильтрами и опциями Hermione, позволяя создавать гибкие конфигурации для запуска тестов.

turns-00020.parquet:55647

0cb2ede9b264efaf6b687203
turn 9/31gpt-4-0125-previewRussianRussia340 words
degenerate_repetitionAbsentFinal dense release
USER
подробно с объяснениями опиши опцию --hermione-set=HERMIONE_SETS
Запустить тесты только в указанном наборе
ASSISTANT
Опция `--hermione-set=HERMIONE_SETS` используется в контексте запуска тестов с помощью инструмента Hermione, который предназначен для автоматизированного тестирования веб-приложений. Эта опция позволяет ограничить выполнение тестов только теми, которые включены в определенный набор (или наборы), предварительно сконфигурированный в файле конфигурации Hermione.

**Hermione** позволяет группировать тесты в наборы (sets), чтобы можно было легко запускать различные подгруппы тестов в зависимости от текущих требований. Например, можно создать отдельные наборы для smoke-тестов, тестов регрессии, тестов определенной функциональности и т.д. Это особенно полезно в больших проектах с обширным набором тестов, где запуск всех тестов за один раз может быть нецелесообразным.

### Формат опции:
```
--hermione-set=HERMIONE_SETS
```
где `HERMIONE_SETS` — это имя одного набора или список имен наборов, разделенных запятыми, которые должны быть выполнены.

### Пример использования:
```
ya make --hermione-set=smoke
```
Эта команда запустит выполнение только тех тестов Hermione, которые включены в набор `smoke`.

Если требуется запустить тесты из нескольких наборов, имена наборов перечисляются через запятую:
```
ya make --hermione-set=smoke,regression
```
В этом случае будут выполнены тесты, включенные в наборы `smoke` и `regression`.

### Как настроить наборы в Hermione:
Конфигурация наборов производится в файле конфигурации Hermione (обычно `hermione.conf.js` или аналогичном). Для определения наборов используется секция `sets` в конфигурационном объекте. Пример:
```javascript
module.exports = {
    sets: {
        smoke: {
            files: ['tests/smoke/*.js']
        },
        regression: {
            files: ['tests/regression/**/*.js']
        }
    },
    // Другие настройки конфигурации...
};
```
В этом примере определены два набора тестов: `smoke` и `regression`, каждый из которых содержит пути к тестовым файлам, входящим в соответствующий набор.

### Зачем это нужно:
- **Гибкость запуска тестов**: Позволяет запускать только те тесты, которые актуальны в данном контексте разработки или деплоя.
- **Оптимизация времени тестирования**: Сокращает время, необходимое на прогон тестов, позволяя фокусироваться на конкретных аспектах приложения.
- **Удобство управления**: Упрощает управление тестами, разделяя их на логические группы.

### Важные моменты:
- Важно корректно настроить наборы в файле конфигурации Hermione, чтобы использование опции `--hermione-set` было эффективным.
- При использовании этой опции следует учитывать, что тесты, не входящие в указанные наборы, не будут выполнены. Это необходимо учитывать, чтобы избежать пропуска важных проверок.

turns-00020.parquet:55648

c110b17942c2b8b139b48174
turn 10/31gpt-4-0125-previewRussianRussia311 words
degenerate_repetitionAbsentFinal dense release
USER
подробно с объяснениями опиши опцию --hermione-gui Запустить Hermione в режиме GUI
ASSISTANT
Опция `--hermione-gui` предназначена для запуска тестов, использующих инструмент Hermione, в графическом интерфейсе пользователя (GUI). Hermione — это популярный инструмент для автоматизации тестирования веб-приложений, работающий на основе Selenium WebDriver. Он позволяет писать тесты на JavaScript, которые могут взаимодействовать с веб-страницами, имитируя действия реальных пользователей.

### Формат опции:
```
--hermione-gui
```

### Как это работает:
При запуске с опцией `--hermione-gui`, Hermione инициирует веб-сервер, который предоставляет графический интерфейс для управления процессом тестирования. Этот интерфейс позволяет выбирать конкретные тесты для запуска, просматривать результаты их выполнения и взаимодействовать с тестовым окружением в более удобной и наглядной форме, чем при работе через командную строку.

### Пример использования:
```
ya make --hermione-gui
```
После запуска команды в консоли появится URL, по которому доступен графический интерфейс Hermione. Открыв этот URL в браузере, вы увидите список доступных для запуска тестов и сможете управлять процессом тестирования непосредственно из браузера.

### Зачем это нужно:
- **Удобство и наглядность**: Графический интерфейс делает процесс настройки и запуска тестов более интуитивно понятным и удобным, особенно для новых пользователей или в ситуациях, когда необходимо быстро настроить выполнение определенных тестов.
- **Отладка и диагностика**: GUI предоставляет дополнительные возможности для отладки тестов, позволяя легко перезапускать тесты, просматривать логи и отчеты о выполнении.
- **Интерактивность**: Возможность интерактивного выбора и запуска тестов упрощает процесс разработки и тестирования, позволяя быстро реагировать на изменения в коде и поведении тестируемого веб-приложения.

### Важные моменты:
- Для работы опции `--hermione-gui` необходимо, чтобы в проекте был корректно настроен и установлен Hermione, а также все зависимости, необходимые для его работы.
- Веб-интерфейс Hermione GUI требует современного браузера с поддержкой JavaScript.
- Работа в режиме GUI может потребовать дополнительных настроек безопасности, особенно если тестирование производится в сетях с ограниченным доступом или защищенных корпоративных средах.

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