Типы тестов
- Функциональные тесты — набор запросов и скриптов, включающий следующие пересекающиеся подмножества:
- Быстрый тест — минимальное подмножество
- Тесты без сохранения состояния, для которых не требуется заполнять базы данных данными
- Последовательные тесты, которые нельзя запускать параллельно
- Интеграционные тесты, запускаемые через
pytestв кластере - Модульные тесты
- Тесты производительности
- Тесты сборки
- Санитайзеры
- Фаззеры а также некоторые другие, см. разделы ниже.
Функциональные тесты
./tests/queries.
Каждый тест может быть одного из двух типов: .sql и .sh.
- Тест
.sql— это простой SQL-скрипт, который передаётся вclickhouse-client. - Тест
.sh— это скрипт, который запускается самостоятельно.
.sh.
Тесты .sh следует использовать только тогда, когда нужно проверить какую-то возможность, недоступную в чистом SQL, например передачу входных данных в clickhouse-client или тестирование clickhouse-local.
Распространённая ошибка при тестировании типов данных
DateTime и DateTime64 — считать, что сервер использует определённый часовой пояс (например, “UTC”). Это не так: в CI часовые пояса в тестовых прогонах
намеренно выбираются случайным образом. Самый простой способ обойти это — явно указывать часовой пояс для тестовых значений, например toDateTime64(val, 3, 'Europe/Amsterdam').Локальный запуск теста
01428_hash_set_nan_key, перейдите в каталог репозитория и выполните следующую команду:
stderr и stdout) записываются в файлы 01428_hash_set_nan_key.[stderr|stdout], которые находятся рядом с самим тестом (для queries/0_stateless/foo.sql вывод будет записан в queries/0_stateless/foo.stdout).
См. tests/clickhouse-test --help для просмотра всех параметров clickhouse-test.
Вы можете запустить все тесты или только их часть, указав filter по именам тестов: ./clickhouse-test substring.
Также есть параметры для запуска тестов параллельно или в случайном порядке.
Запуск быстрых тестов
t3.2xlarge с Ubuntu amd64 и хранилищем 100 ГБ.
- Установите необходимые зависимости и заново войдите в систему.
- Скачайте исходный код.
- Соберите код и запустите “быстрые тесты”.
nohup или disown, чтобы он продолжал выполняться после потери ssh-соединения.
Запуск тестов без сохранения состояния
m7i.8xlarge (Ubuntu amd64) с хранилищем объёмом 200 ГБ.
- Установите необходимые зависимости и снова войдите в систему.
- Скачайте исходный код.
- Соберите код.
- Запустите тесты без сохранения состояния, которые можно запускать параллельно.
python -m ci.praktika run запускают конкретную задачу непрерывной интеграции; подробнее о ClickHouse CI можно прочитать здесь.
Добавление нового теста
.sql или .sh в каталоге queries/0_stateless.
Затем сгенерируйте соответствующий файл .reference с помощью clickhouse-client < 12345_test.sql > 12345_test.reference или ./12345_test.sh > ./12345_test.reference.
В тестах следует только создавать, удалять, выбирать данные из и т. д. таблиц в базе данных test, которая автоматически создаётся заранее.
Допустимо использовать временные таблицы.
Чтобы локально настроить такое же окружение, как в CI, установите конфигурации для тестов (они будут использовать mock-реализацию ZooKeeper и скорректируют некоторые настройки)
Тесты должны быть
- минимальными: создавать только абсолютно необходимые таблицы и столбцы и сохранять минимальную сложность,
- быстрыми: выполняться не дольше нескольких секунд (а лучше — меньше секунды),
- корректными и детерминированными: завершаться с ошибкой тогда и только тогда, когда тестируемая возможность не работает,
- изолированными/без состояния: не зависеть от окружения и таймингов
- исчерпывающими: охватывать пограничные случаи, такие как нули, NULL-значения, пустые множества, исключения (отрицательные тесты; для этого используйте синтаксис
-- { serverError xyz }и-- { clientError xyz }), - очищать таблицы в конце теста (на случай, если что-то осталось),
- убеждаться, что другие тесты не проверяют то же самое (то есть сначала выполните grep).
Ограничение запуска тестов
.sql теги указываются в первой строке в виде SQL-комментария:
.sh теги записываются в виде комментария во второй строке:
| Название тега | Что делает | Пример использования |
|---|---|---|
disabled | Тест не запускается | |
long | Время выполнения теста увеличивается с 1 до 10 минут | |
deadlock | Тест долго выполняется в цикле | |
race | То же, что и deadlock. Предпочтителен deadlock | |
shard | Сервер должен принимать соединения на 127.0.0.* | |
distributed | То же, что и shard. Предпочтителен shard | |
global | То же, что и shard. Предпочтителен shard | |
zookeeper | Для запуска теста требуется ZooKeeper или ClickHouse Keeper | Тест использует ReplicatedMergeTree |
replica | То же, что и zookeeper. Предпочтителен zookeeper | |
no-fasttest | Тест не запускается в Быстром тесте | Тест использует движок таблицы MySQL, который отключен в Быстром тесте |
fasttest-only | Тест запускается только в Быстром тесте | |
no-[asan, tsan, msan, ubsan] | Отключает тесты в сборках с санитайзерами | Тест запускается под QEMU, который не работает с санитайзерами |
no-replicated-database | Отключает тест, если база данных по умолчанию использует ReplicatedDatabaseEngine | |
no-ordinary-database | Отключает тест, если движок базы данных по умолчанию — Ordinary | |
no-parallel | Запрещает параллельный запуск других тестов вместе с этим | Тест читает из таблиц system, и инварианты могут быть нарушены |
no-parallel-replicas | Отключает тест, если включены параллельные реплики | |
no-debug | Отключает тесты в Debug-сборках | |
no-release | Отключает тесты в Release-сборках | |
no-darwin | Отключает тест в macOS (Darwin) | Тест зависит от специфичных для Linux возможностей, таких как распределенные запросы, procfs или HTTP-сервер |
no-stress, no-polymorphic-parts, no-random-settings, no-random-merge-tree-settings, no-backward-compatibility-check, no-cpu-x86_64, no-cpu-aarch64, no-cpu-ppc64le, no-s3-storage.
Помимо перечисленных выше настроек, вы можете использовать флаги USE_* из system.build_options, чтобы указывать использование конкретных возможностей ClickHouse.
Например, если ваш тест использует таблицу MySQL, следует добавить тег use-mysql.
Указание ограничений для случайных настроек
.sh ограничения записываются в виде комментария в строке рядом с тегами или на второй строке, если теги не указаны:
.sql теги указываются в виде SQL-комментария в строке рядом с тегами или в первой строке:
None.
Выбор имени теста
00422_hash_function_constexpr.sql.
Чтобы выбрать префикс, найдите наибольший префикс, уже имеющийся в каталоге, и увеличьте его на единицу.
Проверка ошибки, которая должна возникнуть
x.
Если ошибка не возникает или отличается от ожидаемой, тест завершится неудачей.
Если вы хотите убедиться, что ошибка возникает на стороне клиента, используйте аннотацию clientError.
Не проверяйте конкретную формулировку сообщения об ошибке: в будущем она может измениться, и тест будет ломаться без необходимости.
Проверяйте только код ошибки.
Если существующий код ошибки недостаточно точен для ваших задач, подумайте о том, чтобы добавить новый.
Тестирование распределённого запроса
remote с адресами 127.0.0.{1..2}, чтобы сервер отправлял запросы самому себе; либо использовать предопределённые тестовые кластеры из файла конфигурации сервера, например test_shard_localhost.
Не забудьте добавить слова shard или distributed в имя теста, чтобы он запускался в CI с правильной конфигурацией, где сервер поддерживает распределённые запросы.
Работа с временными файлами
$CLICKHOUSE_TEST_UNIQUE_NAME, чтобы задавать временным файлам уникальные имена для каждого выполняемого теста.
Так вы сможете быть уверены, что файл, который вы создаёте при подготовке или удаляете при очистке, используется только этим тестом, а не каким-то другим, выполняющимся параллельно.
Известные ошибки
tests/queries/bugs.
После исправления ошибок эти тесты переносятся в tests/queries/0_stateless.
Интеграционные тесты
tests/integration/README.md, чтобы узнать, как запускать эти тесты.
Обратите внимание, что интеграция ClickHouse со сторонними драйверами не тестируется.
Кроме того, сейчас у нас нет интеграционных тестов для наших драйверов JDBC и ODBC.
Модульные тесты
ENABLE_TESTS.
Модульные тесты (и другие тестовые программы) находятся в подкаталогах tests по всему коду.
Чтобы запустить модульные тесты, выполните ninja test.
Некоторые тесты используют gtest, а некоторые — это просто программы, которые при сбое теста возвращают ненулевой код завершения.
Модульные тесты не обязательны, если код уже покрыт функциональными тестами (к тому же функциональные тесты обычно гораздо проще в использовании).
Вы можете запускать отдельные проверки gtest, вызывая исполняемый файл напрямую, например:
Тесты производительности
tests/performance/.
Каждый тест представлен файлом .xml с описанием тестового сценария.
Тесты запускаются с помощью инструмента docker/test/performance-comparison. Инструкции по запуску см. в файле readme.
Каждый тест в цикле выполняет один или несколько запросов (возможно, с различными комбинациями параметров).
Если вы хотите повысить производительность ClickHouse в каком-либо сценарии и улучшения можно наблюдать на простых запросах, настоятельно рекомендуется написать тест производительности.
Также рекомендуется писать тесты производительности при добавлении или изменении SQL-функций, которые достаточно изолированы и не слишком узкоспециализированы.
Во время тестирования всегда полезно использовать perf top или другие инструменты perf.
Инструменты и скрипты для тестирования
tests — это не готовые тесты, а вспомогательные инструменты для тестирования.
Например, для Lexer есть инструмент src/Parsers/tests/lexer, который просто разбивает stdin на токены и записывает результат с цветовой подсветкой в stdout.
Вы можете использовать такие инструменты как примеры кода, а также для изучения и ручного тестирования.
Прочие тесты
tests/external_models есть тесты для моделей машинного обучения.
Эти тесты не поддерживаются и должны быть перенесены в интеграционные тесты.
Есть отдельный тест для вставок с кворумом.
Этот тест запускает кластер ClickHouse на отдельных серверах и эмулирует различные сценарии сбоев: сетевое разделение, потерю пакетов (между узлами ClickHouse, между ClickHouse и ZooKeeper, между сервером ClickHouse и клиентом и т. д.), kill -9, kill -STOP и kill -CONT, как в Jepsen. Затем тест проверяет, что все подтверждённые вставки были записаны, а все отклонённые — нет.
Ручное тестирование
programs/clickhouse-server и выполните ./clickhouse-server. По умолчанию он будет использовать конфигурацию (config.xml, users.xml и файлы в каталогах config.d и users.d) из текущего каталога. Чтобы подключиться к серверу ClickHouse, запустите programs/clickhouse-client/clickhouse-client.
Обратите внимание, что все инструменты ClickHouse (server, client и т. д.) — это просто символьные ссылки на один бинарный файл с именем clickhouse.
Этот бинарный файл находится в programs/clickhouse.
Все инструменты также можно запускать как clickhouse tool вместо clickhouse-tool.
Кроме того, вы можете установить пакет ClickHouse: либо стабильный релиз из репозитория ClickHouse, либо собрать пакет самостоятельно с помощью ./release в корневом каталоге исходного кода ClickHouse.
Затем запустите сервер командой sudo clickhouse start (или stop, чтобы остановить сервер).
Ищите журнал по пути /etc/clickhouse-server/clickhouse-server.log.
Если ClickHouse уже установлен в вашей системе, вы можете собрать новый бинарный файл clickhouse и заменить существующий бинарный файл:
clickhouse-server уже запущен и вы не хотите его останавливать, можно изменить номера портов в config.xml (или переопределить их в файле в каталоге config.d), указать подходящий путь к данным и запустить сервер.
Бинарный файл clickhouse почти не имеет зависимостей и работает в широком спектре дистрибутивов Linux.
Чтобы быстро проверить свои изменения на сервере, можно просто скопировать с помощью scp свежесобранный бинарный файл clickhouse на сервер, а затем запустить его, как в примерах выше.
Тесты сборки
- кросс-компиляция для Darwin x86_64 (macOS)
- кросс-компиляция для FreeBSD x86_64
- кросс-компиляция для Linux AArch64
- сборка на Ubuntu с библиотеками из системных пакетов (не рекомендуется)
- сборка с динамической компоновкой библиотек (не рекомендуется)
Проверка совместимости протокола
clickhouse-client работает с новым clickhouse-server, а новый clickhouse-client — со старым clickhouse-server (для этого достаточно запустить бинарные файлы из соответствующих пакетов).
Некоторые случаи мы также проверяем автоматически с помощью интеграционных тестов:
- можно ли в новой версии успешно прочитать данные, записанные старой версией ClickHouse;
- работают ли распределенные запросы в кластере с разными версиями ClickHouse.
Помощь от компилятора
src) собирается с флагами -Wall -Wextra -Werror и некоторыми дополнительными предупреждениями.
Однако для сторонних библиотек эти параметры не включены.
У Clang есть ещё больше полезных предупреждений — их можно посмотреть с помощью -Weverything и выбрать некоторые для сборки по умолчанию.
Мы всегда используем clang для сборки ClickHouse — и для разработки, и в production.
Вы можете собирать на своей машине в режиме отладки (чтобы экономить заряд ноутбука), но обратите внимание, что компилятор может генерировать больше предупреждений с -O3 благодаря более качественному анализу потока управления и межпроцедурному анализу.
При сборке с clang в режиме отладки используется отладочная версия libc++, которая позволяет выявлять больше ошибок во время выполнения.
Санитайзеры
Если процесс (сервер ClickHouse или клиент) аварийно завершается при запуске локально, возможно, потребуется отключить рандомизацию адресного пространства:
sudo sysctl kernel.randomize_va_space=0AddressSanitizer
Санитайзер потоков
Санитайзер памяти
Санитайзер неопределённого поведения
Valgrind (memcheck)
re2, см. эту статью.
Фаззинг
src/Parsers/fuzzers/lexer_fuzzer.cpp.
Конфигурации, словари и корпус данных для LibFuzzer хранятся в tests/fuzz.
Мы рекомендуем писать фазз-тесты для любой функциональности, которая обрабатывает пользовательский ввод.
По умолчанию фаззеры не собираются.
Чтобы собрать фаззеры, нужно задать оба параметра: -DENABLE_FUZZING=1 и -DENABLE_TESTS=1.
Мы рекомендуем отключать Jemalloc при сборке фаззеров.
Конфигурацию, используемую для интеграции фаззинга ClickHouse с
Google OSS-Fuzz, можно найти в docker/fuzz.
Мы также используем простой фазз-тест для генерации случайных SQL-запросов и проверки того, что сервер не падает при их выполнении.
Вы можете найти его в 00746_sql_fuzzy.pl.
Этот тест следует запускать непрерывно (в течение ночи и дольше).
Мы также используем более сложный фаззер запросов на основе AST, который способен находить огромное количество граничных случаев.
Он выполняет случайные перестановки и подстановки в AST запросов.
Он запоминает узлы AST из предыдущих тестов, чтобы использовать их для фаззинга последующих тестов, обрабатывая их в случайном порядке.
Подробнее об этом фаззере можно узнать в этой статье блога.
Стресс-тест
- сервер не падает, не срабатывают ловушки отладчика или санитайзера;
- отсутствуют взаимные блокировки;
- структура базы данных остаётся согласованной;
- сервер может успешно остановиться после теста и снова запуститься без исключений.
Thread fuzzer
Аудит безопасности
Статические анализаторы
clang-tidy для каждого коммита.
Проверки clang-static-analyzer также включены.
clang-tidy также используется для некоторых проверок стиля.
Мы протестировали clang-tidy, Coverity, cppcheck, PVS-Studio, tscancode, CodeQL.
Инструкции по использованию вы найдете в каталоге tests/instructions/.
Если вы используете CLion в качестве IDE, некоторые проверки clang-tidy будут доступны сразу.
Мы также используем shellcheck для статического анализа shell-скриптов.
Усиление защиты
Проверки целостности во время работы
- и это не замедляет работу.
Стиль кода
utils/check-style.
Чтобы привести код к правильному стилю, можно использовать clang-format.
Файл .clang-format находится в корне исходников.
Он в целом соответствует нашему текущему стилю кода.
Но применять clang-format к существующим файлам не рекомендуется, поскольку это может ухудшить форматирование.
Вместо этого можно использовать инструмент clang-format-diff, который находится в репозитории с исходным кодом clang.
Кроме того, можно попробовать инструмент uncrustify для переформатирования кода.
Конфигурация находится в uncrustify.cfg в корне исходников.
Он протестирован меньше, чем clang-format.
У CLion есть собственный форматтер кода, который нужно настроить под наш стиль кода.
Мы также используем codespell для поиска опечаток в коде.
Это тоже делается автоматически.