> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-mintlify-8c05c8a2.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Руководство по тестированию ClickHouse и запуску набора тестов

# Тестирование ClickHouse

<div id="test-types">
  ## Типы тестов
</div>

В ClickHouse есть следующие типы тестов:

* [Функциональные тесты](#functional-tests) — набор запросов и скриптов, включающий следующие пересекающиеся подмножества:
  * [Быстрый тест](#running-fast-tests) — минимальное подмножество
  * [Тесты без сохранения состояния](#running-stateless-tests), для которых не требуется заполнять базы данных данными
  * Последовательные тесты, которые нельзя запускать параллельно
* [Интеграционные тесты](#integration-tests), запускаемые через `pytest` в кластере
* [Модульные тесты](#unit-tests)
* [Тесты производительности](#performance-tests)
* [Тесты сборки](#build-tests)
* [Санитайзеры](#sanitizers)
* [Фаззеры](#fuzzing)
  а также некоторые другие, см. разделы ниже.

<div id="functional-tests">
  ## Функциональные тесты
</div>

Функциональные тесты — самый простой и удобный вариант.
Большинство возможностей ClickHouse можно проверять с помощью функциональных тестов, и их обязательно нужно использовать для любого изменения в коде ClickHouse, которое можно протестировать таким способом.

Каждый функциональный тест отправляет один или несколько запросов на работающий сервер ClickHouse и сравнивает результат с эталоном.

Тесты находятся в каталоге `./tests/queries`.

Каждый тест может быть одного из двух типов: `.sql` и `.sh`.

* Тест `.sql` — это простой SQL-скрипт, который передаётся в `clickhouse-client`.
* Тест `.sh` — это скрипт, который запускается самостоятельно.

Как правило, SQL-тесты предпочтительнее тестов `.sh`.
Тесты `.sh` следует использовать только тогда, когда нужно проверить какую-то возможность, недоступную в чистом SQL, например передачу входных данных в `clickhouse-client` или тестирование `clickhouse-local`.

<Note>
  Распространённая ошибка при тестировании типов данных `DateTime` и `DateTime64` — считать, что сервер использует определённый часовой пояс (например, "UTC"). Это не так: в CI часовые пояса в тестовых прогонах
  намеренно выбираются случайным образом. Самый простой способ обойти это — явно указывать часовой пояс для тестовых значений, например `toDateTime64(val, 3, 'Europe/Amsterdam')`.
</Note>

<div id="running-a-test-locally">
  ### Локальный запуск теста
</div>

Запустите сервер ClickHouse локально на порту по умолчанию (9000).
Чтобы запустить, например, тест `01428_hash_set_nan_key`, перейдите в каталог репозитория и выполните следующую команду:

```sh theme={null}
PATH=<path to clickhouse-client>:$PATH tests/clickhouse-test 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`.
Также есть параметры для запуска тестов параллельно или в случайном порядке.

<div id="running-fast-tests">
  ### Запуск быстрых тестов
</div>

Для запуска подмножества тестов (так называемого "Быстрый тест") может потребоваться достаточно мощная машина. Приведённые ниже команды работают на AWS-инстансе `t3.2xlarge` с Ubuntu amd64 и хранилищем 100 ГБ.

1. Установите необходимые зависимости и заново войдите в систему.

```sh theme={null}
sudo apt-get update
sudo apt-get install docker.io
sudo usermod -aG docker "$USER"
```

2. Скачайте исходный код.

```sh theme={null}
git clone --single-branch https://github.com/ClickHouse/ClickHouse
cd ClickHouse
```

3. Соберите код и запустите "быстрые тесты".

```sh theme={null}
python -m ci.praktika run fast
```

Должно получиться

```sh theme={null}
Failed: 0, Passed: 7394, Skipped: 1795
```

Если вы оставляете запуск без присмотра, можно использовать `nohup` или `disown`, чтобы он продолжал выполняться после потери `ssh`-соединения.

<div id="running-stateless-tests">
  ### Запуск тестов без сохранения состояния
</div>

Для запуска тестов без сохранения состояния может потребоваться достаточно мощная машина. Приведённый ниже вариант работает на инстансе AWS `m7i.8xlarge` (Ubuntu amd64) с хранилищем объёмом 200 ГБ.

1. Установите необходимые зависимости и снова войдите в систему.

```sh theme={null}
sudo apt-get update
sudo apt-get install docker.io
sudo usermod -aG docker "$USER"
sudo tee /etc/docker/daemon.json <<'EOF'
{
  "ipv6": true,
  "ip6tables": true
}
EOF
sudo systemctl restart docker
```

2. Скачайте исходный код.

```sh theme={null}
git clone --single-branch https://github.com/ClickHouse/ClickHouse
cd ClickHouse
```

3. Соберите код.

```sh theme={null}
python -m ci.praktika run build_debug
cp ci/tmp/build/programs/clickhouse ci/tmp
```

4. Запустите тесты без сохранения состояния, которые можно запускать параллельно.

```sh theme={null}
python -m ci.praktika run functional
```

Должно получиться

```sh theme={null}
Failed: 0, Passed: 8497, Skipped: 103
```

Примечание. Команды `python -m ci.praktika run` запускают конкретную задачу непрерывной интеграции; подробнее о ClickHouse CI можно прочитать [здесь](/ru/resources/develop-contribute/contribute/continuous-integration#running-stateless-tests).

<div id="adding-a-new-test">
  ### Добавление нового теста
</div>

Чтобы добавить новый тест, сначала создайте файл `.sql` или `.sh` в каталоге `queries/0_stateless`.
Затем сгенерируйте соответствующий файл `.reference` с помощью `clickhouse-client < 12345_test.sql > 12345_test.reference` или `./12345_test.sh > ./12345_test.reference`.

В тестах следует только создавать, удалять, выбирать данные из и т. д. таблиц в базе данных `test`, которая автоматически создаётся заранее.
Допустимо использовать временные таблицы.

Чтобы локально настроить такое же окружение, как в CI, установите конфигурации для тестов (они будут использовать mock-реализацию ZooKeeper и скорректируют некоторые настройки)

```sh theme={null}
cd <repository>/tests/config
sudo ./install.sh
```

<Note>
  Тесты должны быть

  * минимальными: создавать только абсолютно необходимые таблицы и столбцы и сохранять минимальную сложность,
  * быстрыми: выполняться не дольше нескольких секунд (а лучше — меньше секунды),
  * корректными и детерминированными: завершаться с ошибкой тогда и только тогда, когда тестируемая возможность не работает,
  * изолированными/без состояния: не зависеть от окружения и таймингов
  * исчерпывающими: охватывать пограничные случаи, такие как нули, NULL-значения, пустые множества, исключения (отрицательные тесты; для этого используйте синтаксис `-- { serverError xyz }` и `-- { clientError xyz }`),
  * очищать таблицы в конце теста (на случай, если что-то осталось),
  * убеждаться, что другие тесты не проверяют то же самое (то есть сначала выполните grep).
</Note>

<div id="templated-tests-with-jinja">
  ### Шаблонизированные тесты с Jinja
</div>

Тест `.sql` можно написать в виде шаблона [Jinja2](https://jinja.palletsprojects.com/), добавив к имени файла суффикс `.j2`, так что `foo.sql` превратится в `foo.sql.j2`. Перед запуском теста `clickhouse-test` рендерит шаблон в обычный скрипт `.sql` и выполняет получившийся результат.

Это полезно, когда в тесте один и тот же запрос повторяется с небольшими вариациями: цикл генерирует запросы из компактного шаблона, вместо того чтобы прописывать каждый вручную. Чаще всего используются следующие конструкции:

* `{% for ... %} ... {% endfor %}` — для повторения блока,
* `{{ expression }}` — для подстановки значения в вывод,
* `-%}` и `{%-` — для удаления соседних пробельных символов, чтобы сгенерированный скрипт оставался аккуратным.

Например, этот шаблон:

```sql theme={null}
{% for type in ['UInt8', 'UInt16', 'UInt32'] -%}
SELECT toTypeName(0::{{ type }});
{% endfor -%}
```

получается:

```sql theme={null}
SELECT toTypeName(0::UInt8);
SELECT toTypeName(0::UInt16);
SELECT toTypeName(0::UInt32);
```

Ожидаемый вывод можно задать либо как обычный файл `<name>.reference`, содержащий полностью развёрнутые результаты, либо как шаблон `<name>.reference.j2`, который `clickhouse-test` перед сравнением обрабатывает аналогичным образом. Используйте шаблонный вариант, если ожидаемый вывод тоже имеет повторяющуюся структуру. Больше примеров см. в существующих файлах `*.sql.j2` в `tests/queries/0_stateless/`.

<div id="restricting-test-runs">
  ### Ограничение запуска тестов
</div>

У теста может быть ноль или более *тегов*, задающих ограничения на то, в каких контекстах он запускается в CI.

Для тестов `.sql` теги указываются в первой строке в виде SQL-комментария:

```sql theme={null}
-- Tags: no-fasttest, no-replicated-database
-- no-fasttest: <provide_a_reason_for_the_tag_here>
-- no-replicated-database: <provide_a_reason_here>

SELECT 1
```

Для тестов `.sh` теги записываются в виде комментария во второй строке:

```bash theme={null}
#!/usr/bin/env bash
# Tags: no-fasttest, no-replicated-database
# - no-fasttest: <provide_a_reason_for_the_tag_here>
# - no-replicated-database: <provide_a_reason_here>
```

Список доступных тегов:

| Название тега                  | Что делает                                                                          | Пример использования                                                                                           |
| ------------------------------ | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `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`                  | Тест не запускается в [Быстром тесте](#test-types)                                  | Тест использует движок таблицы `MySQL`, который отключен в Быстром тесте                                       |
| `fasttest-only`                | Тест запускается только в [Быстром тесте](#test-types)                              |                                                                                                                |
| `no-[asan, tsan, msan, ubsan]` | Отключает тесты в сборках с [санитайзерами](#sanitizers)                            | Тест запускается под 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-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`.

<div id="specifying-limits-for-random-settings">
  ### Указание ограничений для случайных настроек
</div>

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

Для тестов `.sh` ограничения записываются в виде комментария в строке рядом с тегами или на второй строке, если теги не указаны:

```bash theme={null}
#!/usr/bin/env bash
# Tags: no-fasttest
# Random settings limits: max_block_size=(1000, 10000); index_granularity=(100, None)
```

Для тестов `.sql` теги указываются в виде SQL-комментария в строке рядом с тегами или в первой строке:

```sql theme={null}
-- Tags: no-fasttest
-- Random settings limits: max_block_size=(1000, 10000); index_granularity=(100, None)
SELECT 1
```

Если нужно указать только одно ограничение, для второго можно использовать `None`.

<div id="choosing-the-test-name">
  ### Выбор имени теста
</div>

Имя теста начинается с пятизначного префикса, за которым следует описательное имя, например `00422_hash_function_constexpr.sql`.
Чтобы выбрать префикс, найдите наибольший префикс, уже имеющийся в каталоге, и увеличьте его на единицу.

```sh theme={null}
ls tests/queries/0_stateless/[0-9]*.reference | tail -n 1
```

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

<div id="checking-for-an-error-that-must-occur">
  ### Проверка ошибки, которая должна возникнуть
</div>

Иногда требуется проверить, что при некорректном запросе возникает ошибка сервера. Для этого в SQL-тестах поддерживаются специальные annotations следующего вида:

```sql theme={null}
SELECT x; -- { serverError 49 }
```

Этот тест проверяет, что сервер возвращает ошибку с кодом 49 о неизвестном столбце `x`.
Если ошибка не возникает или отличается от ожидаемой, тест завершится неудачей.
Если вы хотите убедиться, что ошибка возникает на стороне клиента, используйте аннотацию `clientError`.

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

<div id="testing-a-distributed-query">
  ### Тестирование распределённого запроса
</div>

Если вы хотите использовать распределённые запросы в функциональных тестах, можно воспользоваться табличной функцией `remote` с адресами `127.0.0.{1..2}`, чтобы сервер отправлял запросы самому себе; либо использовать предопределённые тестовые кластеры из файла конфигурации сервера, например `test_shard_localhost`.
Не забудьте добавить слова `shard` или `distributed` в имя теста, чтобы он запускался в CI с правильной конфигурацией, где сервер поддерживает распределённые запросы.

<div id="working-with-temporary-files">
  ### Работа с временными файлами
</div>

Иногда в shell-тесте может потребоваться создать файл на лету.
Имейте в виду, что некоторые проверки CI запускают тесты параллельно, поэтому, если вы создаёте или удаляете временный файл в своём скрипте без уникального имени, это может привести к сбою некоторых проверок CI, например Flaky.
Чтобы избежать этого, используйте переменную окружения `$CLICKHOUSE_TEST_UNIQUE_NAME`, чтобы задавать временным файлам уникальные имена для каждого выполняемого теста.
Так вы сможете быть уверены, что файл, который вы создаёте при подготовке или удаляете при очистке, используется только этим тестом, а не каким-то другим, выполняющимся параллельно.

<div id="known-bugs">
  ## Известные ошибки
</div>

Если нам известны ошибки, которые можно легко воспроизвести с помощью функциональных тестов, мы помещаем соответствующие готовые тесты в каталог `tests/queries/bugs`.
После исправления ошибок эти тесты переносятся в `tests/queries/0_stateless`.

<div id="integration-tests">
  ## Интеграционные тесты
</div>

Интеграционные тесты позволяют тестировать ClickHouse в кластерной конфигурации, а также его взаимодействие с другими серверами, такими как MySQL, Postgres и MongoDB.
Они полезны для эмуляции разделения сети, потери пакетов и т. п.
Эти тесты запускаются в Docker и создают несколько контейнеров с различным ПО.

См. `tests/integration/README.md`, чтобы узнать, как запускать эти тесты.

Обратите внимание, что интеграция ClickHouse со сторонними драйверами не тестируется.
Кроме того, сейчас у нас нет интеграционных тестов для наших драйверов JDBC и ODBC.

<div id="unit-tests">
  ## Модульные тесты
</div>

Модульные тесты полезны, когда нужно тестировать не ClickHouse целиком, а отдельную изолированную библиотеку или класс.
Сборку тестов можно включить или отключить с помощью параметра CMake `ENABLE_TESTS`.
Модульные тесты (и другие тестовые программы) находятся в подкаталогах `tests` по всему коду.
Чтобы запустить модульные тесты, выполните `ninja test`.
Некоторые тесты используют `gtest`, а некоторые — это просто программы, которые при сбое теста возвращают ненулевой код завершения.

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

Вы можете запускать отдельные проверки gtest, вызывая исполняемый файл напрямую, например:

```bash theme={null}
$ ./src/unit_tests_dbms --gtest_filter=LocalAddress*
```

<div id="performance-tests">
  ## Тесты производительности
</div>

Тесты производительности позволяют измерять и сравнивать производительность отдельных изолированных частей ClickHouse на синтетических запросах.
Тесты производительности находятся в каталоге `tests/performance/`.
Каждый тест представлен файлом `.xml` с описанием тестового сценария.
Тесты запускаются с помощью инструмента `docker/test/performance-comparison`. Инструкции по запуску см. в файле readme.

Каждый тест в цикле выполняет один или несколько запросов (возможно, с различными комбинациями параметров).

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

<div id="test-tools-and-scripts">
  ## Инструменты и скрипты для тестирования
</div>

Некоторые программы в каталоге `tests` — это не готовые тесты, а вспомогательные инструменты для тестирования.
Например, для `Lexer` есть инструмент `src/Parsers/tests/lexer`, который просто разбивает stdin на токены и записывает результат с цветовой подсветкой в stdout.
Вы можете использовать такие инструменты как примеры кода, а также для изучения и ручного тестирования.

<div id="miscellaneous-tests">
  ## Прочие тесты
</div>

В `tests/external_models` есть тесты для моделей машинного обучения.
Эти тесты не поддерживаются и должны быть перенесены в интеграционные тесты.

Есть отдельный тест для вставок с кворумом.
Этот тест запускает кластер ClickHouse на отдельных серверах и эмулирует различные сценарии сбоев: сетевое разделение, потерю пакетов (между узлами ClickHouse, между ClickHouse и ZooKeeper, между сервером ClickHouse и клиентом и т. д.), `kill -9`, `kill -STOP` и `kill -CONT`, как в [Jepsen](https://aphyr.com/tags/Jepsen). Затем тест проверяет, что все подтверждённые вставки были записаны, а все отклонённые — нет.

<div id="manual-testing">
  ## Ручное тестирование
</div>

Когда вы разрабатываете новую возможность, имеет смысл также протестировать её вручную.
Это можно сделать, выполнив следующие шаги:

Соберите ClickHouse. Запустите ClickHouse из терминала: перейдите в каталог `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` и заменить существующий бинарный файл:

```bash theme={null}
$ sudo clickhouse stop
$ sudo cp ./clickhouse /usr/bin/
$ sudo clickhouse start
```

Также можно остановить системный clickhouse-server и запустить свой экземпляр с той же конфигурацией, но с выводом логов в терминал:

```bash theme={null}
$ sudo clickhouse stop
$ sudo -u clickhouse /usr/bin/clickhouse server --config-file /etc/clickhouse-server/config.xml
```

Пример с gdb:

```bash theme={null}
$ sudo -u clickhouse gdb --args /usr/bin/clickhouse server --config-file /etc/clickhouse-server/config.xml
```

Если системный `clickhouse-server` уже запущен и вы не хотите его останавливать, можно изменить номера портов в `config.xml` (или переопределить их в файле в каталоге `config.d`), указать подходящий путь к данным и запустить сервер.

Бинарный файл `clickhouse` почти не имеет зависимостей и работает в широком спектре дистрибутивов Linux.
Чтобы быстро проверить свои изменения на сервере, можно просто скопировать с помощью `scp` свежесобранный бинарный файл `clickhouse` на сервер, а затем запустить его, как в примерах выше.

<div id="build-tests">
  ## Тесты сборки
</div>

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

Примеры:

* кросс-компиляция для Darwin x86\_64 (macOS)
* кросс-компиляция для FreeBSD x86\_64
* кросс-компиляция для Linux AArch64
* сборка на Ubuntu с библиотеками из системных пакетов (не рекомендуется)
* сборка с динамической компоновкой библиотек (не рекомендуется)

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

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

Мы также проверяем, что нет единиц компиляции, которые компилируются слишком долго или требуют слишком много оперативной памяти.

Мы также проверяем, что нет слишком больших кадров стека.

<div id="testing-for-protocol-compatibility">
  ## Проверка совместимости протокола
</div>

При расширении сетевого протокола ClickHouse мы вручную проверяем, что старый `clickhouse-client` работает с новым `clickhouse-server`, а новый `clickhouse-client` — со старым `clickhouse-server` (для этого достаточно запустить бинарные файлы из соответствующих пакетов).

Некоторые случаи мы также проверяем автоматически с помощью интеграционных тестов:

* можно ли в новой версии успешно прочитать данные, записанные старой версией ClickHouse;
* работают ли распределенные запросы в кластере с разными версиями ClickHouse.

<div id="help-from-the-compiler">
  ## Помощь от компилятора
</div>

Основной код ClickHouse (то есть код, расположенный в каталоге `src`) собирается с флагами `-Wall -Wextra -Werror` и некоторыми дополнительными предупреждениями.
Однако для сторонних библиотек эти параметры не включены.

У Clang есть ещё больше полезных предупреждений — их можно посмотреть с помощью `-Weverything` и выбрать некоторые для сборки по умолчанию.

Мы всегда используем clang для сборки ClickHouse — и для разработки, и в production.
Вы можете собирать на своей машине в режиме отладки (чтобы экономить заряд ноутбука), но обратите внимание, что компилятор может генерировать больше предупреждений с `-O3` благодаря более качественному анализу потока управления и межпроцедурному анализу.
При сборке с clang в режиме отладки используется отладочная версия `libc++`, которая позволяет выявлять больше ошибок во время выполнения.

<div id="sanitizers">
  ## Санитайзеры
</div>

<Note>
  Если процесс (сервер ClickHouse или клиент) аварийно завершается при запуске локально, возможно, потребуется отключить рандомизацию адресного пространства: `sudo sysctl kernel.randomize_va_space=0`
</Note>

<div id="address-sanitizer">
  ### AddressSanitizer
</div>

Мы запускаем функциональные, интеграционные, стрессовые и модульные тесты с ASan при каждом коммите.

<div id="thread-sanitizer">
  ### Санитайзер потоков
</div>

Мы запускаем функциональные, интеграционные, стрессовые и модульные тесты с TSan для каждого коммита.

<div id="memory-sanitizer">
  ### Санитайзер памяти
</div>

Мы запускаем функциональные, интеграционные, стрессовые и модульные тесты под MSan для каждого коммита.

<div id="undefined-behaviour-sanitizer">
  ### Санитайзер неопределённого поведения
</div>

Мы запускаем функциональные, интеграционные, стресс- и модульные тесты с UBSan для каждого коммита.
Для кода некоторых сторонних библиотек проверка на UB с помощью UBSan не выполняется.

<div id="valgrind-memcheck">
  ### Valgrind (memcheck)
</div>

Раньше мы запускали функциональные тесты под Valgrind по ночам, но теперь этого больше не делаем.
Это занимает несколько часов.
В настоящее время известно об одном ложноположительном срабатывании в библиотеке `re2`, см. [эту статью](https://research.swtch.com/sparse).

<div id="fuzzing">
  ## Фаззинг
</div>

Фаззинг в ClickHouse реализован как с использованием [libFuzzer](https://llvm.org/docs/LibFuzzer.html), так и с помощью случайных SQL-запросов.
Все фазз-тесты следует выполнять с санитайзерами (Address и Undefined).

LibFuzzer используется для изолированного фазз-тестирования библиотечного кода.
Фаззеры реализованы как часть тестового кода и имеют суффикс "\_fuzzer" в имени.
Пример фаззера можно найти в `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 из предыдущих тестов, чтобы использовать их для фаззинга последующих тестов, обрабатывая их в случайном порядке.
Подробнее об этом фаззере можно узнать в [этой статье блога](https://clickhouse.com/blog/fuzzing-click-house).

<div id="stress-test">
  ## Стресс-тест
</div>

Стресс-тесты — ещё один вид фаззинга.
Он запускает все функциональные тесты параллельно, в случайном порядке, на одном сервере.
Результаты тестов не проверяются.

Проверяется, что:

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

Существует пять вариантов (Debug, ASan, TSan, MSan, UBSan).

<div id="thread-fuzzer">
  ## Thread fuzzer
</div>

Thread Fuzzer (не путайте с Thread Sanitizer) — это ещё один вид фаззинга, который позволяет случайным образом изменять порядок выполнения потоков.
Он помогает находить ещё больше нетривиальных случаев.

<div id="security-audit">
  ## Аудит безопасности
</div>

Наша команда по безопасности провела общий обзор возможностей ClickHouse с точки зрения безопасности.

<div id="static-analyzers">
  ## Статические анализаторы
</div>

Мы запускаем `clang-tidy` для каждого коммита.
Проверки `clang-static-analyzer` также включены.
`clang-tidy` также используется для некоторых проверок стиля.

Мы протестировали `clang-tidy`, `Coverity`, `cppcheck`, `PVS-Studio`, `tscancode`, `CodeQL`.
Инструкции по использованию вы найдете в каталоге `tests/instructions/`.

Если вы используете `CLion` в качестве IDE, некоторые проверки `clang-tidy` будут доступны сразу.

Мы также используем `shellcheck` для статического анализа shell-скриптов.

<div id="hardening">
  ## Усиление защиты
</div>

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

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

В отладочной сборке мы также используем модифицированную libc, которая гарантирует, что не будут вызываться «вредные» (устаревшие, небезопасные, непотокобезопасные) функции.

Assert-проверки в отладочной сборке используются очень широко.

В отладочной сборке, если генерируется исключение с кодом "logical error" (что указывает на ошибку в программе), программа аварийно завершается.
Это позволяет использовать исключения в релизной сборке, но в отладочной сборке трактовать их как assert-проверку.

Для отладочных сборок используется отладочная версия jemalloc.
Для отладочных сборок используется отладочная версия libc++.

<div id="runtime-integrity-checks">
  ## Проверки целостности во время работы
</div>

Для данных, хранящихся на диске, вычисляются контрольные суммы.
Для данных в таблицах MergeTree контрольные суммы одновременно вычисляются тремя способами\* (для сжатых блоков данных, несжатых блоков данных и в виде общей контрольной суммы по всем блокам).
Для данных, передаваемых по сети между клиентом и сервером или между серверами, также вычисляются контрольные суммы.
Репликация обеспечивает побитовую идентичность данных на репликах.

Это необходимо для защиты от неисправностей оборудования (деградации битов на носителях данных, инверсии битов в оперативной памяти сервера, инверсии битов в оперативной памяти сетевого контроллера, инверсии битов в оперативной памяти сетевого коммутатора, инверсии битов в оперативной памяти клиента, инверсии битов при передаче по сети).
Обратите внимание, что инверсии битов — обычное явление и, скорее всего, будут происходить даже при использовании ECC-памяти и при наличии контрольных сумм TCP (если вы эксплуатируете тысячи серверов, ежедневно обрабатывающих PB данных).
[Смотрите видео (на русском)](https://www.youtube.com/watch?v=ooBAQIe0KlQ).

ClickHouse предоставляет средства диагностики, которые помогут инженерам по эксплуатации найти неисправное оборудование.

* и это не замедляет работу.

<div id="code-style">
  ## Стиль кода
</div>

Правила стиля кода описаны [здесь](/ru/resources/develop-contribute/contribute/style).

Чтобы проверить некоторые распространённые нарушения стиля, можно использовать скрипт `utils/check-style`.

Чтобы привести код к правильному стилю, можно использовать `clang-format`.
Файл `.clang-format` находится в корне исходников.
Он в целом соответствует нашему текущему стилю кода.
Но применять `clang-format` к существующим файлам не рекомендуется, поскольку это может ухудшить форматирование.
Вместо этого можно использовать инструмент `clang-format-diff`, который находится в репозитории с исходным кодом clang.

Кроме того, можно попробовать инструмент `uncrustify` для переформатирования кода.
Конфигурация находится в `uncrustify.cfg` в корне исходников.
Он протестирован меньше, чем `clang-format`.

У `CLion` есть собственный форматтер кода, который нужно настроить под наш стиль кода.

<div id="test-coverage">
  ## Покрытие тестов
</div>

Мы также отслеживаем покрытие тестов, но только для функциональных тестов и только для clickhouse-server.
Оно измеряется ежедневно.

<div id="tests-for-tests">
  ## Проверка самих тестов
</div>

Есть автоматическая проверка на нестабильные тесты.
Она запускает все новые тесты 100 раз (для функциональных тестов) или 10 раз (для интеграционных тестов).
Если тест не проходит хотя бы один раз, он считается нестабильным.

<div id="test-automation">
  ## Автоматизация тестирования
</div>

Мы запускаем тесты с помощью [GitHub Actions](https://github.com/features/actions).

Задачи сборки и тесты выполняются в песочнице для каждого коммита.
Полученные пакеты и результаты тестов публикуются на GitHub, откуда их можно скачать по прямым ссылкам.
Артефакты хранятся несколько месяцев.
Когда вы отправляете pull request на GitHub, мы помечаем его меткой "can be tested", и наша CI-система собирает для вас пакеты ClickHouse (release, debug, с AddressSanitizer и т. д.).
