32 KiB
slug | sidebar_position | sidebar_label | title | description |
---|---|---|---|---|
/ja/development/tests | 72 | テスト | ClickHouseのテスト | ほとんどのClickHouseの機能は機能テストでテスト可能であり、ClickHouseコードの変更には必ずこれを使用する必要があります。 |
機能テスト
機能テストは最も簡単で便利に使用できるものです。ほとんどのClickHouseの機能は機能テストでテストすることができ、そのようにテストできるClickHouseコードの変更には必ず使用することが求められます。
各機能テストは、実行中のClickHouseサーバーに対して一つまたは複数のクエリを送信し、結果を参照と比較します。
テストは queries
ディレクトリに配置されています。二つのサブディレクトリがあり、それぞれ stateless
と stateful
です。Statelessテストは、事前にロードしたテストデータなしでクエリを実行し、テスト内で小さな合成データセットを即席で作成することが多いです。Statefulテストは、ClickHouseから事前にロードされたテストデータを必要とし、一般公開されています。
各テストは .sql
または .sh
のどちらかの形式であり得ます。.sql
テストは clickhouse-client
にパイプされる単純なSQLスクリプトです。.sh
テストはそれ自体で実行されるスクリプトです。通常、SQLテストは .sh
テストよりも好まれます。.sh
テストは通常のSQLでは試せない機能(clickhouse-client
にデータをパイプしたり、clickhouse-local
をテストしたりする際など)のテストが必要な場合にのみ使用すべきです。
:::note
DateTime
および DateTime64
データ型をテストする際の一般的な誤りは、サーバーが特定のタイムゾーン(例:"UTC")を使用していると仮定することです。実際にはそうではなく、CIテスト実行時のタイムゾーンは意図的にランダム化されています。最も簡単な回避策は、テスト値にタイムゾーンを明示的に指定することです。例えば、toDateTime64(val, 3, 'Europe/Amsterdam')
などです。
:::
ローカルでテストを実行する
ClickHouseサーバーをデフォルトのポート(9000)でローカルで起動します。例えば、01428_hash_set_nan_key
テストを実行するには、リポジトリのフォルダに移動し次のコマンドを実行します:
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 substring
。また、テストを並行して実行したり、ランダムな順序で実行したりするオプションもあります。
新しいテストの追加
新しいテストを追加するには、queries/0_stateless
ディレクトリに .sql
または .sh
ファイルを作成し、手動で確認した後で次の方法で .reference
ファイルを生成します: clickhouse-client < 00000_test.sql > 00000_test.reference
または ./00000_test.sh > ./00000_test.reference
。
テストは、事前に作成されていると仮定される test
データベース内のテーブル(作成、削除など)を使用するのみで、また一時テーブルを使用することもできます。
テスト実行を制限する
テストには、テスト実行の制限を指定するために零個またはそれ以上の テストタグ を含めることができます。
.sh
テストのタグは、二行目にコメントとして記述します:
#!/usr/bin/env bash
# Tags: no-fasttest
.sql
テストのタグは、一行目にSQLコメントとして配置します:
-- Tags: no-fasttest
SELECT 1
タグ名 | 内容 | 使用例 |
---|---|---|
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 テーブルエンジンは高速テストで無効化されている |
no-[asan, tsan, msan, ubsan] |
サニタイザを使用するビルドでテストを無効化 | QEMUの下でのテストはサニタイザと動作しない |
no-replicated-database |
||
no-ordinary-database |
||
no-parallel |
他のテストと並行して実行されることを禁止 | テストは system テーブルから読み取られ、不変条件が破られる可能性がある |
no-parallel-replicas |
||
no-debug |
||
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 |
上記の設定に加えて、特定のClickHouse機能の使用を定義するために system.build_options
の USE_*
フラグを使用できます。
例えば、テストがMySQLテーブルを使用している場合は、use-mysql
タグを追加してください。
ランダム設定の限界を指定する
テストは、実行中にランダム化される設定について、最小および最大許容値を指定することができます。
.sh
テストの場合、限界はタグの次の行またはタグが指定されていない場合は二行目にコメントとして記述します:
#!/usr/bin/env bash
# Tags: no-fasttest
# Random settings limits: max_block_size=(1000, 10000); index_granularity=(100, None)
.sql
テストの場合、限界はタグの次の行または一行目にSQLコメントとして指定します:
-- Tags: no-fasttest
-- Random settings limits: max_block_size=(1000, 10000); index_granularity=(100, None)
SELECT 1
一つの限界のみを指定する場合は、もう一方に None
を使用できます。
テスト名の選び方
テスト名は、5桁の接頭辞に続く説明的な名前で開始します(例: 00422_hash_function_constexpr.sql
)。接頭辞を選ぶには、そのディレクトリで既に存在する最大の接頭辞を見つけ、それを1ずつ増やします。その間に、同じ数の接頭辞を持つ他のテストが追加されるかもしれませんが、それは問題ではなく、その後で変更する必要はありません。
発生すべきエラーの確認
時々、サーバーエラーが不正なクエリに対して発生するかテストしたいことがあります。このために、SQLテストで次の形式の特別なアノテーションをサポートしています:
select x; -- { serverError 49 }
このテストは、サーバーが未知のカラム x
に関するエラーコード49を返すことを保証します。エラーが発生しないか、別のエラーが発生した場合、テストは失敗します。クライアント側でエラーが発生することを確認したい場合は、clientError
アノテーションを使用してください。
エラーメッセージの具体的な表現の確認はしないでください。将来的に変更される可能性があり、テストが不必要に壊れます。エラーコードだけを確認してください。既存のエラーコードがあなたのニーズに十分に厳密でない場合、新しいエラーコードを追加することを検討してください。
分散クエリのテスト
機能テストで分散クエリを使用したい場合は、127.0.0.{1..2}
アドレスを使ってサーバーが自身をクエリする remote
テーブル関数を活用することができます。または、サーバー設定ファイルで事前に定義されたテストクラスター(例: test_shard_localhost
)を使用することができます。分散クエリをサポートするためにサーバーが正しく構成されているCI設定で実行されるよう、テスト名に shard
または distributed
という単語を追加してください。
一時ファイルの取り扱い
時にはシェルテストで、作業用に即席でファイルを作成する必要があるかもしれません。いくつかのCIチェックでは、テストが並行して実行されるため、一意ではない名前のファイルをスクリプト内で作成または削除すると、フレーク状のファイルなどのCIチェックが失敗する可能性があります。この問題を回避するため、環境変数 $CLICKHOUSE_TEST_UNIQUE_NAME
を使用して、実行中のテストに固有の名前を一時ファイルに付けるべきです。これにより、セットアップ時に作成したりクリーンアップ時に削除したりするファイルが、そのテストのみで使用中のファイルであり、並行して実行される他のテストではないことが確認できます。
既知のバグ
機能テストによって容易に再現できるバグが見つかっている場合、その準備された機能テストを tests/queries/bugs
ディレクトリに保存します。バグが修正された際には、これらのテストは tests/queries/0_stateless
に移動されます。
統合テスト
統合テストは、ClickHouseのクラスター構成でのテストや、ClickHouseがMySQL、Postgres、MongoDBなどの他のサーバーとどのように連携するかをテストすることを可能にします。これらはネットワーク分割やパケットドロップなどをエミュレートするのに役立ちます。これらのテストはDocker上で実行され、様々なソフトウェアを含む複数のコンテナを作成します。
これらのテストを実行する方法は tests/integration/README.md
を参照してください。
ClickHouseとサードパーティドライバの統合はテストされていないことに注意が必要です。また、現在、JDBCおよびODBCドライバとの統合テストはありません。
ユニットテスト
ユニットテストは、ClickHouse全体ではなく、単一の独立したライブラリやクラスをテストしたい場合に役立ちます。CMakeオプションの ENABLE_TESTS
でテストのビルドを有効または無効にすることができます。ユニットテスト(およびその他のテストプログラム)は、コード全体の tests
サブディレクトリにあります。ユニットテストを実行するには、ninja test
と入力します。一部のテストは gtest
を使用していますが、テストが失敗すると非ゼロの終了コードを返すプログラムもあります。
コードが既に機能テストでカバーされている場合、ユニットテストを持つ必要はありません(通常、機能テストは使用が非常に簡単です)。
個々のgtestチェックを実行するには、次のように実行ファイルを直接呼び出します:
$ ./src/unit_tests_dbms --gtest_filter=LocalAddress*
パフォーマンステスト
パフォーマンステストは、ClickHouseのある特定の部分のパフォーマンスを測定し、合成クエリで比較することができます。パフォーマンステストは tests/performance/
に配置されています。各テストはテストケースの説明を含む .xml
ファイルで表現されます。テストは docker/test/performance-comparison
ツールを使用して実行されます。起動方法はReadmeファイルで確認してください。
各テストは一つまたは複数のクエリをループで実行します(パラメータの組み合わせを伴う可能性があります)。
ClickHouseのパフォーマンスをあるシナリオで改善したい場合、そして改善が単純なクエリで観察されるのであれば、パフォーマンステストを書くことを強くお勧めします。また、比較的孤立しており、あまり複雑でないSQL関数を追加または変更する場合にも、パフォーマンステストを書くことを推奨します。テストの際には常に perf top
や他の perf
ツールを使用することが意味があります。
テストツールとスクリプト
tests
ディレクトリ内のいくつかのプログラムは準備されたテストではなく、テストツールです。例えば、Lexer
のために src/Parsers/tests/lexer
というツールがあり、これは標準入力のトークン化を行い、標準出力にカラー化された結果を書き出します。これらの種類のツールはコード例として、または検証や手動テストのために使用できます。
その他のテスト
tests/external_models
には機械学習モデルのテストがあります。これらのテストは更新されておらず、統合テストに移行する必要があります。
クォーラム挿入のための個別のテストがあります。このテストはClickHouseクラスターを別のサーバー上で実行し、いくつかの故障ケースをエミュレートします: ネットワーク分割、パケットドロップ(ClickHouseノード間、ClickHouseとZooKeeper間、ClickHouseサーバーとクライアント間など)、kill -9
、kill -STOP
、およびkill -CONT
などを、Jepsen のように。そして、すべての確認された挿入が記録され、すべて拒否された挿入が記録されていないことを確認します。
クォーラムテストは、ClickHouseがオープンソース化される前に別のチームによって書かれました。このチームは現在ClickHouseに関与していません。テストは誤ってJavaで書かれてしまいました。これらの理由から、クォーラムテストは書き直され、統合テストに移行されるべきです。
手動テスト
新しい機能を開発する際には、手動で機能をテストすることも合理的です。以下の手順でそれを行うことができます:
ClickHouseをビルドします。ターミナルからClickHouseを実行します: programs/clickhouse-server
ディレクトリに移動し、./clickhouse-server
で実行します。デフォルトで現在のディレクトリから設定ファイル(config.xml
、users.xml
、および config.d
と users.d
ディレクトリ内のファイル)を使用します。ClickHouseサーバーに接続するには、programs/clickhouse-client/clickhouse-client
を実行します。
すべてのclickhouseツール(サーバー、クライアントなど)は clickhouse
という単一のバイナリにリンクされているだけです。このバイナリは programs/clickhouse
にあります。すべてのツールは clickhouse tool
として、あるいは clickhouse-tool
として起動することができます。
別の方法として、ClickHouseパッケージをインストールすることもできます: ClickHouseリポジトリからの安定版リリースまたは./release
を使用して自分自身でビルドしたパッケージを入手可能です。サーバーを起動するには sudo clickhouse start
(またはサーバーを停止するには stop)を実行します。ログは /etc/clickhouse-server/clickhouse-server.log
にあります。
システムにすでにClickHouseがインストールされている場合、新しい clickhouse
バイナリをビルドし、既存のバイナリを置き換えることができます:
$ sudo clickhouse stop
$ sudo cp ./clickhouse /usr/bin/
$ sudo clickhouse start
またシステムのclickhouse-serverを停止し、同じ設定で独自のサーバーをターミナルでログを取りながら実行することもできます:
$ sudo clickhouse stop
$ sudo -u clickhouse /usr/bin/clickhouse server --config-file /etc/clickhouse-server/config.xml
gdbを使った例:
$ sudo -u clickhouse gdb --args /usr/bin/clickhouse server --config-file /etc/clickhouse-server/config.xml
システムのclickhouse-serverがすでに実行中であり、それを停止したくない場合、config.d
ディレクトリ内のファイルで上書きすることにより自分の config.xml
のポート番号を変更して適切なデータパスを提供し、実行できます。
clickhouse
バイナリはほとんど依存関係がなく、幅広いLinuxディストリビューションで動作します。サーバー上での変更を素早く確認したい場合、ビルドした clickhouse
バイナリをサーバーに scp
し、上記の例のようにそれを実行することができます。
ビルドテスト
ビルドテストを行うことで、異なる代替構成や一部の外国のシステムでビルドが壊れていないことを確認できます。これらのテストは自動化されています。
例:
- Darwin x86_64(macOS)用のクロスコンパイル
- FreeBSD x86_64用のクロスコンパイル
- Linux AArch64用のクロスコンパイル
- システムパッケージからのライブラリでUbuntu上でビルド(推奨されない)
- ライブラリの共有リンクでビルド(推奨されない)
例えば、システムパッケージからのビルドは悪い慣習です。なぜなら、システムが何のバージョンのパッケージを持つかを保証できないからです。しかし、これはDebianのメンテナによってどうしても必要とされます。このため、少なくともこのビルドのバリエーションをサポートする必要があります。別の例としては、共有リンクは一般的なトラブルの原因となりますが、一部の愛好家には必要です。
全てのビルドのバリエーションに全てのテストを実行することはできませんが、少なくとも様々なビルドバリエーションが壊れていないことは確認したいと考えています。この目的でビルドテストを使用します。
また、コンパイルするのに時間がかかるか、多くのRAMを必要とする翻訳単位がないこともテストします。
また、大きすぎるスタックフレームがないこともテストします。
プロトコル互換性のテスト
ClickHouseネットワークプロトコルを拡張する際には、古いclickhouse-clientが新しいclickhouse-serverと動作するか、新しいclickhouse-clientが古いclickhouse-serverと動作するかを手動でテストしています(対応するパッケージからのバイナリを実行することで確認)。
また、統合テストでいくつかのケースを自動的にテストしています:
- 古いバージョンのClickHouseによって書かれたデータが新しいバージョンで正しく読み取り可能であるかどうか。
- 異なるClickHouseバージョンが混在するクラスターで分散クエリが機能するかどうか。
コンパイラの支援
メインのClickHouseコード(dbms
ディレクトリにあるコード)は、-Wall -Wextra -Werror
およびいくつかの追加の警告が有効になってビルドされます。ただし、これらのオプションはサードパーティのライブラリには適用されていません。
Clangにはさらに多くの有用な警告があります - -Weverything
を使ってそれらを探し、デフォルトビルドに取り入れるものを選ぶことができます。
本番ビルドではclangが使用されますが、gccビルドもテストしています。開発では、clangを使用する方が通常は便利です。自分のマシンでデバッグモードでビルドする(ラップトップのバッテリーを節約するため)ことができますが、コンパイラは -O3
を使ってより良い制御フローおよび手続き間解析を行い、より多くの警告を生成することができることを注意してください。デバッグモードでclangを使用するとき、libc++
のデバッグバージョンが使用され、実行時により多くのエラーをキャッチできるようになります。
サニタイザ
:::note
ローカルで起動するときにプロセス(ClickHouseサーバーまたはクライアント)がクラッシュする場合は、アドレス空間レイアウトランダム化を無効にする必要があるかもしれません: sudo sysctl kernel.randomize_va_space=0
:::
アドレスサニタイザ
ASanの下での機能テスト、統合テスト、ストレステスト、およびユニットテストをコミットごとに実行しています。
スレッドサニタイザ
TSanの下での機能テスト、統合テスト、ストレステスト、およびユニットテストをコミットごとに実行しています。
メモリサニタイザ
MSanの下での機能テスト、統合テスト、ストレステスト、およびユニットテストをコミットごとに実行しています。
不定動作サニタイザ
UBSanの下での機能テスト、統合テスト、ストレステスト、およびユニットテストをコミットごとに実行しています。いくつかのサードパーティライブラリのコードはUBについてのサニタイジングがされていません。
Valgrind(Memcheck)
過去にはValgrindを使って夜間に機能テストを実行していましたが、今は行っていません。数時間かかります。現在、re2
ライブラリに既知の偽陽性が一つあります。詳細はこの記事を参照してください。
ファジング
ClickHouseのファジングは、libFuzzer とランダムSQLクエリの両方を使用して実装されています。 すべてのファジーテストはサニタイザ(アドレスおよび不定動作)を使用して実行するべきです。
LibFuzzerはライブラリコードの孤立したファジーテストに使用されます。ファジーはテストコードの一部として実装され、「_fuzzer」という名前の接尾辞が付けられます。
ファザーの例は src/Parsers/fuzzers/lexer_fuzzer.cpp
にあります。LibFuzzer固有の設定、Dictionary、およびコーパスは tests/fuzz
に保存されています。
ユーザー入力を処理するすべての機能に対してファジーテストを書くことを奨励します。
ファッザーはデフォルトでビルドされません。ファッザーをビルドするには -DENABLE_FUZZING=1
および -DENABLE_TESTS=1
オプションを設定する必要があります。
ジェマロックを無効にしてファジーテストをビルドすることをお勧めします。ClickHouseのファッジングをGoogleのOSS-Fuzzに統合するために使用される構成は docker/fuzz
にあります。
また、サーバーがそれらを実行するときに死なないことを確認するためにランダムSQLクエリを生成する単純なファジーテストも使用します。
00746_sql_fuzzy.pl
にあります。これは継続的に(夜間や長時間にわたって)実行されるべきテストです。
また、ASTベースの高度なクエリファザーを使用し、多くのコーナーケースを見つけることができます。これはクエリASTでランダムな置換を行います。テストの途中でそれらをランダムな順序で処理する際に、以前のテストからASTノードを記憶し、後続のテストのファジングにそれらを使用します。このファザーについての詳細はこのブログ記事で学ぶことができます。
ストレステスト
ストレステストはファジングの別のケースです。これは一つのサーバーでランダムな順序で並行してすべての機能テストを実行します。テスト結果は確認されません。
確認されること:
- サーバーがクラッシュしないこと、デバッグまたはサニタイザのトラップが発動されないこと
- デッドロックがないこと
- データベース構造が一貫していること
- テスト後にサーバーが正常に停止でき、例外なく再起動できること
デバッグ、ASan、TSan、MSan、UBSanの五つのバリエーションがあります。
スレッドファザー
スレッドサニタイザと混同しないでください。スレッドファザーはスレッドの実行順序をランダム化する別の種類のファジングです。それにより、さらに特別なケースを見つけることができます。
セキュリティ監査
セキュリティチームはClickHouseの能力について基本的な概要を行いました。
静的解析
clang-tidy
をコミットごとに実行しています。clang-static-analyzer
チェックも有効にしています。clang-tidy
は一部のスタイルチェックにも使用されています。
clang-tidy
、Coverity
、cppcheck
、PVS-Studio
、tscancode
、CodeQL
を評価しました。使用方法についての指示は tests/instructions/
ディレクトリにあります。
CLion
をIDEとして使用している場合、いくつかの clang-tidy
チェックをそのまま使用することができます。
また、shellcheck
をシェルスクリプトの静的解析に使用しております。
ハードニング
デバッグビルドでは、ユーザーレベルの割り当てのASLR(アドレス空間レイアウトランダム化)を行うカスタムアロケータを使用しています。
また、アロケーション後に読み取り専用であることが期待されるメモリ領域を手動で保護します。
デバッグビルドでは、古く、非推奨であるか、セキュリティ上問題があるか、スレッド安全でないとされる関数が呼び出されないことを保証するカスタマイズが施されています。
デバッグアサーションが広範に使用されています。
デバッグビルドでは、"論理エラー" コード(バグを含意)で例外がスローされる場合、プログラムは直ちに停止されます。これにより、リリースビルドでは例外を使用し、デバッグビルドではアサーションとして扱うことができます。
デバッグビルドではジェマロックのデバッグバージョンを使用しています。 デバッグビルドではlibc++のデバッグバージョンも使用しています。
実行時整合性チェック
ディスクに保存されたデータにはチェックサムが付けられています。MergeTreeテーブルのデータは3つの方法で同時にチェックサムされます(圧縮データブロック、非圧縮データブロック、ブロック間の総合チェックサム)。クライアントとサーバー間、またはサーバー間で転送されるデータもチェックサムされています。レプリケーションはレプリカ上のビット単位で同一のデータを保証します。
これは、故障したハードウェア(ストレージメディアのビット腐食、サーバーのRAMのビットフリップ、ネットワークコントローラのRAMのビットフリップ、ネットワークスイッチのRAMのビットフリップ、クライアントのRAMのビットフリップ、ワイヤ上のビットフリップ)から保護するために必要です。ビットフリップは一般的であり、ECC RAMでも、TCPチェックサムが存在していても発生する可能性があります(数千のサーバーが毎日ペタバイトのデータを処理すると管理する必要があることもあります)。動画を参照してください(ロシア語).
ClickHouseはopsエンジニアが故障したハードウェアを見つけるのに役立つ診断を提供します。
* そしてそれは遅くありません。
コードスタイル
コードスタイルのルールはここに記載されています。
一般的なスタイル違反をチェックするために、utils/check-style
スクリプトを使用することができます。
コードの適切なスタイルを強制するために、clang-format
を使用することができます。.clang-format
ファイルはソースのルートにあります。これは私たちの実際のコードスタイルと主に一致しています。しかし、既存のファイルに clang-format
を適用することは推奨されません。フォーマットが悪くなるからです。clangソースリポジトリにある clang-format-diff
ツールを使用することができます。
また、uncrustify
ツールを試してコードを再フォーマットすることができます。設定はソースのルートにある uncrustify.cfg
にあります。clang-format
よりもテストされていない部分があります。
CLion
には独自のコードフォーマッタがあり、私たちのコードスタイルに合わせて調整する必要があります。
また、codespell
を使用してコード内のスペルミスを見つけます。これは自動化されています。
テストカバレッジ
機能テストのみでテストカバレッジを追跡していますが、clickhouse-serverのみです。これは日次で実行されます。
テストのためのテスト
不安定なテスト用の自動チェックがあります。すべての新しいテストを100回(機能テストの場合)または10回(統合テストの場合)実行します。少なくとも一回でもテストが失敗した場合、それはフレーク状とみなされます。
テストの自動化
テストはGitHub Actionsを利用して実行されます。
ビルドジョブとテストはコミットごとにSandboxで実行されます。生成されたパッケージとテスト結果はGitHubに公開され、直接リンクでダウンロードすることができます。成果物は数か月間保存されます。GitHubでプルリクエストを送信すると、それは「テスト可能」とタグ付けされ、CIシステムがClickHouseパッケージ(リリース、デバッグ、アドレスサニタイザ付)をビルドしてくれます。
時間と計算力に制限があるため、Travis CIは使用していません。 Jenkinsは使用していません。それはかつて使用されていましたが、現在は使用していないことに満足しています。