Commit 39264445 authored by Alex Pooley's avatar Alex Pooley Committed by Imre Farkas

Stub feature flags before specs executes

Feature flags are stubbed as true by default during tests. The stub
creation can occur after spec code has already executed.

This MR stubs all feature flags to true before any spec code can
execute.
parent e94295cc
...@@ -17,9 +17,9 @@ RSpec.describe Groups::SharedProjectsController do ...@@ -17,9 +17,9 @@ RSpec.describe Groups::SharedProjectsController do
).execute(group) ).execute(group)
end end
let_it_be(:group) { create(:group) } let!(:group) { create(:group) }
let_it_be(:user) { create(:user) } let!(:user) { create(:user) }
let_it_be(:shared_project) do let!(:shared_project) do
shared_project = create(:project, namespace: user.namespace) shared_project = create(:project, namespace: user.namespace)
share_project(shared_project) share_project(shared_project)
......
...@@ -107,7 +107,6 @@ RSpec.configure do |config| ...@@ -107,7 +107,6 @@ RSpec.configure do |config|
config.include FixtureHelpers config.include FixtureHelpers
config.include NonExistingRecordsHelpers config.include NonExistingRecordsHelpers
config.include GitlabRoutingHelper config.include GitlabRoutingHelper
config.include StubFeatureFlags
config.include StubExperiments config.include StubExperiments
config.include StubGitlabCalls config.include StubGitlabCalls
config.include StubGitlabData config.include StubGitlabData
...@@ -140,6 +139,8 @@ RSpec.configure do |config| ...@@ -140,6 +139,8 @@ RSpec.configure do |config|
config.include SidekiqMiddleware config.include SidekiqMiddleware
config.include StubActionCableConnection, type: :channel config.include StubActionCableConnection, type: :channel
include StubFeatureFlags
if ENV['CI'] || ENV['RETRIES'] if ENV['CI'] || ENV['RETRIES']
# This includes the first try, i.e. tests will be run 4 times before failing. # This includes the first try, i.e. tests will be run 4 times before failing.
config.default_retry_count = ENV.fetch('RETRIES', 3).to_i + 1 config.default_retry_count = ENV.fetch('RETRIES', 3).to_i + 1
...@@ -158,6 +159,10 @@ RSpec.configure do |config| ...@@ -158,6 +159,10 @@ RSpec.configure do |config|
# Reload all feature flags definitions # Reload all feature flags definitions
Feature.register_definitions Feature.register_definitions
# Enable all features by default for testing
# Reset any changes in after hook.
stub_all_feature_flags
end end
config.after(:all) do config.after(:all) do
...@@ -176,9 +181,6 @@ RSpec.configure do |config| ...@@ -176,9 +181,6 @@ RSpec.configure do |config|
config.before do |example| config.before do |example|
if example.metadata.fetch(:stub_feature_flags, true) if example.metadata.fetch(:stub_feature_flags, true)
# Enable all features by default for testing
stub_all_feature_flags
# The following can be removed when we remove the staged rollout strategy # The following can be removed when we remove the staged rollout strategy
# and we can just enable it using instance wide settings # and we can just enable it using instance wide settings
# (ie. ApplicationSetting#auto_devops_enabled) # (ie. ApplicationSetting#auto_devops_enabled)
...@@ -203,6 +205,8 @@ RSpec.configure do |config| ...@@ -203,6 +205,8 @@ RSpec.configure do |config|
stub_feature_flags(file_identifier_hash: false) stub_feature_flags(file_identifier_hash: false)
allow(Gitlab::GitalyClient).to receive(:can_use_disk?).and_return(enable_rugged) allow(Gitlab::GitalyClient).to receive(:can_use_disk?).and_return(enable_rugged)
else
unstub_all_feature_flags
end end
# Enable Marginalia feature for all specs in the test suite. # Enable Marginalia feature for all specs in the test suite.
...@@ -314,6 +318,9 @@ RSpec.configure do |config| ...@@ -314,6 +318,9 @@ RSpec.configure do |config|
config.after do config.after do
Fog.unmock! if Fog.mock? Fog.unmock! if Fog.mock?
Gitlab::CurrentSettings.clear_in_memory_application_settings! Gitlab::CurrentSettings.clear_in_memory_application_settings!
# Reset all feature flag stubs to default for testing
stub_all_feature_flags
end end
config.before(:example, :mailer) do config.before(:example, :mailer) do
......
# frozen_string_literal: true # frozen_string_literal: true
module StubFeatureFlags module StubFeatureFlags
def self.included(base)
# Extend Feature class with methods that can stub feature flags.
Feature.prepend(StubbedFeature)
end
class StubFeatureGate class StubFeatureGate
attr_reader :flipper_id attr_reader :flipper_id
...@@ -9,28 +14,14 @@ module StubFeatureFlags ...@@ -9,28 +14,14 @@ module StubFeatureFlags
end end
end end
# Ensure feature flags are stubbed and reset.
def stub_all_feature_flags def stub_all_feature_flags
adapter = Flipper::Adapters::Memory.new Feature.stub = true
flipper = Flipper.new(adapter) Feature.reset_flipper
allow(Feature).to receive(:flipper).and_return(flipper)
# All new requested flags are enabled by default
allow(Feature).to receive(:enabled?).and_wrap_original do |m, *args|
feature_flag = m.call(*args)
# If feature flag is not persisted we mark the feature flag as enabled
# We do `m.call` as we want to validate the execution of method arguments
# and a feature flag state if it is not persisted
unless Feature.persisted_name?(args.first)
# TODO: this is hack to support `promo_feature_available?`
# We enable all feature flags by default unless they are `promo_`
# Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/218667
feature_flag = true unless args.first.to_s.start_with?('promo_')
end end
feature_flag def unstub_all_feature_flags
end Feature.stub = false
end end
# Stub Feature flags with `flag_name: true/false` # Stub Feature flags with `flag_name: true/false`
......
# frozen_string_literal: true
# Extend the Feature class with the ability to stub feature flags.
module StubbedFeature
extend ActiveSupport::Concern
class_methods do
# Turn stubbed feature flags on or off.
def stub=(stub)
@stub = stub
end
def stub?
@stub.nil? ? true : @stub
end
# Wipe any previously set feature flags.
def reset_flipper
@flipper = nil
end
# Replace #flipper method with the optional stubbed/unstubbed version.
def flipper
if stub?
@flipper ||= Flipper.new(Flipper::Adapters::Memory.new)
else
super
end
end
# Replace #enabled? method with the optional stubbed/unstubbed version.
def enabled?(*args)
feature_flag = super(*args)
return feature_flag unless stub?
# If feature flag is not persisted we mark the feature flag as enabled
# We do `m.call` as we want to validate the execution of method arguments
# and a feature flag state if it is not persisted
unless Feature.persisted_name?(args.first)
# TODO: this is hack to support `promo_feature_available?`
# We enable all feature flags by default unless they are `promo_`
# Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/218667
feature_flag = true unless args.first.to_s.start_with?('promo_')
end
feature_flag
end
end
end
...@@ -119,6 +119,42 @@ RSpec.describe StubFeatureFlags do ...@@ -119,6 +119,42 @@ RSpec.describe StubFeatureFlags do
end end
end end
describe 'stub timing' do
context 'let_it_be variable' do
let_it_be(:let_it_be_var) { Feature.enabled?(:any_feature_flag) }
it { expect(let_it_be_var).to eq true }
end
context 'before_all variable' do
before_all do
@suite_var = Feature.enabled?(:any_feature_flag)
end
it { expect(@suite_var).to eq true }
end
context 'before(:all) variable' do
before(:all) do
@suite_var = Feature.enabled?(:any_feature_flag)
end
it { expect(@suite_var).to eq true }
end
context 'with stub_feature_flags meta' do
let(:var) { Feature.enabled?(:any_feature_flag) }
context 'as true', :stub_feature_flags do
it { expect(var).to eq true }
end
context 'as false', stub_feature_flags: false do
it { expect(var).to eq false }
end
end
end
def actor(actor) def actor(actor)
case actor case actor
when Array when Array
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment