require 'spec_helper' describe Namespace do let!(:namespace) { create(:namespace) } it { is_expected.to have_one(:namespace_statistics) } it { is_expected.to belong_to(:plan) } it { is_expected.to delegate_method(:shared_runners_minutes).to(:namespace_statistics) } it { is_expected.to delegate_method(:shared_runners_seconds).to(:namespace_statistics) } it { is_expected.to delegate_method(:shared_runners_seconds_last_reset).to(:namespace_statistics) } context 'scopes' do describe '.with_plan' do let!(:namespace) { create :namespace, plan: namespace_plan } context 'plan is set' do let(:namespace_plan) { :bronze_plan } it 'returns namespaces with plan' do expect(described_class.with_plan).to eq([namespace]) end end context 'plan is not set' do context 'plan is empty string' do let(:namespace_plan) { '' } it 'returns no namespace' do expect(described_class.with_plan).to be_empty end end context 'plan is nil' do let(:namespace_plan) { nil } it 'returns no namespace' do expect(described_class.with_plan).to be_empty end end end end end describe 'custom validations' do describe '#validate_plan_name' do let(:group) { build(:group) } context 'with a valid plan name' do it 'is valid' do group.plan = create(:bronze_plan) expect(group).to be_valid end end context 'with an invalid plan name' do it 'is invalid' do group.plan = 'unknown' expect(group).not_to be_valid expect(group.errors[:plan]).to include('is not included in the list') end end end describe '#validate_shared_runner_minutes_support' do before do stub_feature_flags(shared_runner_minutes_on_root_namespace: true) end context 'when changing :shared_runners_minutes_limit' do before do namespace.shared_runners_minutes_limit = 100 end context 'when group is subgroup' do set(:root_ancestor) { create(:group) } let(:namespace) { create(:namespace, parent: root_ancestor) } it 'is invalid' do expect(namespace).not_to be_valid expect(namespace.errors[:shared_runners_minutes_limit]).to include('is not supported for this namespace') end end context 'when group is root' do it 'is valid' do expect(namespace).to be_valid end end end end end describe '#move_dir' do context 'when running on a primary node' do set(:primary) { create(:geo_node, :primary) } set(:secondary) { create(:geo_node) } let(:gitlab_shell) { Gitlab::Shell.new } it 'logs the Geo::RepositoryRenamedEvent for each project inside namespace' do parent = create(:namespace) child = create(:group, name: 'child', path: 'child', parent: parent) project_legacy_storage = create(:project_empty_repo, :legacy_storage, namespace: parent) create(:project, namespace: child) create(:project_empty_repo, :legacy_storage, namespace: child) full_path_was = "#{parent.full_path}_old" new_path = parent.full_path allow(parent).to receive(:gitlab_shell).and_return(gitlab_shell) allow(parent).to receive(:path_changed?).and_return(true) allow(parent).to receive(:full_path_was).and_return(full_path_was) allow(parent).to receive(:full_path).and_return(new_path) allow(gitlab_shell).to receive(:mv_namespace) .with(project_legacy_storage.repository_storage_path, full_path_was, new_path) .and_return(true) expect { parent.move_dir }.to change(Geo::RepositoryRenamedEvent, :count).by(3) end end end describe '#features' do let(:plan_license) { :free_plan } let(:group) { create(:group, plan: plan_license) } let(:global_license) { create(:license) } before do allow(License).to receive(:current).and_return(global_license) allow(global_license).to receive(:features).and_return([ :epics, # Gold only :service_desk, # Silver and up :audit_events, # Bronze and up :geo, # Global feature, should not be checked at namespace level ]) end subject { group.features } context 'when the namespace should be checked' do before do enable_namespace_license_check! end context 'when bronze' do let(:plan_license) { :bronze_plan } it 'filters for bronze features' do is_expected.to contain_exactly(:audit_events, :geo) end end context 'when silver' do let(:plan_license) { :silver_plan } it 'filters for silver features' do is_expected.to contain_exactly(:service_desk, :audit_events, :geo) end end context 'when gold' do let(:plan_license) { :gold_plan } it 'filters for gold features' do is_expected.to contain_exactly(:epics, :service_desk, :audit_events, :geo) end end context 'when free plan' do let(:plan_license) { :free_plan } it 'filters out paid features' do is_expected.to contain_exactly(:geo) end end end context 'when namespace should not be checked' do it 'includes all features in global license' do is_expected.to contain_exactly(:epics, :service_desk, :audit_events, :geo) end end context 'when there is no license' do before do allow(License).to receive(:current).and_return(nil) end it { is_expected.to be_empty } end end describe '#feature_available?' do let(:plan_license) { :bronze_plan } let(:group) { create(:group, plan: plan_license) } let(:feature) { :service_desk } subject { group.feature_available?(feature) } before do stub_licensed_features(feature => true) end it 'uses the global setting when running on premise' do stub_application_setting_on_object(group, should_check_namespace_plan: false) is_expected.to be_truthy end it 'only checks the plan once' do expect(group).to receive(:load_feature_available).once.and_call_original 2.times { group.feature_available?(:service_desk) } end context 'when checking namespace plan' do before do stub_application_setting_on_object(group, should_check_namespace_plan: true) end it 'combines the global setting with the group setting when not running on premise' do is_expected.to be_falsy end context 'when feature available on the plan' do let(:plan_license) { :gold_plan } context 'when feature available for current group' do it 'returns true' do is_expected.to be_truthy end end if Group.supports_nested_groups? context 'when license is applied to parent group' do let(:child_group) { create :group, parent: group } it 'child group has feature available' do expect(child_group.feature_available?(feature)).to be_truthy end end end end context 'when feature not available in the plan' do let(:feature) { :deploy_board } let(:plan_license) { :bronze_plan } it 'returns false' do is_expected.to be_falsy end end end end describe '#max_active_pipelines' do context 'when there is no limit defined' do it 'returns zero' do expect(namespace.max_active_pipelines).to be_zero end end context 'when free plan has limit defined' do before do create(:free_plan, active_pipelines_limit: 40) end it 'returns a free plan limits' do expect(namespace.max_active_pipelines).to be 40 end end context 'when associated plan has no limit defined' do before do namespace.plan = create(:gold_plan) end it 'returns zero' do expect(namespace.max_active_pipelines).to be_zero end end context 'when limit is defined' do before do namespace.plan = create(:gold_plan) namespace.plan.update_column(:active_pipelines_limit, 10) end it 'returns a number of maximum active pipelines' do expect(namespace.max_active_pipelines).to eq 10 end end end describe '#max_pipeline_size' do context 'when there are no limits defined' do it 'returns zero' do expect(namespace.max_pipeline_size).to be_zero end end context 'when free plan has limit defined' do before do create(:free_plan, pipeline_size_limit: 40) end it 'returns a free plan limits' do expect(namespace.max_pipeline_size).to be 40 end end context 'when associated plan has no limits defined' do before do namespace.plan = create(:gold_plan) end it 'returns zero' do expect(namespace.max_pipeline_size).to be_zero end end context 'when limit is defined' do before do namespace.plan = create(:gold_plan) namespace.plan.update_column(:pipeline_size_limit, 15) end it 'returns a number of maximum pipeline size' do expect(namespace.max_pipeline_size).to eq 15 end end end describe '#shared_runners_enabled?' do subject { namespace.shared_runners_enabled? } context 'without projects' do it { is_expected.to be_falsey } end context 'with project' do context 'and disabled shared runners' do let!(:project) do create(:project, namespace: namespace, shared_runners_enabled: false) end it { is_expected.to be_falsey } end context 'and enabled shared runners' do let!(:project) do create(:project, namespace: namespace, shared_runners_enabled: true) end it { is_expected.to be_truthy } end end end describe '#actual_shared_runners_minutes_limit' do subject { namespace.actual_shared_runners_minutes_limit } context 'when no limit defined' do it { is_expected.to be_zero } end context 'when application settings limit is set' do before do stub_application_setting(shared_runners_minutes: 1000) end it 'returns global limit' do is_expected.to eq(1000) end context 'when namespace limit is set' do before do namespace.shared_runners_minutes_limit = 500 end it 'returns namespace limit' do is_expected.to eq(500) end end end end describe '#shared_runner_minutes_supported?' do subject { namespace.shared_runner_minutes_supported? } context 'when is subgroup' do before do namespace.parent = build(:group) end context 'when shared_runner_minutes_on_root_namespace is disabled' do before do stub_feature_flags(shared_runner_minutes_on_root_namespace: false) end it 'returns true' do is_expected.to eq(true) end end context 'when shared_runner_minutes_on_root_namespace is enabled', :nested_groups do before do stub_feature_flags(shared_runner_minutes_on_root_namespace: true) end it 'returns false' do is_expected.to eq(false) end end end context 'when is root' do it 'returns true' do is_expected.to eq(true) end end end describe '#shared_runners_minutes_limit_enabled?' do subject { namespace.shared_runners_minutes_limit_enabled? } context 'with project' do let!(:project) do create(:project, namespace: namespace, shared_runners_enabled: true) end context 'when no limit defined' do it { is_expected.to be_falsey } end context 'when limit is defined' do before do namespace.shared_runners_minutes_limit = 500 end it { is_expected.to be_truthy } context 'when is subgroup', :nested_groups do before do stub_feature_flags(shared_runner_minutes_on_root_namespace: true) namespace.parent = build(:group) end it { is_expected.to be_falsey } end end end context 'without project' do it { is_expected.to be_falsey } end end describe '#shared_runners_enabled?' do subject { namespace.shared_runners_enabled? } context 'subgroup with shared runners enabled project' do let(:subgroup) { create(:group, parent: namespace) } let!(:subproject) { create(:project, namespace: subgroup, shared_runners_enabled: true) } context 'when shared_runner_minutes_on_root_namespace is disabled' do before do stub_feature_flags(shared_runner_minutes_on_root_namespace: false) end it "returns false" do is_expected.to eq(false) end end context 'when shared_runner_minutes_on_root_namespace is enabled', :nested_groups do before do stub_feature_flags(shared_runner_minutes_on_root_namespace: true) end it "returns true" do is_expected.to eq(true) end end end context 'group with shared runners enabled project' do let!(:project) { create(:project, namespace: namespace, shared_runners_enabled: true) } it "returns true" do is_expected.to eq(true) end end context 'group without projects' do it "returns false" do is_expected.to eq(false) end end end describe '#shared_runners_minutes_used?' do subject { namespace.shared_runners_minutes_used? } context 'with project' do let!(:project) do create(:project, namespace: namespace, shared_runners_enabled: true) end context 'when limit is defined' do context 'when limit is used' do let(:namespace) { create(:namespace, :with_used_build_minutes_limit) } it { is_expected.to be_truthy } end context 'when limit not yet used' do let(:namespace) { create(:namespace, :with_not_used_build_minutes_limit) } it { is_expected.to be_falsey } end context 'when minutes are not yet set' do it { is_expected.to be_falsey } end end context 'without limit' do let(:namespace) { create(:namespace, :with_build_minutes_limit) } it { is_expected.to be_falsey } end end context 'without project' do it { is_expected.to be_falsey } end end describe '#actual_plan' do context 'when namespace has a plan associated' do before do namespace.plan = create(:gold_plan) end it 'returns an associated plan' do expect(namespace.plan).not_to be_nil expect(namespace.actual_plan.name).to eq 'gold' end end context 'when namespace does not have plan associated' do before do create(:free_plan) end it 'returns a free plan object' do expect(namespace.plan).to be_nil expect(namespace.actual_plan.name).to eq 'free' end end end describe '#actual_plan_name' do context 'when namespace has a plan associated' do before do namespace.plan = create(:gold_plan) end it 'returns an associated plan name' do expect(namespace.actual_plan_name).to eq 'gold' end end context 'when namespace does not have plan associated' do it 'returns a free plan name' do expect(namespace.actual_plan_name).to eq 'free' end end end end