Commit c653ae39 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'dm-license-features' into 'master'

Simplify specification of EE license/plan features

Closes #2466

See merge request gitlab-org/gitlab-ee!2943
parents 13ef4412 4aa10f53
This diff is collapsed.
...@@ -179,14 +179,11 @@ module EE ...@@ -179,14 +179,11 @@ module EE
!public? && shared_runners_enabled? && namespace.shared_runners_minutes_limit_enabled? !public? && shared_runners_enabled? && namespace.shared_runners_minutes_limit_enabled?
end end
# Checks licensed feature availability if `feature` matches any
# key on License::FEATURE_CODES. Otherwise, check feature availability
# through ProjectFeature.
def feature_available?(feature, user = nil) def feature_available?(feature, user = nil)
if License::FEATURE_CODES.key?(feature) if ProjectFeature::FEATURES.include?(feature)
licensed_feature_available?(feature)
else
super super
else
licensed_feature_available?(feature)
end end
end end
......
...@@ -94,6 +94,7 @@ module Gitlab ...@@ -94,6 +94,7 @@ module Gitlab
usage_data[:license_user_count] = license.restricted_user_count usage_data[:license_user_count] = license.restricted_user_count
usage_data[:license_starts_at] = license.starts_at usage_data[:license_starts_at] = license.starts_at
usage_data[:license_expires_at] = license.expires_at usage_data[:license_expires_at] = license.expires_at
usage_data[:license_plan] = license.plan
usage_data[:license_add_ons] = license.add_ons usage_data[:license_add_ons] = license.add_ons
end end
......
...@@ -107,11 +107,11 @@ describe Project do ...@@ -107,11 +107,11 @@ describe Project do
allow(namespace).to receive(:plan) { plan_license } allow(namespace).to receive(:plan) { plan_license }
end end
License::FEATURE_CODES.each do |feature_sym, feature_code| License::EEU_FEATURES.each do |feature_sym|
context feature_sym.to_s do
let(:feature) { feature_sym } let(:feature) { feature_sym }
let(:feature_code) { feature_code }
context feature_sym.to_s do
unless License::GLOBAL_FEATURES.include?(feature_sym)
context "checking #{feature_sym} availability both on Global and Namespace license" do context "checking #{feature_sym} availability both on Global and Namespace license" do
let(:check_namespace_plan) { true } let(:check_namespace_plan) { true }
...@@ -156,8 +156,9 @@ describe Project do ...@@ -156,8 +156,9 @@ describe Project do
end end
end end
end end
end
context "when checking #{feature_code} only for Global license" do context "when checking #{feature_sym} only for Global license" do
let(:check_namespace_plan) { false } let(:check_namespace_plan) { false }
context 'allowed by Global License' do context 'allowed by Global License' do
......
...@@ -9,9 +9,6 @@ module EE ...@@ -9,9 +9,6 @@ module EE
# This enables `geo` and disables `deploy_board` features for a spec. # This enables `geo` and disables `deploy_board` features for a spec.
# Other features are still enabled/disabled as defined in the licence. # Other features are still enabled/disabled as defined in the licence.
def stub_licensed_features(features) def stub_licensed_features(features)
unknown_features = features.keys - License::FEATURE_CODES.keys
raise "Unknown features: #{unknown_features.inspect}" unless unknown_features.empty?
allow(License).to receive(:feature_available?).and_call_original allow(License).to receive(:feature_available?).and_call_original
features.each do |feature, enabled| features.each do |feature, enabled|
......
...@@ -23,6 +23,7 @@ describe Gitlab::UsageData do ...@@ -23,6 +23,7 @@ describe Gitlab::UsageData do
counts counts
historical_max_users historical_max_users
license_add_ons license_add_ons
license_plan
license_expires_at license_expires_at
license_starts_at license_starts_at
license_user_count license_user_count
......
...@@ -214,21 +214,21 @@ describe License do ...@@ -214,21 +214,21 @@ describe License do
describe '.features_for_plan' do describe '.features_for_plan' do
it 'returns features for starter plan' do it 'returns features for starter plan' do
expect(described_class.features_for_plan('starter')) expect(described_class.features_for_plan('starter'))
.to include({ 'GitLab_MultipleIssueAssignees' => 1 }) .to include(:multiple_issue_assignees)
end end
it 'returns features for premium plan' do it 'returns features for premium plan' do
expect(described_class.features_for_plan('premium')) expect(described_class.features_for_plan('premium'))
.to include({ 'GitLab_MultipleIssueAssignees' => 1, 'GitLab_DeployBoard' => 1, 'GitLab_FileLocks' => 1 }) .to include(:multiple_issue_assignees, :deploy_board, :file_locks)
end end
it 'returns features for early adopter plan' do it 'returns features for early adopter plan' do
expect(described_class.features_for_plan('premium')) expect(described_class.features_for_plan('premium'))
.to include({ 'GitLab_DeployBoard' => 1, 'GitLab_FileLocks' => 1 } ) .to include(:deploy_board, :file_locks)
end end
it 'returns empty Hash if no features for given plan' do it 'returns empty array if no features for given plan' do
expect(described_class.features_for_plan('bronze')).to eq({}) expect(described_class.features_for_plan('bronze')).to eq([])
end end
end end
...@@ -264,8 +264,8 @@ describe License do ...@@ -264,8 +264,8 @@ describe License do
let(:plan) { 'premium' } let(:plan) { 'premium' }
let(:feature) { nil } let(:feature) { nil }
it 'raises KeyError' do it 'returns false' do
expect { subject }.to raise_error(KeyError) is_expected.to eq(false)
end end
end end
end end
...@@ -420,73 +420,60 @@ describe License do ...@@ -420,73 +420,60 @@ describe License do
end end
end end
describe '#add_ons' do describe '#features_from_add_ons' do
context 'without add-ons' do context 'without add-ons' do
it 'returns an empty Hash' do it 'returns an empty array' do
license = build_license_with_add_ons({}, plan: 'unknown') license = build_license_with_add_ons({}, plan: 'unknown')
expect(license.add_ons).to eq({}) expect(license.features_from_add_ons).to eq([])
end end
end end
context 'with add-ons' do context 'with add-ons' do
it 'returns all available add-ons' do it 'returns all available add-ons' do
license = build_license_with_add_ons({ License::DEPLOY_BOARD_FEATURE => 1, License::FILE_LOCKS_FEATURE => 2 }) license = build_license_with_add_ons({ 'GitLab_DeployBoard' => 1, 'GitLab_FileLocks' => 2 })
expect(license.add_ons.keys).to include(License::DEPLOY_BOARD_FEATURE, License::FILE_LOCKS_FEATURE)
end
it 'can return details about a single add-on' do
license = build_license_with_add_ons({ License::DEPLOY_BOARD_FEATURE => 2 })
expect(license.add_ons[License::DEPLOY_BOARD_FEATURE]).to eq(2)
end
end
context 'with extra features mapped by plan' do
it 'returns all available add-ons and extra features' do
license = build_license_with_add_ons({ License::DEPLOY_BOARD_FEATURE => 1 }, plan: License::PREMIUM_PLAN)
eep_features = License::EEP_FEATURES.reduce({}, :merge).keys
expect(license.add_ons.keys).to include(License::DEPLOY_BOARD_FEATURE, *eep_features) expect(license.features_from_add_ons).to match_array([:deploy_board, :file_locks])
end end
end end
end end
describe '#feature_available?' do describe '#feature_available?' do
it 'returns true if add-on exists and have a quantity greater than 0' do it 'returns true if add-on exists and have a quantity greater than 0' do
license = build_license_with_add_ons({ License::DEPLOY_BOARD_FEATURE => 1 }) license = build_license_with_add_ons({ 'GitLab_DeployBoard' => 1 })
expect(license.feature_available?(:deploy_board)).to eq(true) expect(license.feature_available?(:deploy_board)).to eq(true)
end end
it 'returns false if add-on exists but have a quantity of 0' do it 'returns true if the feature is included in the plan do' do
license = build_license_with_add_ons({ License::DEPLOY_BOARD_FEATURE => 0 }) license = build_license_with_add_ons({}, plan: License::PREMIUM_PLAN)
expect(license.feature_available?(:deploy_board)).to eq(false) expect(license.feature_available?(:auditor_user)).to eq(true)
end end
it 'returns false if add-on does not exists' do it 'returns false if add-on exists but have a quantity of 0' do
license = build_license_with_add_ons({}) license = build_license_with_add_ons({ 'GitLab_DeployBoard' => 0 })
expect(license.feature_available?(:deploy_board)).to eq(false) expect(license.feature_available?(:deploy_board)).to eq(false)
end end
it 'raises error if invalid symbol is sent' do it 'returns false if add-on does not exists' do
license = build_license_with_add_ons({}) license = build_license_with_add_ons({})
expect { license.feature_available?(:invalid) }.to raise_error(KeyError) expect(license.feature_available?(:deploy_board)).to eq(false)
expect(license.feature_available?(:auditor_user)).to eq(false)
end end
context 'with an expired trial license' do context 'with an expired trial license' do
let(:license) { create(:license, trial: true, expired: true) }
before(:all) do before(:all) do
described_class.destroy_all described_class.destroy_all
create(:license, trial: true, expired: true)
end end
::License::FEATURE_CODES.keys do |feature_code| ::License::EES_FEATURES.each do |feature|
it "returns false for #{feature_code}" do it "returns false for #{feature}" do
expect(license.feature_available?(feature_code)).to eq(false) expect(license.feature_available?(feature)).to eq(false)
end end
end end
end end
......
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