2021-01-03 14:25:43 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
require 'spec_helper'
|
|
|
|
|
2023-03-04 22:38:38 +05:30
|
|
|
RSpec.describe API::FeatureFlags, feature_category: :feature_flags do
|
2021-01-03 14:25:43 +05:30
|
|
|
include FeatureFlagHelpers
|
|
|
|
|
|
|
|
let_it_be(:project) { create(:project) }
|
|
|
|
let_it_be(:developer) { create(:user) }
|
|
|
|
let_it_be(:reporter) { create(:user) }
|
|
|
|
let_it_be(:non_project_member) { create(:user) }
|
2021-09-30 23:02:18 +05:30
|
|
|
|
2021-01-03 14:25:43 +05:30
|
|
|
let(:user) { developer }
|
|
|
|
|
|
|
|
before_all do
|
|
|
|
project.add_developer(developer)
|
|
|
|
project.add_reporter(reporter)
|
|
|
|
end
|
|
|
|
|
|
|
|
shared_examples_for 'check user permission' do
|
|
|
|
context 'when user is reporter' do
|
|
|
|
let(:user) { reporter }
|
|
|
|
|
|
|
|
it 'forbids the request' do
|
|
|
|
subject
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:forbidden)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
shared_examples_for 'not found' do
|
|
|
|
it 'returns Not Found' do
|
|
|
|
subject
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:not_found)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'GET /projects/:id/feature_flags' do
|
|
|
|
subject { get api("/projects/#{project.id}/feature_flags", user) }
|
|
|
|
|
|
|
|
context 'when there are two feature flags' do
|
|
|
|
let!(:feature_flag_1) do
|
|
|
|
create(:operations_feature_flag, project: project)
|
|
|
|
end
|
|
|
|
|
|
|
|
let!(:feature_flag_2) do
|
|
|
|
create(:operations_feature_flag, project: project)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns feature flags ordered by name' do
|
|
|
|
subject
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flags')
|
|
|
|
expect(json_response.count).to eq(2)
|
|
|
|
expect(json_response.first['name']).to eq(feature_flag_1.name)
|
|
|
|
expect(json_response.second['name']).to eq(feature_flag_2.name)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns the legacy flag version' do
|
|
|
|
subject
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flags')
|
2021-09-04 01:27:46 +05:30
|
|
|
expect(json_response.map { |f| f['version'] }).to eq(%w[new_version_flag new_version_flag])
|
2021-01-03 14:25:43 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not have N+1 problem' do
|
|
|
|
control_count = ActiveRecord::QueryRecorder.new { subject }
|
|
|
|
|
|
|
|
create_list(:operations_feature_flag, 3, project: project)
|
|
|
|
|
|
|
|
expect { get api("/projects/#{project.id}/feature_flags", user) }
|
|
|
|
.not_to exceed_query_limit(control_count)
|
|
|
|
end
|
|
|
|
|
|
|
|
it_behaves_like 'check user permission'
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with version 2 feature flags' do
|
|
|
|
let!(:feature_flag) do
|
|
|
|
create(:operations_feature_flag, :new_version_flag, project: project, name: 'feature1')
|
|
|
|
end
|
|
|
|
|
|
|
|
let!(:strategy) do
|
|
|
|
create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
|
|
|
|
end
|
|
|
|
|
|
|
|
let!(:scope) do
|
|
|
|
create(:operations_scope, strategy: strategy, environment_scope: 'production')
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns the feature flags' do
|
|
|
|
subject
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flags')
|
|
|
|
expect(json_response).to eq([{
|
|
|
|
'name' => 'feature1',
|
|
|
|
'description' => nil,
|
|
|
|
'active' => true,
|
|
|
|
'version' => 'new_version_flag',
|
|
|
|
'updated_at' => feature_flag.updated_at.as_json,
|
|
|
|
'created_at' => feature_flag.created_at.as_json,
|
|
|
|
'scopes' => [],
|
|
|
|
'strategies' => [{
|
|
|
|
'id' => strategy.id,
|
|
|
|
'name' => 'default',
|
|
|
|
'parameters' => {},
|
|
|
|
'scopes' => [{
|
|
|
|
'id' => scope.id,
|
|
|
|
'environment_scope' => 'production'
|
|
|
|
}]
|
|
|
|
}]
|
|
|
|
}])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'GET /projects/:id/feature_flags/:name' do
|
|
|
|
subject { get api("/projects/#{project.id}/feature_flags/#{feature_flag.name}", user) }
|
|
|
|
|
|
|
|
context 'when there is a feature flag' do
|
|
|
|
let!(:feature_flag) { create_flag(project, 'awesome-feature') }
|
|
|
|
|
|
|
|
it 'returns a feature flag entry' do
|
|
|
|
subject
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flag')
|
|
|
|
expect(json_response['name']).to eq(feature_flag.name)
|
|
|
|
expect(json_response['description']).to eq(feature_flag.description)
|
2021-09-04 01:27:46 +05:30
|
|
|
expect(json_response['version']).to eq('new_version_flag')
|
2021-01-03 14:25:43 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it_behaves_like 'check user permission'
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with a version 2 feature_flag' do
|
|
|
|
it 'returns the feature flag' do
|
|
|
|
feature_flag = create(:operations_feature_flag, :new_version_flag, project: project, name: 'feature1')
|
|
|
|
strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
|
|
|
|
scope = create(:operations_scope, strategy: strategy, environment_scope: 'production')
|
|
|
|
|
|
|
|
get api("/projects/#{project.id}/feature_flags/feature1", user)
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flag')
|
|
|
|
expect(json_response).to eq({
|
|
|
|
'name' => 'feature1',
|
|
|
|
'description' => nil,
|
|
|
|
'active' => true,
|
|
|
|
'version' => 'new_version_flag',
|
|
|
|
'updated_at' => feature_flag.updated_at.as_json,
|
|
|
|
'created_at' => feature_flag.created_at.as_json,
|
|
|
|
'scopes' => [],
|
|
|
|
'strategies' => [{
|
|
|
|
'id' => strategy.id,
|
|
|
|
'name' => 'default',
|
|
|
|
'parameters' => {},
|
|
|
|
'scopes' => [{
|
|
|
|
'id' => scope.id,
|
|
|
|
'environment_scope' => 'production'
|
|
|
|
}]
|
|
|
|
}]
|
|
|
|
})
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'POST /projects/:id/feature_flags' do
|
|
|
|
subject do
|
|
|
|
post api("/projects/#{project.id}/feature_flags", user), params: params
|
|
|
|
end
|
|
|
|
|
|
|
|
let(:params) do
|
|
|
|
{
|
2021-11-11 11:23:49 +05:30
|
|
|
name: 'awesome-feature'
|
2021-01-03 14:25:43 +05:30
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'creates a new feature flag' do
|
|
|
|
subject
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:created)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flag')
|
|
|
|
|
|
|
|
feature_flag = project.operations_feature_flags.last
|
|
|
|
expect(feature_flag.name).to eq(params[:name])
|
|
|
|
expect(feature_flag.description).to eq(params[:description])
|
|
|
|
end
|
|
|
|
|
2021-11-11 11:23:49 +05:30
|
|
|
it 'defaults to a version 2 (new) feature flag' do
|
2021-01-03 14:25:43 +05:30
|
|
|
subject
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:created)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flag')
|
|
|
|
|
|
|
|
feature_flag = project.operations_feature_flags.last
|
2021-11-11 11:23:49 +05:30
|
|
|
expect(feature_flag.version).to eq('new_version_flag')
|
2021-01-03 14:25:43 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it_behaves_like 'check user permission'
|
|
|
|
|
|
|
|
it 'returns version' do
|
|
|
|
subject
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:created)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flag')
|
2021-11-11 11:23:49 +05:30
|
|
|
expect(json_response['version']).to eq('new_version_flag')
|
2021-01-03 14:25:43 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
context 'when there is a feature flag with the same name already' do
|
|
|
|
before do
|
|
|
|
create_flag(project, 'awesome-feature')
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'fails to create a new feature flag' do
|
|
|
|
subject
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:bad_request)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when creating a version 2 feature flag' do
|
|
|
|
it 'creates a new feature flag' do
|
|
|
|
params = {
|
|
|
|
name: 'new-feature',
|
|
|
|
version: 'new_version_flag'
|
|
|
|
}
|
|
|
|
|
|
|
|
post api("/projects/#{project.id}/feature_flags", user), params: params
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:created)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flag')
|
|
|
|
expect(json_response).to match(hash_including({
|
|
|
|
'name' => 'new-feature',
|
|
|
|
'description' => nil,
|
|
|
|
'active' => true,
|
|
|
|
'version' => 'new_version_flag',
|
|
|
|
'scopes' => [],
|
|
|
|
'strategies' => []
|
|
|
|
}))
|
|
|
|
|
|
|
|
feature_flag = project.operations_feature_flags.last
|
|
|
|
expect(feature_flag.name).to eq(params[:name])
|
|
|
|
expect(feature_flag.version).to eq('new_version_flag')
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'creates a new feature flag that is inactive' do
|
|
|
|
params = {
|
|
|
|
name: 'new-feature',
|
|
|
|
version: 'new_version_flag',
|
|
|
|
active: false
|
|
|
|
}
|
|
|
|
|
|
|
|
post api("/projects/#{project.id}/feature_flags", user), params: params
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:created)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flag')
|
|
|
|
expect(json_response['active']).to eq(false)
|
|
|
|
|
|
|
|
feature_flag = project.operations_feature_flags.last
|
|
|
|
expect(feature_flag.active).to eq(false)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'creates a new feature flag with strategies' do
|
|
|
|
params = {
|
|
|
|
name: 'new-feature',
|
|
|
|
version: 'new_version_flag',
|
|
|
|
strategies: [{
|
|
|
|
name: 'userWithId',
|
|
|
|
parameters: { 'userIds': 'user1' }
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
|
|
|
|
post api("/projects/#{project.id}/feature_flags", user), params: params
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:created)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flag')
|
|
|
|
|
|
|
|
feature_flag = project.operations_feature_flags.last
|
|
|
|
expect(feature_flag.name).to eq(params[:name])
|
|
|
|
expect(feature_flag.version).to eq('new_version_flag')
|
|
|
|
expect(feature_flag.strategies.map { |s| s.slice(:name, :parameters).deep_symbolize_keys }).to eq([{
|
|
|
|
name: 'userWithId',
|
|
|
|
parameters: { userIds: 'user1' }
|
|
|
|
}])
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'creates a new feature flag with gradual rollout strategy with scopes' do
|
|
|
|
params = {
|
|
|
|
name: 'new-feature',
|
|
|
|
version: 'new_version_flag',
|
|
|
|
strategies: [{
|
|
|
|
name: 'gradualRolloutUserId',
|
|
|
|
parameters: { groupId: 'default', percentage: '50' },
|
|
|
|
scopes: [{
|
|
|
|
environment_scope: 'staging'
|
|
|
|
}]
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
|
|
|
|
post api("/projects/#{project.id}/feature_flags", user), params: params
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:created)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flag')
|
|
|
|
|
|
|
|
feature_flag = project.operations_feature_flags.last
|
|
|
|
expect(feature_flag.name).to eq(params[:name])
|
|
|
|
expect(feature_flag.version).to eq('new_version_flag')
|
|
|
|
expect(feature_flag.strategies.map { |s| s.slice(:name, :parameters).deep_symbolize_keys }).to eq([{
|
|
|
|
name: 'gradualRolloutUserId',
|
|
|
|
parameters: { groupId: 'default', percentage: '50' }
|
|
|
|
}])
|
|
|
|
expect(feature_flag.strategies.first.scopes.map { |s| s.slice(:environment_scope).deep_symbolize_keys }).to eq([{
|
|
|
|
environment_scope: 'staging'
|
|
|
|
}])
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'creates a new feature flag with flexible rollout strategy with scopes' do
|
|
|
|
params = {
|
|
|
|
name: 'new-feature',
|
|
|
|
version: 'new_version_flag',
|
|
|
|
strategies: [{
|
|
|
|
name: 'flexibleRollout',
|
2021-10-27 15:23:28 +05:30
|
|
|
parameters: { groupId: 'default', rollout: '50', stickiness: 'default' },
|
2021-01-03 14:25:43 +05:30
|
|
|
scopes: [{
|
|
|
|
environment_scope: 'staging'
|
|
|
|
}]
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
|
|
|
|
post api("/projects/#{project.id}/feature_flags", user), params: params
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:created)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flag')
|
|
|
|
|
|
|
|
feature_flag = project.operations_feature_flags.last
|
|
|
|
expect(feature_flag.name).to eq(params[:name])
|
|
|
|
expect(feature_flag.version).to eq('new_version_flag')
|
|
|
|
expect(feature_flag.strategies.map { |s| s.slice(:name, :parameters).deep_symbolize_keys }).to eq([{
|
|
|
|
name: 'flexibleRollout',
|
2021-10-27 15:23:28 +05:30
|
|
|
parameters: { groupId: 'default', rollout: '50', stickiness: 'default' }
|
2021-01-03 14:25:43 +05:30
|
|
|
}])
|
|
|
|
expect(feature_flag.strategies.first.scopes.map { |s| s.slice(:environment_scope).deep_symbolize_keys }).to eq([{
|
|
|
|
environment_scope: 'staging'
|
|
|
|
}])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when given invalid parameters' do
|
|
|
|
it 'responds with a 400 when given an invalid version' do
|
|
|
|
params = { name: 'new-feature', version: 'bad_value' }
|
|
|
|
|
|
|
|
post api("/projects/#{project.id}/feature_flags", user), params: params
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:bad_request)
|
|
|
|
expect(json_response).to eq({ 'message' => 'Version is invalid' })
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'PUT /projects/:id/feature_flags/:name' do
|
|
|
|
context 'with a version 2 feature flag' do
|
|
|
|
let!(:feature_flag) do
|
2022-10-11 01:57:18 +05:30
|
|
|
create(:operations_feature_flag, :new_version_flag,
|
|
|
|
project: project, active: true, name: 'feature1', description: 'old description')
|
2021-01-03 14:25:43 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns a 404 if the feature flag does not exist' do
|
|
|
|
params = { description: 'new description' }
|
|
|
|
|
|
|
|
put api("/projects/#{project.id}/feature_flags/other_flag_name", user), params: params
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:not_found)
|
|
|
|
expect(feature_flag.reload.description).to eq('old description')
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'forbids a request for a reporter' do
|
|
|
|
params = { description: 'new description' }
|
|
|
|
|
|
|
|
put api("/projects/#{project.id}/feature_flags/feature1", reporter), params: params
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:forbidden)
|
|
|
|
expect(feature_flag.reload.description).to eq('old description')
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns an error for an invalid update of gradual rollout' do
|
|
|
|
strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
|
|
|
|
params = {
|
|
|
|
strategies: [{
|
|
|
|
id: strategy.id,
|
|
|
|
name: 'gradualRolloutUserId',
|
|
|
|
parameters: { bad: 'params' }
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
|
|
|
|
put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:bad_request)
|
|
|
|
expect(json_response['message']).not_to be_nil
|
|
|
|
result = feature_flag.reload.strategies.map { |s| s.slice(:id, :name, :parameters).deep_symbolize_keys }
|
|
|
|
expect(result).to eq([{
|
|
|
|
id: strategy.id,
|
|
|
|
name: 'default',
|
|
|
|
parameters: {}
|
|
|
|
}])
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns an error for an invalid update of flexible rollout' do
|
|
|
|
strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
|
|
|
|
params = {
|
|
|
|
strategies: [{
|
|
|
|
id: strategy.id,
|
|
|
|
name: 'flexibleRollout',
|
|
|
|
parameters: { bad: 'params' }
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
|
|
|
|
put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:bad_request)
|
|
|
|
expect(json_response['message']).not_to be_nil
|
|
|
|
result = feature_flag.reload.strategies.map { |s| s.slice(:id, :name, :parameters).deep_symbolize_keys }
|
|
|
|
expect(result).to eq([{
|
|
|
|
id: strategy.id,
|
|
|
|
name: 'default',
|
|
|
|
parameters: {}
|
|
|
|
}])
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'updates the feature flag' do
|
|
|
|
params = { description: 'new description' }
|
|
|
|
|
|
|
|
put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flag')
|
|
|
|
expect(feature_flag.reload.description).to eq('new description')
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'updates the flag active value' do
|
|
|
|
params = { active: false }
|
|
|
|
|
|
|
|
put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flag')
|
|
|
|
expect(json_response['active']).to eq(false)
|
|
|
|
expect(feature_flag.reload.active).to eq(false)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'updates the feature flag name' do
|
|
|
|
params = { name: 'new-name' }
|
|
|
|
|
|
|
|
put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flag')
|
|
|
|
expect(json_response['name']).to eq('new-name')
|
|
|
|
expect(feature_flag.reload.name).to eq('new-name')
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'ignores a provided version parameter' do
|
|
|
|
params = { description: 'other description', version: 'bad_value' }
|
|
|
|
|
|
|
|
put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flag')
|
|
|
|
expect(feature_flag.reload.description).to eq('other description')
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns the feature flag json' do
|
|
|
|
params = { description: 'new description' }
|
|
|
|
|
|
|
|
put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flag')
|
|
|
|
feature_flag.reload
|
|
|
|
expect(json_response).to eq({
|
|
|
|
'name' => 'feature1',
|
|
|
|
'description' => 'new description',
|
|
|
|
'active' => true,
|
|
|
|
'created_at' => feature_flag.created_at.as_json,
|
|
|
|
'updated_at' => feature_flag.updated_at.as_json,
|
|
|
|
'scopes' => [],
|
|
|
|
'strategies' => [],
|
|
|
|
'version' => 'new_version_flag'
|
|
|
|
})
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'updates an existing feature flag strategy to be gradual rollout strategy' do
|
|
|
|
strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
|
|
|
|
params = {
|
|
|
|
strategies: [{
|
|
|
|
id: strategy.id,
|
|
|
|
name: 'gradualRolloutUserId',
|
|
|
|
parameters: { groupId: 'default', percentage: '10' }
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
|
|
|
|
put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flag')
|
|
|
|
result = feature_flag.reload.strategies.map { |s| s.slice(:id, :name, :parameters).deep_symbolize_keys }
|
|
|
|
expect(result).to eq([{
|
|
|
|
id: strategy.id,
|
|
|
|
name: 'gradualRolloutUserId',
|
|
|
|
parameters: { groupId: 'default', percentage: '10' }
|
|
|
|
}])
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'updates an existing feature flag strategy to be flexible rollout strategy' do
|
|
|
|
strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
|
|
|
|
params = {
|
|
|
|
strategies: [{
|
|
|
|
id: strategy.id,
|
|
|
|
name: 'flexibleRollout',
|
2021-10-27 15:23:28 +05:30
|
|
|
parameters: { groupId: 'default', rollout: '10', stickiness: 'default' }
|
2021-01-03 14:25:43 +05:30
|
|
|
}]
|
|
|
|
}
|
|
|
|
|
|
|
|
put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flag')
|
|
|
|
result = feature_flag.reload.strategies.map { |s| s.slice(:id, :name, :parameters).deep_symbolize_keys }
|
|
|
|
expect(result).to eq([{
|
|
|
|
id: strategy.id,
|
|
|
|
name: 'flexibleRollout',
|
2021-10-27 15:23:28 +05:30
|
|
|
parameters: { groupId: 'default', rollout: '10', stickiness: 'default' }
|
2021-01-03 14:25:43 +05:30
|
|
|
}])
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'adds a new gradual rollout strategy to a feature flag' do
|
|
|
|
strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
|
|
|
|
params = {
|
|
|
|
strategies: [{
|
|
|
|
name: 'gradualRolloutUserId',
|
|
|
|
parameters: { groupId: 'default', percentage: '10' }
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
|
|
|
|
put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flag')
|
|
|
|
result = feature_flag.reload.strategies
|
|
|
|
.map { |s| s.slice(:id, :name, :parameters).deep_symbolize_keys }
|
|
|
|
.sort_by { |s| s[:name] }
|
|
|
|
expect(result.first[:id]).to eq(strategy.id)
|
|
|
|
expect(result.map { |s| s.slice(:name, :parameters) }).to eq([{
|
|
|
|
name: 'default',
|
|
|
|
parameters: {}
|
|
|
|
}, {
|
|
|
|
name: 'gradualRolloutUserId',
|
|
|
|
parameters: { groupId: 'default', percentage: '10' }
|
|
|
|
}])
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'adds a new gradual flexible strategy to a feature flag' do
|
|
|
|
strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
|
|
|
|
params = {
|
|
|
|
strategies: [{
|
|
|
|
name: 'flexibleRollout',
|
2021-10-27 15:23:28 +05:30
|
|
|
parameters: { groupId: 'default', rollout: '10', stickiness: 'default' }
|
2021-01-03 14:25:43 +05:30
|
|
|
}]
|
|
|
|
}
|
|
|
|
|
|
|
|
put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flag')
|
|
|
|
result = feature_flag.reload.strategies
|
|
|
|
.map { |s| s.slice(:id, :name, :parameters).deep_symbolize_keys }
|
|
|
|
.sort_by { |s| s[:name] }
|
|
|
|
expect(result.first[:id]).to eq(strategy.id)
|
|
|
|
expect(result.map { |s| s.slice(:name, :parameters) }).to eq([{
|
|
|
|
name: 'default',
|
|
|
|
parameters: {}
|
|
|
|
}, {
|
|
|
|
name: 'flexibleRollout',
|
2021-10-27 15:23:28 +05:30
|
|
|
parameters: { groupId: 'default', rollout: '10', stickiness: 'default' }
|
2021-01-03 14:25:43 +05:30
|
|
|
}])
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'deletes a feature flag strategy' do
|
|
|
|
strategy_a = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
|
2022-10-11 01:57:18 +05:30
|
|
|
strategy_b = create(:operations_strategy,
|
|
|
|
feature_flag: feature_flag, name: 'userWithId', parameters: { userIds: 'userA,userB' })
|
2021-01-03 14:25:43 +05:30
|
|
|
params = {
|
|
|
|
strategies: [{
|
|
|
|
id: strategy_a.id,
|
|
|
|
name: 'default',
|
|
|
|
parameters: {},
|
|
|
|
_destroy: true
|
|
|
|
}, {
|
|
|
|
id: strategy_b.id,
|
|
|
|
name: 'userWithId',
|
|
|
|
parameters: { userIds: 'userB' }
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
|
|
|
|
put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flag')
|
|
|
|
result = feature_flag.reload.strategies
|
|
|
|
.map { |s| s.slice(:id, :name, :parameters).deep_symbolize_keys }
|
|
|
|
.sort_by { |s| s[:name] }
|
|
|
|
expect(result).to eq([{
|
|
|
|
id: strategy_b.id,
|
|
|
|
name: 'userWithId',
|
|
|
|
parameters: { userIds: 'userB' }
|
|
|
|
}])
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'updates an existing feature flag scope' do
|
|
|
|
strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
|
|
|
|
scope = create(:operations_scope, strategy: strategy, environment_scope: '*')
|
|
|
|
params = {
|
|
|
|
strategies: [{
|
|
|
|
id: strategy.id,
|
|
|
|
scopes: [{
|
|
|
|
id: scope.id,
|
|
|
|
environment_scope: 'production'
|
|
|
|
}]
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
|
|
|
|
put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flag')
|
|
|
|
result = feature_flag.reload.strategies.first.scopes.map { |s| s.slice(:id, :environment_scope).deep_symbolize_keys }
|
|
|
|
expect(result).to eq([{
|
|
|
|
id: scope.id,
|
|
|
|
environment_scope: 'production'
|
|
|
|
}])
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'deletes an existing feature flag scope' do
|
|
|
|
strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
|
|
|
|
scope = create(:operations_scope, strategy: strategy, environment_scope: '*')
|
|
|
|
params = {
|
|
|
|
strategies: [{
|
|
|
|
id: strategy.id,
|
|
|
|
scopes: [{
|
|
|
|
id: scope.id,
|
|
|
|
_destroy: true
|
|
|
|
}]
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
|
|
|
|
put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
|
|
expect(response).to match_response_schema('public_api/v4/feature_flag')
|
|
|
|
expect(feature_flag.reload.strategies.first.scopes.count).to eq(0)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'DELETE /projects/:id/feature_flags/:name' do
|
|
|
|
subject do
|
|
|
|
delete api("/projects/#{project.id}/feature_flags/#{feature_flag.name}", user),
|
|
|
|
params: params
|
|
|
|
end
|
|
|
|
|
2021-11-11 11:23:49 +05:30
|
|
|
let!(:feature_flag) { create(:operations_feature_flag, project: project) }
|
2021-01-03 14:25:43 +05:30
|
|
|
let(:params) { {} }
|
|
|
|
|
|
|
|
it 'destroys the feature flag' do
|
|
|
|
expect { subject }.to change { Operations::FeatureFlag.count }.by(-1)
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns version' do
|
|
|
|
subject
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
2021-11-11 11:23:49 +05:30
|
|
|
expect(json_response['version']).to eq('new_version_flag')
|
2021-01-03 14:25:43 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
context 'with a version 2 feature flag' do
|
|
|
|
let!(:feature_flag) { create(:operations_feature_flag, :new_version_flag, project: project) }
|
|
|
|
|
|
|
|
it 'destroys the flag' do
|
|
|
|
expect { subject }.to change { Operations::FeatureFlag.count }.by(-1)
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|