Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-09-20 16:18:24 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-09-20 16:18:24 +0300
commit0653e08efd039a5905f3fa4f6e9cef9f5d2f799c (patch)
tree4dcc884cf6d81db44adae4aa99f8ec1233a41f55 /spec/models/operations
parent744144d28e3e7fddc117924fef88de5d9674fe4c (diff)
Add latest changes from gitlab-org/gitlab@14-3-stable-eev14.3.0-rc42
Diffstat (limited to 'spec/models/operations')
-rw-r--r--spec/models/operations/feature_flag_scope_spec.rb391
-rw-r--r--spec/models/operations/feature_flag_spec.rb118
2 files changed, 1 insertions, 508 deletions
diff --git a/spec/models/operations/feature_flag_scope_spec.rb b/spec/models/operations/feature_flag_scope_spec.rb
deleted file mode 100644
index dc83789fade..00000000000
--- a/spec/models/operations/feature_flag_scope_spec.rb
+++ /dev/null
@@ -1,391 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Operations::FeatureFlagScope do
- describe 'associations' do
- it { is_expected.to belong_to(:feature_flag) }
- end
-
- describe 'validations' do
- context 'when duplicate environment scope is going to be created' do
- let!(:existing_feature_flag_scope) do
- create(:operations_feature_flag_scope)
- end
-
- let(:new_feature_flag_scope) do
- build(:operations_feature_flag_scope,
- feature_flag: existing_feature_flag_scope.feature_flag,
- environment_scope: existing_feature_flag_scope.environment_scope)
- end
-
- it 'validates uniqueness of environment scope' do
- new_feature_flag_scope.save
-
- expect(new_feature_flag_scope.errors[:environment_scope])
- .to include("(#{existing_feature_flag_scope.environment_scope})" \
- " has already been taken")
- end
- end
-
- context 'when environment scope of a default scope is updated' do
- let!(:feature_flag) { create(:operations_feature_flag, :legacy_flag) }
- let!(:scope_default) { feature_flag.default_scope }
-
- it 'keeps default scope intact' do
- scope_default.update(environment_scope: 'review/*')
-
- expect(scope_default.errors[:environment_scope])
- .to include("cannot be changed from default scope")
- end
- end
-
- context 'when a default scope is destroyed' do
- let!(:feature_flag) { create(:operations_feature_flag, :legacy_flag) }
- let!(:scope_default) { feature_flag.default_scope }
-
- it 'prevents from destroying the default scope' do
- expect { scope_default.destroy! }.to raise_error(ActiveRecord::ReadOnlyRecord)
- end
- end
-
- describe 'strategy validations' do
- it 'handles null strategies which can occur while adding the column during migration' do
- scope = create(:operations_feature_flag_scope, active: true)
- allow(scope).to receive(:strategies).and_return(nil)
-
- scope.active = false
- scope.save
-
- expect(scope.errors[:strategies]).to be_empty
- end
-
- it 'validates multiple strategies' do
- feature_flag = create(:operations_feature_flag)
- scope = described_class.create(feature_flag: feature_flag,
- environment_scope: 'production', active: true,
- strategies: [{ name: "default", parameters: {} },
- { name: "invalid", parameters: {} }])
-
- expect(scope.errors[:strategies]).not_to be_empty
- end
-
- where(:invalid_value) do
- [{}, 600, "bad", [{ name: 'default', parameters: {} }, 300]]
- end
- with_them do
- it 'must be an array of strategy hashes' do
- scope = create(:operations_feature_flag_scope)
-
- scope.strategies = invalid_value
- scope.save
-
- expect(scope.errors[:strategies]).to eq(['must be an array of strategy hashes'])
- end
- end
-
- describe 'name' do
- using RSpec::Parameterized::TableSyntax
-
- where(:name, :params, :expected) do
- 'default' | {} | []
- 'gradualRolloutUserId' | { groupId: 'mygroup', percentage: '50' } | []
- 'userWithId' | { userIds: 'sam' } | []
- 5 | nil | ['strategy name is invalid']
- nil | nil | ['strategy name is invalid']
- "nothing" | nil | ['strategy name is invalid']
- "" | nil | ['strategy name is invalid']
- 40.0 | nil | ['strategy name is invalid']
- {} | nil | ['strategy name is invalid']
- [] | nil | ['strategy name is invalid']
- end
- with_them do
- it 'must be one of "default", "gradualRolloutUserId", or "userWithId"' do
- feature_flag = create(:operations_feature_flag)
- scope = described_class.create(feature_flag: feature_flag,
- environment_scope: 'production', active: true,
- strategies: [{ name: name, parameters: params }])
-
- expect(scope.errors[:strategies]).to eq(expected)
- end
- end
- end
-
- describe 'parameters' do
- context 'when the strategy name is gradualRolloutUserId' do
- it 'must have parameters' do
- feature_flag = create(:operations_feature_flag)
- scope = described_class.create(feature_flag: feature_flag,
- environment_scope: 'production', active: true,
- strategies: [{ name: 'gradualRolloutUserId' }])
-
- expect(scope.errors[:strategies]).to eq(['parameters are invalid'])
- end
-
- where(:invalid_parameters) do
- [nil, {}, { percentage: '40', groupId: 'mygroup', userIds: '4' }, { percentage: '40' },
- { percentage: '40', groupId: 'mygroup', extra: nil }, { groupId: 'mygroup' }]
- end
- with_them do
- it 'must have valid parameters for the strategy' do
- feature_flag = create(:operations_feature_flag)
- scope = described_class.create(feature_flag: feature_flag,
- environment_scope: 'production', active: true,
- strategies: [{ name: 'gradualRolloutUserId',
- parameters: invalid_parameters }])
-
- expect(scope.errors[:strategies]).to eq(['parameters are invalid'])
- end
- end
-
- it 'allows the parameters in any order' do
- feature_flag = create(:operations_feature_flag)
- scope = described_class.create(feature_flag: feature_flag,
- environment_scope: 'production', active: true,
- strategies: [{ name: 'gradualRolloutUserId',
- parameters: { percentage: '10', groupId: 'mygroup' } }])
-
- expect(scope.errors[:strategies]).to be_empty
- end
-
- describe 'percentage' do
- where(:invalid_value) do
- [50, 40.0, { key: "value" }, "garbage", "00", "01", "101", "-1", "-10", "0100",
- "1000", "10.0", "5%", "25%", "100hi", "e100", "30m", " ", "\r\n", "\n", "\t",
- "\n10", "20\n", "\n100", "100\n", "\n ", nil]
- end
- with_them do
- it 'must be a string value between 0 and 100 inclusive and without a percentage sign' do
- feature_flag = create(:operations_feature_flag)
- scope = described_class.create(feature_flag: feature_flag,
- environment_scope: 'production', active: true,
- strategies: [{ name: 'gradualRolloutUserId',
- parameters: { groupId: 'mygroup', percentage: invalid_value } }])
-
- expect(scope.errors[:strategies]).to eq(['percentage must be a string between 0 and 100 inclusive'])
- end
- end
-
- where(:valid_value) do
- %w[0 1 10 38 100 93]
- end
- with_them do
- it 'must be a string value between 0 and 100 inclusive and without a percentage sign' do
- feature_flag = create(:operations_feature_flag)
- scope = described_class.create(feature_flag: feature_flag,
- environment_scope: 'production', active: true,
- strategies: [{ name: 'gradualRolloutUserId',
- parameters: { groupId: 'mygroup', percentage: valid_value } }])
-
- expect(scope.errors[:strategies]).to eq([])
- end
- end
- end
-
- describe 'groupId' do
- where(:invalid_value) do
- [nil, 4, 50.0, {}, 'spaces bad', 'bad$', '%bad', '<bad', 'bad>', '!bad',
- '.bad', 'Bad', 'bad1', "", " ", "b" * 33, "ba_d", "ba\nd"]
- end
- with_them do
- it 'must be a string value of up to 32 lowercase characters' do
- feature_flag = create(:operations_feature_flag)
- scope = described_class.create(feature_flag: feature_flag,
- environment_scope: 'production', active: true,
- strategies: [{ name: 'gradualRolloutUserId',
- parameters: { groupId: invalid_value, percentage: '40' } }])
-
- expect(scope.errors[:strategies]).to eq(['groupId parameter is invalid'])
- end
- end
-
- where(:valid_value) do
- ["somegroup", "anothergroup", "okay", "g", "a" * 32]
- end
- with_them do
- it 'must be a string value of up to 32 lowercase characters' do
- feature_flag = create(:operations_feature_flag)
- scope = described_class.create(feature_flag: feature_flag,
- environment_scope: 'production', active: true,
- strategies: [{ name: 'gradualRolloutUserId',
- parameters: { groupId: valid_value, percentage: '40' } }])
-
- expect(scope.errors[:strategies]).to eq([])
- end
- end
- end
- end
-
- context 'when the strategy name is userWithId' do
- it 'must have parameters' do
- feature_flag = create(:operations_feature_flag)
- scope = described_class.create(feature_flag: feature_flag,
- environment_scope: 'production', active: true,
- strategies: [{ name: 'userWithId' }])
-
- expect(scope.errors[:strategies]).to eq(['parameters are invalid'])
- end
-
- where(:invalid_parameters) do
- [nil, { userIds: 'sam', percentage: '40' }, { userIds: 'sam', some: 'param' }, { percentage: '40' }, {}]
- end
- with_them do
- it 'must have valid parameters for the strategy' do
- feature_flag = create(:operations_feature_flag)
- scope = described_class.create(feature_flag: feature_flag,
- environment_scope: 'production', active: true,
- strategies: [{ name: 'userWithId', parameters: invalid_parameters }])
-
- expect(scope.errors[:strategies]).to eq(['parameters are invalid'])
- end
- end
-
- describe 'userIds' do
- where(:valid_value) do
- ["", "sam", "1", "a", "uuid-of-some-kind", "sam,fred,tom,jane,joe,mike",
- "gitlab@example.com", "123,4", "UPPER,Case,charActeRS", "0",
- "$valid$email#2345#$%..{}+=-)?\\/@example.com", "spaces allowed",
- "a" * 256, "a,#{'b' * 256},ccc", "many spaces"]
- end
- with_them do
- it 'is valid with a string of comma separated values' do
- feature_flag = create(:operations_feature_flag)
- scope = described_class.create(feature_flag: feature_flag,
- environment_scope: 'production', active: true,
- strategies: [{ name: 'userWithId', parameters: { userIds: valid_value } }])
-
- expect(scope.errors[:strategies]).to be_empty
- end
- end
-
- where(:invalid_value) do
- [1, 2.5, {}, [], nil, "123\n456", "1,2,3,12\t3", "\n", "\n\r",
- "joe\r,sam", "1,2,2", "1,,2", "1,2,,,,", "b" * 257, "1, ,2", "tim, ,7", " ",
- " ", " ,1", "1, ", " leading,1", "1,trailing ", "1, both ,2"]
- end
- with_them do
- it 'is invalid' do
- feature_flag = create(:operations_feature_flag)
- scope = described_class.create(feature_flag: feature_flag,
- environment_scope: 'production', active: true,
- strategies: [{ name: 'userWithId', parameters: { userIds: invalid_value } }])
-
- expect(scope.errors[:strategies]).to include(
- 'userIds must be a string of unique comma separated values each 256 characters or less'
- )
- end
- end
- end
- end
-
- context 'when the strategy name is default' do
- it 'must have parameters' do
- feature_flag = create(:operations_feature_flag)
- scope = described_class.create(feature_flag: feature_flag,
- environment_scope: 'production', active: true,
- strategies: [{ name: 'default' }])
-
- expect(scope.errors[:strategies]).to eq(['parameters are invalid'])
- end
-
- where(:invalid_value) do
- [{ groupId: "hi", percentage: "7" }, "", "nothing", 7, nil, [], 2.5]
- end
- with_them do
- it 'must be empty' do
- feature_flag = create(:operations_feature_flag)
- scope = described_class.create(feature_flag: feature_flag,
- environment_scope: 'production', active: true,
- strategies: [{ name: 'default',
- parameters: invalid_value }])
-
- expect(scope.errors[:strategies]).to eq(['parameters are invalid'])
- end
- end
-
- it 'must be empty' do
- feature_flag = create(:operations_feature_flag)
- scope = described_class.create(feature_flag: feature_flag,
- environment_scope: 'production', active: true,
- strategies: [{ name: 'default',
- parameters: {} }])
-
- expect(scope.errors[:strategies]).to be_empty
- end
- end
- end
- end
- end
-
- describe '.enabled' do
- subject { described_class.enabled }
-
- let!(:feature_flag_scope) do
- create(:operations_feature_flag_scope, active: active)
- end
-
- context 'when scope is active' do
- let(:active) { true }
-
- it 'returns the scope' do
- is_expected.to include(feature_flag_scope)
- end
- end
-
- context 'when scope is inactive' do
- let(:active) { false }
-
- it 'returns an empty array' do
- is_expected.not_to include(feature_flag_scope)
- end
- end
- end
-
- describe '.disabled' do
- subject { described_class.disabled }
-
- let!(:feature_flag_scope) do
- create(:operations_feature_flag_scope, active: active)
- end
-
- context 'when scope is active' do
- let(:active) { true }
-
- it 'returns an empty array' do
- is_expected.not_to include(feature_flag_scope)
- end
- end
-
- context 'when scope is inactive' do
- let(:active) { false }
-
- it 'returns the scope' do
- is_expected.to include(feature_flag_scope)
- end
- end
- end
-
- describe '.for_unleash_client' do
- it 'returns scopes for the specified project' do
- project1 = create(:project)
- project2 = create(:project)
- expected_feature_flag = create(:operations_feature_flag, project: project1)
- create(:operations_feature_flag, project: project2)
-
- scopes = described_class.for_unleash_client(project1, 'sandbox').to_a
-
- expect(scopes).to contain_exactly(*expected_feature_flag.scopes)
- end
-
- it 'returns a scope that matches exactly over a match with a wild card' do
- project = create(:project)
- feature_flag = create(:operations_feature_flag, project: project)
- create(:operations_feature_flag_scope, feature_flag: feature_flag, environment_scope: 'production*')
- expected_scope = create(:operations_feature_flag_scope, feature_flag: feature_flag, environment_scope: 'production')
-
- scopes = described_class.for_unleash_client(project, 'production').to_a
-
- expect(scopes).to contain_exactly(expected_scope)
- end
- end
-end
diff --git a/spec/models/operations/feature_flag_spec.rb b/spec/models/operations/feature_flag_spec.rb
index cb9da2aea34..d689632e2b4 100644
--- a/spec/models/operations/feature_flag_spec.rb
+++ b/spec/models/operations/feature_flag_spec.rb
@@ -49,28 +49,7 @@ RSpec.describe Operations::FeatureFlag do
it { is_expected.to validate_presence_of(:project) }
it { is_expected.to validate_presence_of(:name) }
it { is_expected.to validate_uniqueness_of(:name).scoped_to(:project_id) }
- it { is_expected.to define_enum_for(:version).with_values(legacy_flag: 1, new_version_flag: 2) }
-
- context 'a version 1 feature flag' do
- it 'is valid if associated with Operations::FeatureFlagScope models' do
- project = create(:project)
- feature_flag = described_class.create!({ name: 'test', project: project, version: 1,
- scopes_attributes: [{ environment_scope: '*', active: false }] })
-
- expect(feature_flag).to be_valid
- end
-
- it 'is invalid if associated with Operations::FeatureFlags::Strategy models' do
- project = create(:project)
- feature_flag = described_class.new({ name: 'test', project: project, version: 1,
- strategies_attributes: [{ name: 'default', parameters: {} }] })
-
- expect(feature_flag.valid?).to eq(false)
- expect(feature_flag.errors.messages).to eq({
- version_associations: ["version 1 feature flags may not have strategies"]
- })
- end
- end
+ it { is_expected.to define_enum_for(:version).with_values(new_version_flag: 2) }
context 'a version 2 feature flag' do
it 'is invalid if associated with Operations::FeatureFlagScope models' do
@@ -102,64 +81,9 @@ RSpec.describe Operations::FeatureFlag do
end
end
- describe 'feature flag version' do
- it 'defaults to 1 if unspecified' do
- project = create(:project)
-
- feature_flag = described_class.create!(name: 'my_flag', project: project, active: true)
-
- expect(feature_flag).to be_valid
- expect(feature_flag.version_before_type_cast).to eq(1)
- end
- end
-
- describe 'Scope creation' do
- subject { described_class.new(**params) }
-
- let(:project) { create(:project) }
-
- let(:params) do
- { name: 'test', project: project, scopes_attributes: scopes_attributes }
- end
-
- let(:scopes_attributes) do
- [{ environment_scope: '*', active: false },
- { environment_scope: 'review/*', active: true }]
- end
-
- it { is_expected.to be_valid }
-
- context 'when the first scope is not wildcard' do
- let(:scopes_attributes) do
- [{ environment_scope: 'review/*', active: true },
- { environment_scope: '*', active: false }]
- end
-
- it { is_expected.not_to be_valid }
- end
- end
-
describe 'the default scope' do
let_it_be(:project) { create(:project) }
- context 'with a version 1 feature flag' do
- it 'creates a default scope' do
- feature_flag = described_class.create!({ name: 'test', project: project, scopes_attributes: [], version: 1 })
-
- expect(feature_flag.scopes.count).to eq(1)
- expect(feature_flag.scopes.first.environment_scope).to eq('*')
- end
-
- it 'allows specifying the default scope in the parameters' do
- feature_flag = described_class.create!({ name: 'test', project: project,
- scopes_attributes: [{ environment_scope: '*', active: false },
- { environment_scope: 'review/*', active: true }], version: 1 })
-
- expect(feature_flag.scopes.count).to eq(2)
- expect(feature_flag.scopes.first.environment_scope).to eq('*')
- end
- end
-
context 'with a version 2 feature flag' do
it 'does not create a default scope' do
feature_flag = described_class.create!({ name: 'test', project: project, scopes_attributes: [], version: 2 })
@@ -180,16 +104,6 @@ RSpec.describe Operations::FeatureFlag do
end
end
- context 'when the feature flag is active and all scopes are inactive' do
- let!(:feature_flag) { create(:operations_feature_flag, :legacy_flag, active: true) }
-
- it 'returns the flag' do
- feature_flag.default_scope.update!(active: false)
-
- is_expected.to eq([feature_flag])
- end
- end
-
context 'when the feature flag is inactive' do
let!(:feature_flag) { create(:operations_feature_flag, active: false) }
@@ -197,16 +111,6 @@ RSpec.describe Operations::FeatureFlag do
is_expected.to be_empty
end
end
-
- context 'when the feature flag is inactive and all scopes are active' do
- let!(:feature_flag) { create(:operations_feature_flag, :legacy_flag, active: false) }
-
- it 'does not return the flag' do
- feature_flag.default_scope.update!(active: true)
-
- is_expected.to be_empty
- end
- end
end
describe '.disabled' do
@@ -220,16 +124,6 @@ RSpec.describe Operations::FeatureFlag do
end
end
- context 'when the feature flag is active and all scopes are inactive' do
- let!(:feature_flag) { create(:operations_feature_flag, :legacy_flag, active: true) }
-
- it 'does not return the flag' do
- feature_flag.default_scope.update!(active: false)
-
- is_expected.to be_empty
- end
- end
-
context 'when the feature flag is inactive' do
let!(:feature_flag) { create(:operations_feature_flag, active: false) }
@@ -237,16 +131,6 @@ RSpec.describe Operations::FeatureFlag do
is_expected.to eq([feature_flag])
end
end
-
- context 'when the feature flag is inactive and all scopes are active' do
- let!(:feature_flag) { create(:operations_feature_flag, :legacy_flag, active: false) }
-
- it 'returns the flag' do
- feature_flag.default_scope.update!(active: true)
-
- is_expected.to eq([feature_flag])
- end
- end
end
describe '.for_unleash_client' do