- マージリクエストが承認される前の予測テストジョブ
- マージリクエストパイプラインにおけるフェイルファストジョブ
- マージリクエストパイプラインで、以前に失敗したテストを再実行します。
- 列車のマージ
- いくつかのマージリクエストに対するフィードバックの高速化
- テストジョブ
- テストスイートの並列化
- Flakyなテスト
- 互換性テスト
- モニタリング
- 伐採
- マージリクエストのパイプラインタイプ
- CI設定内部
- パフォーマンス
GitLabプロジェクトのパイプライン
gitlab-org/gitlab
(dev
のインスタンスと同様) のパイプラインは、通常の.gitlab-ci.yml
で設定します。 には、メンテナンスしやすいように.gitlab/ci/
のファイルが含まれています。
私たちは GitLabCI/CD の機能とベストプラクティスをできる限りドッグフード化しようと努力しています。
マージリクエストが承認される前の予測テストジョブ
パイプラインのコストを削減し、ジョブ期間を短縮するために、マージリクエストが承認される前に、パイプラインはマージリクエストの変更に対して失敗する可能性の高い RSpec & Jest テストを予測的に実行します。
マージリクエストが承認された後、パイプラインには完全な RSpec & Jest テストがコンテナされます。これにより、マージリクエストがマージされる前に、すべてのテストが実行されるようになります。
GitLab プロジェクトのテスト依存関係の概要
予測テストジョブがどのように実行されるかを理解するためには、GitLabのコード(フロントエンドとバックエンド)とそれぞれのテスト(JestとRSpec)の依存関係を理解する必要があります。この依存関係は以下の図で可視化できます:
まとめると
- RSpec のテストはバックエンドのコードに依存します。
- Jest テストはフロントエンドとバックエンドの両方のコードに依存し、 後者はフロントエンドのフィクスチャに依存します。
予測テストのダッシュボード
- https://app.periscopedata.com/app/gitlab/1116767/Test-Intelligence-Accuracy
- https://app.periscopedata.com/app/gitlab/899368/EP---Predictive-testing-analysis
detect-tests
CIジョブ
gitlab-org/gitlab
の CI/CD パイプラインのほとんどはprepare
ステージでdetect-tests
CI ジョブ を実行し、与えられた MR で変更されたファイルに基づいてどのバックエンド/フロントエンドのテストを実行すべきかを検出します。
detect-tests
ジョブは、実行すべきバックエンド/フロントエンドテストを含む多くのファイルを作成します。これらのファイルはパイプラインの後続のジョブで読み込まれ、それらのテストのみが実行されます。
RSpec 予測ジョブ
マージリクエストでの RSpec テストファイルの予測決定
マージリクエストで失敗しそうな RSpec テストを特定するために、静的マッピングと 動的マッピングを使用します。
静的マッピング
カバレッジトレースでマッピングできない特殊なケースのために、tests.yml
ファイル に静的マッピングをメンテナーとして保持し、test_file_finder
gem を使用しています(使用箇所を参照)。
テストマッピングには、各ソースファイルと、ソースファイルに依存するテストファイルのリストとのマッピングがコンテナで格納されています。
動的マッピング
まず、test_file_finder
gem を使って、テストカバレッジトレース(Crystalball
gem を使って生成)から動的なマッピングを行います(どこで使われているか参照)。
test_file_finder
に加えて、さらに多くのテストを検出するための高度なマッピングをいくつか追加しました:
-
FindChanges
(!74003)- バックエンドの変更時に実行される Jest テストを自動的に検出します (フロントエンドのフィクスチャ経由で)。
-
PartialToViewsMappings
(#395016)- ビューに含まれるRailsパーシャルがMRで変更されたときにビュー仕様を実行
-
JsToSystemSpecsMappings
(#386754)- MRでJavaScriptファイルが変更された場合、特定のシステム仕様を実行します。
-
GraphqlBaseTypeMappings
(#386756)- ある GraphQL タイプのクラスが変更された場合、このタイプを含む可能性のある他の GraphQL タイプを特定し、その仕様を実行するようにします。
-
ViewToSystemSpecsMappings
(#395017)- ビューが変更されたとき、私たちはコードのその領域をテストする機能仕様を見つけようとします。
-
ViewToJsMappings
(#386719)- JSファイルが変更された場合、そのJSコンポーネントをカバーしているシステム仕様を特定するようにすべきです。
-
FindFilesUsingFeatureFlags
(#407366)- 機能フラグが変更された場合、どのRubyファイルがその機能フラグを含んでいるかをチェックし、detect-tests CIジョブの変更ファイルリストに追加します。残りのジョブは、変更されたファイルに基づいてどのフロントエンド/バックエンドのテストを実行すべきかを検出します。
例外的なケース
さらに、常に完全な RSpec テストを実行するような状況もいくつかあります:
- マージリクエストに
pipeline:run-all-rspec
ラベルが設定されている場合。このラベルは、as-if-foss
ジョブで実行されるテストを含む、すべての RSpec テストをトリガーします。 - マージリクエストに
pipeline:mr-approved
ラベルが設定され、コード変更がbackend-patterns
ルールを満たす場合。このラベルは、マージ リクエストがいずれかのレビュアーによって承認されたときに、トリアージ オートメーションによって割り当てられることに注意してください。このラベルを手動で適用することはお勧めしません。 - マージリクエストが自動化によって作成された場合 (たとえば、Gitaly アップデートや 安定版ブランチを対象とした MR など)
- マージリクエストがセキュリティミラーで作成された場合。
- CI 設定ファイルが変更されたとき (たとえば、
.gitlab-ci.yml
や.gitlab/ci/**/*
)
バックエンドの予測テストで問題が発生しましたか?
もしそうであれば、予測テストの問題に対処する方法について、予測テストに関するエンジニアリング生産性RUNBOOKをご覧ください。さらに、テスト選択のギャップを発見された場合は、@gl-quality/eng-prod
までお知らせください。そうすれば、テスト選択を最適化するために必要な措置を講じることができます。
Jest 予測ジョブ
マージリクエストでの予測 Jest テストファイルの決定
マージリクエストで失敗しそうな Jest テストを特定するために、--findRelatedTests
オプションを使用してjest
に変更されたファイルの一覧を渡します。このモードでは、jest
は変更されたファイルに関連するすべての依存関係を解決します。この依存関係には、これらのファイルを依存関係の鎖に持つテストファイルが含まれます。
例外的なケース
さらに、常に Jest テストを実行するような状況もいくつかあります:
- マージリクエストに
pipeline:run-all-jest
ラベルが設定されたとき - マージリクエストが自動化によって作成された場合 (たとえば、Gitaly アップデートや 安定版ブランチを対象とした MR など)
- マージリクエストがセキュリティミラーで作成された場合。
- 関連する CI 設定ファイルが変更されたとき (
.gitlab/ci/rules.gitlab-ci.yml
,.gitlab/ci/frontend.gitlab-ci.yml
) - フロントエンドの依存ファイルが変更されたとき (例:
package.json
,yarn.lock
,config/webpack.config.js
,config/helpers/**/*.js
) - ベンダーのJavaScriptファイルが変更されたとき (例:
vendor/assets/javascripts/**/*
)
完全な Jest テストのためのrules
定義は.frontend:rules:jest
のrules.gitlab-ci.yml
で定義されています。
フロントエンドの予測テストで問題が発生しましたか?
もしそうであれば、予測テストの問題に対処する方法について、予測テストに関するエンジニアリング生産性RUNBOOKをご覧ください。
フォークパイプライン
MRにpipeline:run-all-rspec
ラベルが設定されていない限り、フォークパイプラインの予測RSpec & Jestジョブのみを実行します。目的は、フォークパイプラインで消費される計算クォータを削減することです。
実験イシューを参照してください。
マージリクエストパイプラインにおけるフェイルファストジョブ
マージリクエストが既存のテストを破壊した場合に、より迅速なフィードバックを提供するために、fail-fast メカニズムを実装しました。
rspec fail-fast
ジョブは、マージリクエストパイプラインの他のすべてのrspec
ジョブと並行して追加されます。このジョブはマージリクエストの変更に直接関係するテストを実行します。
これらのテストのいずれかが失敗した場合、rspec fail-fast
ジョブは失敗し、fail-pipeline-early
ジョブの実行を fail-pipeline-early
トリガーします。fail-pipeline-early
ジョブは fail-pipeline-early
- 現在実行中のパイプラインと進行中のすべてのジョブをキャンセルします。
- パイプラインのステータスを
failed
に設定します。
使用例:
rspec fail-fast
マージリクエストに関連するテストファイルが 10 個以上 rspec fail-fast
ある場合、このオプションはrspec fail-fast
使用できません rspec fail-fast
。rspec fail-fast
これは rspec fail-fast
、期間が平均rspec
ジョブ期間を超え、その目的が達成されなくなることを防ぎます。
この数値はRSPEC_FAIL_FAST_TEST_FILE_COUNT_THRESHOLD
という名前の CI/CD 変数を設定することでオーバーライドできます。
マージリクエストパイプラインで、以前に失敗したテストを再実行します。
マージリクエストで失敗したテストを解決した後のフィードバック時間を短縮するために、rspec rspec-pg14-rerun-previous-failed-tests
およびrspec rspec-ee-pg14-rerun-previous-failed-tests
ジョブは、以前の MR パイプラインから失敗したテストを実行します。
これは 2021 年 8 月 25 日にhttps://gitlab.com/gitlab-org/gitlab/-/merge_requests/69053で導入されました。
どのように機能するのですか?
-
detect-previous-failed-tests
ジョブ (prepare
ステージ) は、前の MR パイプラインで失敗した RSpec ジョブに関連するテストファイルを検出します。 -
rspec rspec-pg14-rerun-previous-failed-tests
とrspec rspec-ee-pg14-rerun-previous-failed-tests
ジョブはdetect-previous-failed-tests
ジョブによって収集されたテストファイルを実行します。
列車のマージ
マージトレインを有効にするには、なぜ “stable” master ブランチが必要なのですか?
マスターブランチが不安定な場合 (つまり、マスターブランチの CI/CD パイプラインが頻繁に失敗する場合)、失敗したマージリクエストパイプラインの後に追加されたすべてのマージリクエストパイプラインをキャンセルして 列車に追加し直さなければなりません。
マージトレインを有効にするために、masterブランチはどれくらい安定していなければならないのでしょうか?
具体的な数値はありませんが、テストの失敗やインフラストラクチャの障害については、よりよい数値が必要です (master Broken Incidents RCA Dashboard を参照ください)。
CI/CDの設定で、徐々にマージトレインに移行できないでしょうか?
あるコントリビューターからの提案がありましたが、このアプローチにはいくつかの欠点があります。
いくつかのマージリクエストに対するフィードバックの高速化
壊れたマスターの修正
壊れたmaster
を修正する必要がある場合、pipeline:expedite
ラベルを追加することで、マージリクエストで実行されるパイプラインを高速化することができます。
マージリクエストにはmaster:broken
またはmaster:foss-broken
ラベルが設定されている必要があることに注意してください。
MRの復帰
MR の差し戻しを高速化するには、マージリクエストを作成する前に MR の差し戻しテンプレートを使用してください。これにより、pipeline:expedite
ラベルや、マージリクエストで実行されるパイプラインを高速化するその他の機能が適用されます。
pipeline:expedite
ラベル
このラベルが割り当てられると、CI/CDパイプラインの以下のステップがスキップされます:
-
e2e:package-and-test
ジョブ。 -
rspec:undercoverage
ジョブ。 - レビューアプリの全プロセス。
ラベルをマージリクエストに適用し、MRの新しいパイプラインを実行します。
テストジョブ
各テストレベル専用のジョブがあり、各ジョブはマージリクエストで行った変更に応じて実行されます。変更に関係なくすべての RSpec ジョブを強制的に実行したい場合は、マージリクエストにpipeline:run-all-rspec
ラベルを追加します。
エンド・ツー・エンドのジョブ
e2e:package-and-test
子パイプラインは、変更に応じて自動的にエンドツーエンドジョブを実行し、それ以外の場合は手動で実行します。具体的なルールの一覧はrules.gitlab-ci.yml
の.qa:rules:package-and-test
を参照してください。
変更に関係なくe2e:package-and-test
を強制的に実行させたい場合は、マージリクエストにpipeline:run-all-e2e
ラベルを追加します。
詳細はエンドツーエンドテスト専用ページを参照してください。
アプリジョブのレビュー
start-review-app-pipeline
子パイプラインはレビューアプリをデプロイし、それに対してエンドツーエンドのテストを変更に応じて自動的に実行します。ルールの具体的な一覧はrules.gitlab-ci.yml
の.review:rules:start-review-app-pipeline
を参照してください。
あなたの変更に関係なくレビューアプリを強制的にデプロイしたい場合は、マージリクエストにpipeline:run-review-app
ラベルを追加します。
詳しくはレビューアプリ専用ページをご覧ください。
As-if-FOSSのジョブ
* as-if-foss
ジョブは GitLab テストスイートを「あたかも FOSS であるかのように」実行します。つまり、ジョブはgitlab-org/gitlab-foss
のコンテキストで実行されるかのように実行されます。これらのジョブは以下の場合にのみ作成されます:
- マージリクエストに
pipeline:run-as-if-foss
ラベルが設定されたとき -
gitlab-org/security/gitlab
プロジェクトでマージリクエストが作成されたとき。 - CI 設定ファイルが変更されたとき (たとえば、
.gitlab-ci.yml
や.gitlab/ci/**/*
)
* as-if-foss
ジョブは、通常の EE-context ジョブに追加して実行されます。これらのジョブはFOSS_ONLY='1'
変数が設定され、テストが実行される前にee/
フォルダが削除されます。
これは、gitlab-org/gitlab
がgitlab-org/gitlab-foss
に同期された後に、変更によって障害が発生しないようにするためです。
As-if-JH クロスプロジェクト・ダウンストリーム・パイプライン
内容
このパイプラインはJiHuバリデーションパイプラインとも呼ばれ、現在失敗することが許されています。その場合は、検証パイプラインが失敗したときの対処法に従ってください。
実行方法
start-as-if-jh
ジョブは、”as if JiHu”、つまりGitLab JH のコンテキストでパイプラインが実行されるかのように GitLab テストスイートを実行するクロスプロジェクトダウンストリームパイプラインをトリガーします。これらのジョブは以下の場合にのみ作成されます:
- 機能フラグに変更が加えられたとき
- マージリクエストに
pipeline:run-as-if-jh
ラベルが設定されたとき
このパイプラインは、GitLab JHのミラーである検証プロジェクトの生成ブランチのコンテキストで実行されます。
生成ブランチ名には、マージリクエストのブランチ名とともにas-if-jh/
が先頭に付きます。この生成ブランチはマージリクエストブランチをベースに、対応する JH ブランチからダウンロードした変更を追加し、パイプライン全体を JiHu のようにします。
この意図は、GitLabが GitLab JHに同期された後、変更によって障害が発生しないようにすることです。
pipeline:run-as-if-jh
ラベルの適用を検討するタイミング
Rubyファイルの名前が変更され、それに対応するprepend_mod
行がある場合、GitLab JHがそれに依存している可能性があり、前置するモジュールやクラスの名前を変更する必要があります。
対応する JH ブランチ
ブランチ名に-jh
を追加することで、GitLab JHに対応する JH ブランチを作成できます。対応する JH ブランチが見つかった場合、as-if-jh パイプラインはデフォルトのブランチmain-jh
ではなく、対応するブランチからファイルを取得します。
as-if-JHパイプラインの設定方法
全体のプロセスは次のようになります:
sync-as-if-jh-branch
を実行するのは、依存関係に変更があったときだけです。プロジェクト変数に設定されたトークン
-
ADD_JH_FILES_TOKEN
:JiHuファイルをダウンロードできるようにするための、read_api
権限を持つGitLab JHミラープロジェクトトークンです。 -
AS_IF_JH_TOKEN
:生成されたas-if-jh/*
ブランチをプッシュするための、write_repository
権限を持つGitLab JH 検証プロジェクトトークンです。
as-if-JHブランチの生成方法
最初のadd-jh-files
ジョブは、対応する JH ブランチから必要な JiHu ファイルをダウンロードし、アーティファクトに保存します。次のprepare-as-if-jh-branch
ジョブは、マージリクエストブランチから新しいブランチを作成し、変更をコミットして、最後にそのブランチを検証プロジェクトにプッシュします。
オプションとして、マージリクエストに依存関係の変更がある場合、sync-as-if-jh-branch
ジョブを実行し、検証プロジェクトのas-if-jh-code-sync
ブランチ でダウンストリームパイプラインをトリガーするステップを追加します。このジョブはJiHuのcode-syncと同じ処理を行い、検証パイプラインを実行する前に依存関係の変更がas-if-jhブランチに反映されるようにします。
依存関係の変更がない場合は、この処理を実行しません。
as-if-JHパイプラインのトリガーと実行方法
as-if-jh/*
ブランチを準備し、オプションで同期させた後、start-as-if-jh
ジョブは検証プロジェクトのパイプラインをトリガーし、プロジェクト横断のダウンストリームパイプラインを実行します。
GitLab JHミラープロジェクトのセットアップ方法
GitLab JH ミラープロジェクトは非公開で、CI は無効です。
GitLab JH からプルミラーを作成し、すべてのブランチをミラーし、分岐した参照元を上書きし、ミラーが更新されたときにパイプラインをトリガーしません。
プルしているユーザーは@gitlab-jh-bot
で、プロジェクトのメンテナーです。認証情報は 1password のエンジニアリング保管庫にあります。
GitLab JH は公開プロジェクトなので、ミラーリングのパスワードは使用しません。
GitLab JH検証プロジェクトの設定方法
このGitLab JH検証プロジェクトは公開され、CIが有効になっており、一時的なプロジェクト変数が設定されています。
GitLab JH ミラーからプルミラーを作成し、特定のブランチをミラーしています:(master|main-jh)
ミラーが更新されたときにパイプラインは発生しません。
プルユーザーは@gitlab-jh-validation-bot
で、プロジェクトのメンテナーであり、GitLab JH ミラーのレポーターでもあります。認証情報は 1password エンジニアリング保管庫にあります。
GitLab JH ミラーから変更をプルするためのパスワードとして、write_repository
権限を持つ@gitlab-jh-validation-bot
からの個人アクセストークンが使われます。ユーザー名はgitlab-jh-validation-bot
で設定します。
また、メンテナンスパイプラインを実行するパイプラインスケジュールがあり、変数SCHEDULE_TYPE
をmaintenance
に設定して毎日実行し、キャッシュを更新します。
デフォルトの CI/CD 設定ファイルもjh/.gitlab-ci.yml
に設定されているので、GitLab JH と全く同じように実行されます。
さらに、特別なブランチas-if-jh-code-sync
が設定され、保護されています。メンテナーはこのブランチをプッシュでき、開発者はマージできます。開発者がマージできるように設定する必要があるのは、このブランチでパイプラインをトリガーできるようにする必要があるからです。これは、開発者レベルのユーザーが保護されたブランチでパイプラインを実行できなくなるのを解決する前の妥協案です。
これは、マージリクエストによって依存関係が変更された場合に、sync-as-if-jh-branch
を実行して依存関係を同期させるために使用します。as-if-JH ブランチの生成方法をご覧ください。
GitLab JH 検証プロジェクトの一時変数
-
BUNDLER_CHECKSUM_VERIFICATION_OPT_IN
に設定されています。false
- JiHuが
jh/Gemfile.checksum
、この変数を削除することができます。より詳しい説明はfalse
に設定するとスキップできます。
- JiHuが
なぜミラープロジェクトと検証プロジェクトの両方があるのですか?
プロジェクトを分けているのにはいくつかの理由があります。
- セキュリティです:以前はミラープロジェクトだけを持っていました。しかし、セキュリティのイシューを完全に軽減するために、ミラープロジェクトを非公開にする必要がありました。
-
分離:JHコードを完全に分離されたスタンドアロンのプロジェクトで実行したいのです。ミラープロジェクトがある
gitlab-org
グループのもとで実行すべきではありません。検証プロジェクトは完全に分離されています。 - コスト:マージリクエストのたびにJiHuLab.comに接続したくありません。JiHuLab.comのコードをGitLab.comのどこかにミラーリングして、マージリクエストはそこからコードを取得するほうがコスト効率がよいのです。これは、検証プロジェクトがJiHuLab.comからではなくミラーからコードを取得できることを意味します。ミラープロジェクトは定期的に JiHuLab.com からコードを取得します。
-
ブランチの分離/セキュリティ/効率:JiHuLab.comから対応するJHブランチをフェッチできるように、すべてのブランチをミラーしたいです。しかし、検証プロジェクトの
as-if-jh-code-sync
ブランチは上書きしたくありません。検証パイプラインを制御するために使用しており、AS_IF_JH_TOKEN
へのアクセス権を持っているからです。 しかし、1 つのブランチを除いてすべてのブランチをミラーすることはできません。詳しくはこのイシューをご覧ください。このイシューを考慮して、検証プロジェクトは
master
とmain-jh
のみをミラーするように設定されています。技術的にはこれらのブランチは必要ないのですが、すべてのデフォルトブランチでリポジトリを最新に保ちたいので、マージリクエストからの変更をプッシュするときに、マージリクエストからの変更だけをプッシュすればよくなり、効率がよくなります。 - 懸念の分離:
- 検証プロジェクトには以下のブランチしかありません:
-
master
とmain-jh
で変更を最新に保つことができます。 -
as-if-jh-code-sync
依存関係の同期のためです。これをミラーリングすべきではありません。 -
as-if-jh/*
マージリクエストからのブランチ。これらをミラーすべきではありません。
-
- ミラープロジェクトからのブランチはすべてJiHuLab.comからのものです。ミラープロジェクトには何もプッシュしませんし、パイプラインも実行しません。ミラープロジェクトではCI/CDは無効です。
- 検証プロジェクトには以下のブランチしかありません:
セットアップとプロセスを簡素化するために2つのプロジェクトをマージすることを検討することはできますが、これらのすべての理由がもはや懸念事項ではないことを確認する必要があります。
rspec:undercoverage
ジョブ
GitLab 14.6で導入されました。
rspec:undercoverage
ジョブはundercover
を実行し、マージリクエストで導入された変更のカバレッジがゼロの場合に失敗します。
rspec:undercoverage
ジョブはrspec:coverage
ジョブからカバレッジデータを取得します。
CEメソッドがEEでオーバーライドされたためにrspec:undercoverage
ジョブがカバレッジ不足を検出した場合は、マージリクエストにpipeline:run-as-if-foss
ラベルを追加し、新しいパイプラインを開始します。
緊急のイベント、またはこのジョブによる偽陽性の場合は、pipeline:skip-undercoverage
ラベルをマージリクエストに追加して、このジョブが失敗するようにします。
rspec:undercoverage
失敗のトラブルシューティング
rspec:undercoverage
のジョブには、偽陽性の失敗を引き起こす既知のバグがあります。pipeline:skip-undercoverage
を適用しても安全かどうかを判断するために、カバレッジを内部でテストすることができます。たとえば、<spec>
を失敗の原因となるテストの名前として使います:
-
SIMPLECOV=1 bundle exec rspec <spec>
を実行してください。 -
scripts/undercoverage
を実行してください。
これらのコマンドがundercover: ✅ No coverage is missing in latest changes
を返した場合、pipeline:skip-undercoverage
を適用してパイプラインの障害を回避することができます。
テストスイートの並列化
現在のRSpecテストの並列化設定は以下の通りです:
-
prepare
ステージのretrieve-tests-metadata
ジョブは、knapsack/report-master.json
ファイルがあることを保証します:-
knapsack/report-master.json
ファイルは、update-tests-metadata
を実行する最新のmain
パイプライン(今のところ、2 時間ごとにスケジュールされたmaintenance
マスターパイプラインです)からフェッチされます。ここにない場合は、{}
でファイルを初期化します。
-
- 各
[rspec|rspec-ee] [migration|unit|integration|system|geo] n m
ジョブはknapsack rspec
と共に実行され、テストのシェアは均等になるはずです:- ジョブが
knapsack/report-master.json
にアクセスできるのは、「デフォルトで前のステージのアーティファクトがすべて渡される」からです。 - ジョブは独自のレポートパスを
"knapsack/${TEST_TOOL}_${TEST_LEVEL}_${DATABASE}_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json"
に設定します。 - knapsack がそのジョブを実行している場合、実行されたテストファイルは
Leftover specs
の下ではなくReport specs
の下にリストされるはずです。
- ジョブが
-
update-tests-metadata
ジョブ(canonicalプロジェクトのスケジュールされたパイプラインでのみ実行されます)は、knapsack/rspec*.json
ファイルをすべて受け取り、それらをマージして、アーティファクトとして保存されるknapsack/report-master.json
ファイルにまとめます。
その後、次のパイプラインは最新のknapsack/report-master.json
。
Flakyなテスト
欠陥テストの自動スキップ
以前は、flaky であることが判明しているテストをスキップしていましたが、master
が実際に壊れる可能性があるため、それをやめました。その代わりに、#master-broken
のインシデントでレポーターが報告した欠陥のあるテストを積極的に隔離するために、高速な隔離プロセスを導入しました。
この高速検疫プロセスは、$FAST_QUARANTINE
変数をfalse
に設定することで 無効にすることができます。
失敗したテストを別プロセスで自動再試行
$RETRY_FAILED_TESTS_IN_NEW_PROCESS
変数にfalse
( デフォルトではtrue
) を設定しない限り、失敗した RSpec テストは自動的に別の RSpec プロセスで再試行されます。その目的は、テストに失敗した際に発生する可能性のある、以前のテストによる副作用のほとんどを取り除くことです。
再試行されたテストは、rspec:flaky-tests-report
ジョブによってアーティファクトとして保存された$RETRIED_TESTS_REPORT_FILE
ファイルに記録されます。
実験イシューを参照してください。
互換性テスト
デフォルトでは、GitLab.com上で動作するバージョンですべてのテストを実行します。
その他のバージョン(通常、下位互換バージョンと上位互換バージョン)は、毎晩スケジュールされるパイプラインで実行されるはずです。
この一般的なガイドラインに対する例外は、動機付けされ、文書化されるべきです。
Rubyのバージョンテスト
私たちは GitLab.com 上で Ruby 3.0 を動かしています。マージリクエストやデフォルトブランチでも Ruby 3.0 を動かしています。次のリリースであるRuby 3.1に備えて、Ruby 3.1に対するテストスイートも専用の2時間ごとのパイプラインで実行しています。
マージリクエストの場合は、pipeline:run-in-ruby3_1
というラベルを追加することで、テストスイート全体の実行に使う Ruby のバージョンを 3.1 に切り替えることができます。これを行うと、テストスイートは Ruby 3.0 (デフォルト) では実行されなくなり、verify-ruby-3.0
という追加のジョブも実行され、マージリクエストをマージする前にラベルを削除して Ruby 3.0 で実行するように常に通知されます。
これで
- Ruby 3.1のテスト変更
- デフォルトブランチにマージしても何も壊れないことを確認
PostgreSQLバージョンのテスト
GitLab.comはPostgreSQL 14で動作しており、Omnibusは新規インストールとアップグレードのデフォルトをPG14に設定しているため、私たちのテストスイートはPostgreSQL 14で動作しています。
PostgreSQL 14 に対するテストスイートは、毎晩スケジュールされたパイプラインで実行しています。
また、PostgreSQL 12とPostgreSQL 13に対しても、マージリクエストとmain
パイプライン(rspec db-library-code pg12
とrspec db-library-code pg13
ジョブを使用)で特定のデータベースライブラリの変更時にテストスイートを実行しています。
現在のバージョンのテスト
どこで? | PostgreSQLのバージョン | Rubyバージョン |
---|---|---|
マージリクエスト | 14 (デフォルトバージョン)、13 (DB ライブラリの変更) | 3.0(デフォルト・バージョン) |
master ブランチコミット | 14 (デフォルトバージョン)、13 (DB ライブラリの変更) | 3.0(デフォルト・バージョン) |
maintenance master ブランチのパイプラインをスケジュール (偶数時間ごと) | 14 (デフォルトバージョン)、13 (DB ライブラリの変更) | 3.0(デフォルト・バージョン) |
maintenance ruby3_1 ブランチのパイプラインをスケジュール(奇数時間ごと)。 | 14 (デフォルトバージョン)、13 (DB ライブラリの変更) | 3.1 |
nightly master ブランチのパイプラインをスケジュールしました。 | 14 (デフォルトバージョン), 12, 13, 15 | 3.0(デフォルト・バージョン) |
Ruby 3.1のテストには2つのパイプラインスケジュールがあります。ひとつはruby3_1-sync
ブランチでパイプラインを起動し、ruby3_1
ブランチを最新のmaster
で更新します。もうひとつのスケジュールは、ruby3_1
ブランチの 5 分後にパイプラインを起動するもので、これはテストスイートの実行とキャッシュの更新を行うメンテナンススケジュールとみなされます。
ruby3_1
ブランチには変更があってはなりません。ブランチは、メンテナンスパイプラインスケジュールでRUBY_VERSION
を3.1
に設定するためだけに存在します。
ruby3_1-sync
ブランチのgitlab
ジョブは、write_repository
スコープとMaintainer
ロール付きのgitlab-org/gitlab
プロジェクトトークンを使用します。トークンはgitlab-org/gitlab
のRUBY3_1_SYNC_TOKEN
変数に格納されます。
Redisのバージョンテスト
GitLab.comはRedis 6で動作しており、Omnibusの新規インストールやアップグレードのデフォルトもRedis 6になっています。
nightly
のスケジュールパイプライン、特に PostgreSQL 15 の前方互換ジョブを実行するときには、Redis 7 に対してテストスイートを実行します。
現在のバージョンのテスト
どこで? | Redisのバージョン |
---|---|
MRs | 6 |
default branch (非定期パイプライン) | 6 |
nightly 定期パイプライン | 7 |
単一データベースのテスト
デフォルトでは、すべてのテストは複数のデータベースで実行されます。
また、夜間にスケジュールされるパイプラインや、データベース関連のファイルに触れるマージリクエストでも、単一のデータベースでテストを実行します。
単一データベースのテストは、2 つのモードで実行されます:
-
一つの接続で一つのデータベース。GitLabが1つの接続プールを使ってすべてのテーブルに接続します。で終わるすべてのジョブを実行します。
-single-db
-
2つの接続を持つ単一のデータベース。GitLabが異なるデータベース接続を使って
gitlab_main
,gitlab_ci
データベースのテーブルに接続する場合。これは、-single-db-ci-connection
で終わるすべてのジョブを実行します。
単一のデータベースでテストを実行させたい場合は、マージリクエストにpipeline:run-single-db
というラベルを追加します。
モニタリング
GitLabテストスイートはmain
ブランチと、名前にrspec-profile
を含むブランチを監視しています。
伐採
- Railsのロギングはパフォーマンス上の理由から、CIではデフォルトで
log/test.log
。この設定を無効にするには、RAILS_ENABLE_TEST_LOG
環境変数を指定します。
マージリクエストのパイプラインタイプ
一般的に、MRのパイプラインは、MRで行われた変更に応じて、以下のタイプ(短いものから長いものまで)のいずれかに分類されます:
- ドキュメンテーション・パイプライン:ドキュメントに触れる MR の場合。
- バックエンドパイプライン:バックエンドのコードに触れるMR向け。
- レビューアプリパイプライン:フロントエンドのコードに触れるMR向け。
-
エンドツーエンドのパイプライン:
qa/
フォルダ内のコードに触れる MR。
パイプライン・タイプ」は抽象的な用語で、主に「クリティカル・パス」(例えば、個々の継続時間の合計がパイプラインの継続時間と等しくなるジョブの連鎖)を表します。私たちはメトリクス・ダッシュボードでこれらの「パイプライン・タイプ」を使用して、最初に最適化する必要があるタイプやジョブを検出します。
複数の領域に接触する MR は、該当する最も長いタイプに関連付けられます。例えば、バックエンドとフロントエンドに触れるMRは、”バックエンド “パイプラインタイプよりも終了に時間がかかるため、”フロントエンド “パイプラインタイプに分類されます。
パイプラインで実行する必要があるジョブを決定するために、rules:
とneeds:
キーワードを多用します。複数のタイプの変更を含むMRでは、複数のタイプのジョブを含むパイプラインを持つことに注意してください(例えば、docs-onlyとcode-onlyのパイプラインの組み合わせ)。
以下は、各パイプラインタイプのクリティカルパスのグラフです。クリティカルパスの一部でないジョブは省略されています。
ドキュメントパイプライン
バックエンドパイプライン
レビューアプリ パイプライン
エンド・ツー・エンドのパイプライン
CI設定内部
専用のCI設定内部ページを参照してください。
パフォーマンス
専用のCI設定パフォーマンスページをご覧ください。