フィーチャーフラグを使ったテスト

機能フラグを有効にして特定のテストを実行するには、QA::Runtime::Feature クラスを使用して機能フラグを有効/無効にできます(API 経由)。

機能フラグを変更するには管理者認証が必要であることに注意しましょう。GITLAB_QA_ADMIN_ACCESS_TOKEN (推奨) を使って適切なアクセストークンを提供するか、GITLAB_ADMIN_USERNAMEGITLAB_ADMIN_PASSWORD を提供すれば、QA::Runtime::Feature は自動的に管理者認証を行います。

feature_flag RSpecタグ

適切な環境でテストをスキップできるように、feature_flag タグを必ず記述してください。

オプションのメタデータ:

name

  • フォーマット:feature_flag: { name: 'feature_flag_name' }
  • 現時点では情報提供目的でのみ使用。どの機能フラグがテスト中なのかを素早く判断するのに役立ちます。

scope

  • フォーマット:feature_flag: { name: 'feature_flag_name', scope: :project }
  • scope:global に設定されている場合、テストはすべてのライブ .com 環境でスキップされます。これは、機能フラグの変更がその環境の他のテストやユーザーに影響するイシューを避けるためです。
  • scope が他の値(:project:group:userなど)に設定されている場合、またはscope が指定されていない場合、テストはカナリア、プロダクション、プリプロダクションでのみスキップされます。これは、管理者アクセスが利用できないためです。

警告: まず、グループ、プロジェクト、ユーザー、または機能グループに対してのみ機能フラグを有効にしてみることを強くお勧めします。

  • グローバル機能フラグを使用しなければならない場合は、feature_flag メタデータにscope: :global を適用することを強くお勧めします。ただし、これはSETの判断に委ねられます。
    • 例えば、あるテストが、アプリケーションの小さな領域だけに影響するグローバル機能フラグを使用し、実稼働 環境におけるクリティカルな問題をチェックするためにも必要であるとします。このようなシナリオでは、テストの実行を省略する方がリスクが高いでしょう。このような場合、scope をメタデータから除外することで、ステージングのような管理者アクセス権を持つ実稼働環境でも実行できるようになります。

** requires_admin に関する注意:** 機能フラグの更新とは無関係に、管理者アクセスを必要とするアクションがテスト内にある場合も、このタグを適用してください(API 経由でのユーザー作成など)。

以下のコードは、テストによって作成されたプロジェクトに対して:feature_flag_name という機能フラグを有効にします:

RSpec.describe "with feature flag enabled", feature_flag: {
  name: 'feature_flag_name',
  scope: :project
  } do

  let(:project) { Resource::Project.fabricate_via_api! }

  around do |example|
    Runtime::Feature.enable(:feature_flag_name, project: project)
    example.run
    Runtime::Feature.disable(:feature_flag_name, project: project)
  end

  it "feature flag test" do
    # Execute the test with the feature flag enabled.
    # It will only affect the project created in this test.
  end
end

enable メソッドとdisable メソッドは、まずフラグを設定し、更新された値が API から返されることを確認します。

同様に、グループ、ユーザー、または機能グループに対して機能を有効にすることができます:

group = Resource::Group.fabricate_via_api!
Runtime::Feature.enable(:feature_flag_name, group: group)

user = Resource::User.fabricate_via_api!
Runtime::Feature.enable(:feature_flag_name, user: user)

feature_group = "a_feature_group"
Runtime::Feature.enable(:feature_flag_name, feature_group: feature_group)

スコープが指定されていない場合、機能フラグはインスタンス全体に設定されます:

# This will affect all users!
Runtime::Feature.enable(:feature_flag_name)

セレクタの操作

新しい機能は、vue コンポーネントやhaml ファイルを新しいものに置き換えることがよくあります。ほとんどの場合、新しいファイルやコンポーネントには機能フラグがないとアクセスできません。機能フラグが有効な場合と無効な場合の両方でテストに合格しなければならない場合、この方法は問題になります。両方のシナリオでテストが合格するようにするには、次のようにします:

  1. 新しいコンポーネントやファイルの中に別のセレクタを作成します。
  2. 古いセレクタと同じ名前をつけてください。

セレクタはページオブジェクトの特定のフロントエンドファイルに接続され、qa:selectors テスト内部で利用可能かチェックされます。言及されたセレクタがフロントエンドファイルに存在しない場合、テストは失敗します。機能フラグが有効もしくは無効にされたときにセレクタが利用可能であることを保証するために、古いセレクタはそのままにして、新しいセレクタをページオブジェクトに追加します。このテストは正しいセレクタを使用し、かつ、欠落しているセレクタを検出します。

新しい機能が、すでにセレクタを持つ既存のフロントエンドファイルを変更する場合、同じ名前の新しいセレクタを追加することができます。しかし、ページに表示されるセレクタは1つだけです。そうすべきです:

  1. 機能フラグでもう片方を無効にします。
  2. 機能フラグが取り除かれたとき、フロントエンドファイルとページオブジェクトファイルから古いセレクタを削除するために、フロントエンドファイルにコメントを追加します。

# This is the link to the old file
view 'app/views/devise/passwords/edit.html.haml' do
  # The new selector should have the same name
  element :password_field
  ...
end

view 'app/views/devise/passwords/edit.html.haml' do
  element :password_field
  ...
end

# Now it can verify the selector is available
view 'app/views/devise/passwords/new_edit_behind_ff.html.haml' do
  # The selector has the same name
  element :password_field
end

リソースクラスでの作業

機能フラグがアクティブなときにリソースクラスが異なる動作をする必要がある場合、クラス内部で機能フラグの名前を持つ変数をトグルします。この変数と条件によって、すべてのアクションが適切に処理されるようになります。

この変数はfabricate_via_api 呼び出し内部で設定できます。一貫したアプローチ

  • 非アクティブではなく、activated
  • 変数名の最後にactivated を追加してください。
  • initialize メソッド内部で、変数のデフォルト値を設定します。

使用例:

def initialize
  name_of_the_feature_flag_activated = false
  ...
end

クリーンアップ

機能フラグが削除されたら、リソースクラスをクリーンアップし、変数を削除します。すべてのメソッドは、現在のデフォルト状態の条件手続きを使用する必要があります。

キャッシュによるフラグの管理

すべてのアプリケーション設定とすべての機能フラグは、GitLab内部で1分間キャッシュされます。静的環境を除いて、テスト中はすべてのキャッシュが無効になります。

テストが機能フラグを変更したとき、要素が機能フラグがアクティブな状態でのみ表示されると、動作が不安定になることがあります。この挙動を回避するには、機能フラグの後ろにある要素に対して待機を追加します。

機能フラグを有効にしたシナリオの実行

既存のテストを編集したり、新しいテストを書いたりすることなく、機能フラグを有効にしてシナリオ全体を実行することも可能です。

詳細はQA READMEをご覧ください。

機能フラグを有効にしてエンドツーエンドテストが合格することを確認します。

エンドツーエンドのテストは、機能フラグを有効にした状態でパスする必要があります。更新が必要なテストは、クワッドプランニングの一環として特定する必要があります。該当するテスト担当のソフトウェアエンジニアは、テストを更新するか、他のエンジニアを支援する責任があります。しかし、変更がクワッドプランニングを通過せず、必要なテストの更新が行われなかった場合、テストの失敗によってデプロイが妨げられる可能性があります。

機能フラグ定義が変更された場合の自動テスト実行

エンドツーエンドのテストがパスしたことを確認するには、2 つの方法があります:

  • マージリクエストが機能フラグ定義ファイルを追加または編集する場合、2 つのe2e:package-and-test ジョブ (ee:instance-parallelee:instance-parallel-ff-inverse) が自動的にマージリクエストパイプラインに含まれます。1つのジョブはデフォルトの機能フラグ状態でアプリケーションを実行し、もう1つのジョブは機能フラグを逆の値に設定します。これらのジョブは同じテストスイートを実行し、機能フラグが有効または無効の状態でパスすることを確認します。
  • エンドツーエンドのテストジョブが自動的に起動しなかったり、デフォルトの機能フラグ値でテストを実行した (これは望ましくないかもしれません) 場合、機能フラグを有効にする MR ドラフトを作成して、機能フラグが有効でも無効でもすべての E2E テストが合格するようにすることができます。

機能フラグが有効な場合のエンドツーエンド・テストの失敗に関するトラブルシューティング

機能フラグを有効にした結果、E2E テストが失敗した場合は、失敗したパイプラインのアーティファクトをブラウズして、失敗したテストのスクリーンショットを確認できます。その後、次のいずれかを実行できます:

機能開発中のテスト実行

エンドツーエンドテストで機能フラグが有効になっている場合、マージリクエストパイプラインでe2e:package-and-test ジョブを実行することで、エンドツーエンドテストスイートを使ってマージリクエストの変更をテストすることができます。機能フラグと関連する変更がすでにマージされている場合、デフォルトブランチ上でテストがパスすることを確認できます。エンドツーエンドのテストはデフォルトブランチで 2 時間ごとに実行され、その結果はtestcase-sessions プロジェクトで公開されているテストセッションレポートに出力されます。

関連するテストが機能フラグを有効にしていない場合は、機能フラグ定義ファイルを使用してデフォルトでフラグを有効にするマージリクエストの草案を作成することで、テストを更新する必要があるかどうかを調べることができます。これにより、エンドツーエンドのテストスイートが自動的に実行されます。テストが合格したら、マージリクエストを閉じることができます。テストの更新にサポートが必要な場合は、品質部門の関連する安定版担当者に連絡してください。