summaryrefslogtreecommitdiff
path: root/spec/models/concerns/featurable_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/models/concerns/featurable_spec.rb')
-rw-r--r--spec/models/concerns/featurable_spec.rb184
1 files changed, 184 insertions, 0 deletions
diff --git a/spec/models/concerns/featurable_spec.rb b/spec/models/concerns/featurable_spec.rb
new file mode 100644
index 00000000000..89720e3652c
--- /dev/null
+++ b/spec/models/concerns/featurable_spec.rb
@@ -0,0 +1,184 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Featurable do
+ let_it_be(:user) { create(:user) }
+ let(:project) { create(:project) }
+ let(:feature_class) { subject.class }
+ let(:features) { feature_class::FEATURES }
+
+ subject { project.project_feature }
+
+ describe '.quoted_access_level_column' do
+ it 'returns the table name and quoted column name for a feature' do
+ expected = '"project_features"."issues_access_level"'
+
+ expect(feature_class.quoted_access_level_column(:issues)).to eq(expected)
+ end
+ end
+
+ describe '.access_level_attribute' do
+ it { expect(feature_class.access_level_attribute(:wiki)).to eq :wiki_access_level }
+
+ it 'raises error for unspecified feature' do
+ expect { feature_class.access_level_attribute(:unknown) }
+ .to raise_error(ArgumentError, /invalid feature: unknown/)
+ end
+ end
+
+ describe '.set_available_features' do
+ let!(:klass) do
+ Class.new do
+ include Featurable
+ set_available_features %i(feature1 feature2)
+
+ def feature1_access_level
+ Featurable::DISABLED
+ end
+
+ def feature2_access_level
+ Featurable::ENABLED
+ end
+ end
+ end
+ let!(:instance) { klass.new }
+
+ it { expect(klass.available_features).to eq [:feature1, :feature2] }
+ it { expect(instance.feature1_enabled?).to be_falsey }
+ it { expect(instance.feature2_enabled?).to be_truthy }
+ end
+
+ describe '.available_features' do
+ it { expect(feature_class.available_features).to include(*features) }
+ end
+
+ describe '#access_level' do
+ it 'returns access level' do
+ expect(subject.access_level(:wiki)).to eq(subject.wiki_access_level)
+ end
+ end
+
+ describe '#feature_available?' do
+ let(:features) { %w(issues wiki builds merge_requests snippets repository pages metrics_dashboard) }
+
+ context 'when features are disabled' do
+ it "returns false" do
+ update_all_project_features(project, features, ProjectFeature::DISABLED)
+
+ features.each do |feature|
+ expect(project.feature_available?(feature.to_sym, user)).to eq(false), "#{feature} failed"
+ end
+ end
+ end
+
+ context 'when features are enabled only for team members' do
+ it "returns false when user is not a team member" do
+ update_all_project_features(project, features, ProjectFeature::PRIVATE)
+
+ features.each do |feature|
+ expect(project.feature_available?(feature.to_sym, user)).to eq(false), "#{feature} failed"
+ end
+ end
+
+ it "returns true when user is a team member" do
+ project.add_developer(user)
+
+ update_all_project_features(project, features, ProjectFeature::PRIVATE)
+
+ features.each do |feature|
+ expect(project.feature_available?(feature.to_sym, user)).to eq(true), "#{feature} failed"
+ end
+ end
+
+ it "returns true when user is a member of project group" do
+ group = create(:group)
+ project = create(:project, namespace: group)
+ group.add_developer(user)
+
+ update_all_project_features(project, features, ProjectFeature::PRIVATE)
+
+ features.each do |feature|
+ expect(project.feature_available?(feature.to_sym, user)).to eq(true), "#{feature} failed"
+ end
+ end
+
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it "returns true if user is an admin" do
+ user.update_attribute(:admin, true)
+
+ update_all_project_features(project, features, ProjectFeature::PRIVATE)
+
+ features.each do |feature|
+ expect(project.feature_available?(feature.to_sym, user)).to eq(true), "#{feature} failed"
+ end
+ end
+ end
+
+ context 'when admin mode is disabled' do
+ it "returns false when user is an admin" do
+ user.update_attribute(:admin, true)
+
+ update_all_project_features(project, features, ProjectFeature::PRIVATE)
+
+ features.each do |feature|
+ expect(project.feature_available?(feature.to_sym, user)).to eq(false), "#{feature} failed"
+ end
+ end
+ end
+ end
+
+ context 'when feature is enabled for everyone' do
+ it "returns true" do
+ expect(project.feature_available?(:issues, user)).to eq(true)
+ end
+ end
+
+ context 'when feature is disabled by a feature flag' do
+ it 'returns false' do
+ stub_feature_flags(issues: false)
+
+ expect(project.feature_available?(:issues, user)).to eq(false)
+ end
+ end
+
+ context 'when feature is enabled by a feature flag' do
+ it 'returns true' do
+ stub_feature_flags(issues: true)
+
+ expect(project.feature_available?(:issues, user)).to eq(true)
+ end
+ end
+ end
+
+ describe '#*_enabled?' do
+ let(:features) { %w(wiki builds merge_requests) }
+
+ it "returns false when feature is disabled" do
+ update_all_project_features(project, features, ProjectFeature::DISABLED)
+
+ features.each do |feature|
+ expect(project.public_send("#{feature}_enabled?")).to eq(false), "#{feature} failed"
+ end
+ end
+
+ it "returns true when feature is enabled only for team members" do
+ update_all_project_features(project, features, ProjectFeature::PRIVATE)
+
+ features.each do |feature|
+ expect(project.public_send("#{feature}_enabled?")).to eq(true), "#{feature} failed"
+ end
+ end
+
+ it "returns true when feature is enabled for everyone" do
+ features.each do |feature|
+ expect(project.public_send("#{feature}_enabled?")).to eq(true), "#{feature} failed"
+ end
+ end
+ end
+
+ def update_all_project_features(project, features, value)
+ project_feature_attributes = features.map { |f| ["#{f}_access_level", value] }.to_h
+ project.project_feature.update(project_feature_attributes)
+ end
+end