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
path: root/spec
diff options
context:
space:
mode:
authorAlejandro Rodríguez <alejorro70@gmail.com>2017-06-01 00:06:01 +0300
committerDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>2017-06-01 00:06:01 +0300
commit671284ba375109becbfa2a288032cdc7301b157b (patch)
treefc055d19700f433115bbed4f62a86a72c711c56f /spec
parent322c9be816cd5cd9747a8737ec04622aa6b81e6b (diff)
Add feature toggles through Flipper
Diffstat (limited to 'spec')
-rw-r--r--spec/lib/feature_spec.rb26
-rw-r--r--spec/lib/gitlab/gitaly_client_spec.rb82
-rw-r--r--spec/requests/api/features_spec.rb104
-rw-r--r--spec/support/gitaly.rb3
4 files changed, 213 insertions, 2 deletions
diff --git a/spec/lib/feature_spec.rb b/spec/lib/feature_spec.rb
new file mode 100644
index 00000000000..1d92a5cb33f
--- /dev/null
+++ b/spec/lib/feature_spec.rb
@@ -0,0 +1,26 @@
+require 'spec_helper'
+
+describe Feature, lib: true do
+ describe '.get' do
+ let(:feature) { double(:feature) }
+ let(:key) { 'my_feature' }
+
+ it 'returns the Flipper feature' do
+ expect_any_instance_of(Flipper::DSL).to receive(:feature).with(key).
+ and_return(feature)
+
+ expect(described_class.get(key)).to be(feature)
+ end
+ end
+
+ describe '.all' do
+ let(:features) { Set.new }
+
+ it 'returns the Flipper features as an array' do
+ expect_any_instance_of(Flipper::DSL).to receive(:features).
+ and_return(features)
+
+ expect(described_class.all).to eq(features.to_a)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb
index 08ee0dff6b2..95ecba67532 100644
--- a/spec/lib/gitlab/gitaly_client_spec.rb
+++ b/spec/lib/gitlab/gitaly_client_spec.rb
@@ -1,7 +1,10 @@
require 'spec_helper'
-describe Gitlab::GitalyClient, lib: true do
+# We stub Gitaly in `spec/support/gitaly.rb` for other tests. We don't want
+# those stubs while testing the GitalyClient itself.
+describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do
describe '.stub' do
+ # Notice that this is referring to gRPC "stubs", not rspec stubs
before { described_class.clear_stubs! }
context 'when passed a UNIX socket address' do
@@ -32,4 +35,81 @@ describe Gitlab::GitalyClient, lib: true do
end
end
end
+
+ describe 'feature_enabled?' do
+ let(:feature_name) { 'my_feature' }
+ let(:real_feature_name) { "gitaly_#{feature_name}" }
+
+ context 'when Gitaly is disabled' do
+ before { allow(described_class).to receive(:enabled?).and_return(false) }
+
+ it 'returns false' do
+ expect(described_class.feature_enabled?(feature_name)).to be(false)
+ end
+ end
+
+ context 'when the feature status is DISABLED' do
+ let(:feature_status) { Gitlab::GitalyClient::MigrationStatus::DISABLED }
+
+ it 'returns false' do
+ expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false)
+ end
+ end
+
+ context 'when the feature_status is OPT_IN' do
+ let(:feature_status) { Gitlab::GitalyClient::MigrationStatus::OPT_IN }
+
+ context "when the feature flag hasn't been set" do
+ it 'returns false' do
+ expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false)
+ end
+ end
+
+ context "when the feature flag is set to disable" do
+ before { Feature.get(real_feature_name).disable }
+
+ it 'returns false' do
+ expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false)
+ end
+ end
+
+ context "when the feature flag is set to enable" do
+ before { Feature.get(real_feature_name).enable }
+
+ it 'returns true' do
+ expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(true)
+ end
+ end
+
+ context "when the feature flag is set to a percentage of time" do
+ before { Feature.get(real_feature_name).enable_percentage_of_time(70) }
+
+ it 'bases the result on pseudo-random numbers' do
+ expect(Random).to receive(:rand).and_return(0.3)
+ expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(true)
+
+ expect(Random).to receive(:rand).and_return(0.8)
+ expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false)
+ end
+ end
+ end
+
+ context 'when the feature_status is OPT_OUT' do
+ let(:feature_status) { Gitlab::GitalyClient::MigrationStatus::OPT_OUT }
+
+ context "when the feature flag hasn't been set" do
+ it 'returns true' do
+ expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(true)
+ end
+ end
+
+ context "when the feature flag is set to disable" do
+ before { Feature.get(real_feature_name).disable }
+
+ it 'returns false' do
+ expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false)
+ end
+ end
+ end
+ end
end
diff --git a/spec/requests/api/features_spec.rb b/spec/requests/api/features_spec.rb
new file mode 100644
index 00000000000..f169e6661d1
--- /dev/null
+++ b/spec/requests/api/features_spec.rb
@@ -0,0 +1,104 @@
+require 'spec_helper'
+
+describe API::Features do
+ let(:user) { create(:user) }
+ let(:admin) { create(:admin) }
+
+ describe 'GET /features' do
+ let(:expected_features) do
+ [
+ {
+ 'name' => 'feature_1',
+ 'state' => 'on',
+ 'gates' => [{ 'key' => 'boolean', 'value' => true }]
+ },
+ {
+ 'name' => 'feature_2',
+ 'state' => 'off',
+ 'gates' => [{ 'key' => 'boolean', 'value' => false }]
+ }
+ ]
+ end
+
+ before do
+ Feature.get('feature_1').enable
+ Feature.get('feature_2').disable
+ end
+
+ it 'returns a 401 for anonymous users' do
+ get api('/features')
+
+ expect(response).to have_http_status(401)
+ end
+
+ it 'returns a 403 for users' do
+ get api('/features', user)
+
+ expect(response).to have_http_status(403)
+ end
+
+ it 'returns the feature list for admins' do
+ get api('/features', admin)
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to match_array(expected_features)
+ end
+ end
+
+ describe 'POST /feature' do
+ let(:feature_name) { 'my_feature' }
+ it 'returns a 401 for anonymous users' do
+ post api("/features/#{feature_name}")
+
+ expect(response).to have_http_status(401)
+ end
+
+ it 'returns a 403 for users' do
+ post api("/features/#{feature_name}", user)
+
+ expect(response).to have_http_status(403)
+ end
+
+ it 'creates an enabled feature if passed true' do
+ post api("/features/#{feature_name}", admin), value: 'true'
+
+ expect(response).to have_http_status(201)
+ expect(Feature.get(feature_name)).to be_enabled
+ end
+
+ it 'creates a feature with the given percentage if passed an integer' do
+ post api("/features/#{feature_name}", admin), value: '50'
+
+ expect(response).to have_http_status(201)
+ expect(Feature.get(feature_name).percentage_of_time_value).to be(50)
+ end
+
+ context 'when the feature exists' do
+ let(:feature) { Feature.get(feature_name) }
+
+ before do
+ feature.disable # This also persists the feature on the DB
+ end
+
+ it 'enables the feature if passed true' do
+ post api("/features/#{feature_name}", admin), value: 'true'
+
+ expect(response).to have_http_status(201)
+ expect(feature).to be_enabled
+ end
+
+ context 'with a pre-existing percentage value' do
+ before do
+ feature.enable_percentage_of_time(50)
+ end
+
+ it 'updates the percentage of time if passed an integer' do
+ post api("/features/#{feature_name}", admin), value: '30'
+
+ expect(response).to have_http_status(201)
+ expect(Feature.get(feature_name).percentage_of_time_value).to be(30)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/gitaly.rb b/spec/support/gitaly.rb
index 7aca902fc61..2bf159002a0 100644
--- a/spec/support/gitaly.rb
+++ b/spec/support/gitaly.rb
@@ -1,6 +1,7 @@
if Gitlab::GitalyClient.enabled?
RSpec.configure do |config|
- config.before(:each) do
+ config.before(:each) do |example|
+ next if example.metadata[:skip_gitaly_mock]
allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(true)
end
end