diff options
Diffstat (limited to 'spec/models/namespace_spec.rb')
-rw-r--r-- | spec/models/namespace_spec.rb | 246 |
1 files changed, 172 insertions, 74 deletions
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 647e279bf83..65d787d334b 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -6,7 +6,7 @@ RSpec.describe Namespace do include ProjectForksHelper include GitHelpers - let!(:namespace) { create(:namespace) } + let!(:namespace) { create(:namespace, :with_namespace_settings) } let(:gitlab_shell) { Gitlab::Shell.new } let(:repository_storage) { 'default' } @@ -32,14 +32,68 @@ RSpec.describe Namespace do it { is_expected.to validate_presence_of(:owner) } it { is_expected.to validate_numericality_of(:max_artifacts_size).only_integer.is_greater_than(0) } + context 'validating the parent of a namespace' do + context 'when the namespace has no parent' do + it 'allows a namespace to have no parent associated with it' do + namespace = build(:namespace) + + expect(namespace).to be_valid + end + end + + context 'when the namespace has a parent' do + it 'does not allow a namespace to have a group as its parent' do + namespace = build(:namespace, parent: build(:group)) + + expect(namespace).not_to be_valid + expect(namespace.errors[:parent_id].first).to eq('a user namespace cannot have a parent') + end + + it 'does not allow a namespace to have another namespace as its parent' do + namespace = build(:namespace, parent: build(:namespace)) + + expect(namespace).not_to be_valid + expect(namespace.errors[:parent_id].first).to eq('a user namespace cannot have a parent') + end + end + + context 'when the feature flag `validate_namespace_parent_type` is disabled' do + before do + stub_feature_flags(validate_namespace_parent_type: false) + end + + context 'when the namespace has no parent' do + it 'allows a namespace to have no parent associated with it' do + namespace = build(:namespace) + + expect(namespace).to be_valid + end + end + + context 'when the namespace has a parent' do + it 'allows a namespace to have a group as its parent' do + namespace = build(:namespace, parent: build(:group)) + + expect(namespace).to be_valid + end + + it 'allows a namespace to have another namespace as its parent' do + namespace = build(:namespace, parent: build(:namespace)) + + expect(namespace).to be_valid + end + end + end + end + it 'does not allow too deep nesting' do ancestors = (1..21).to_a - nested = build(:namespace, parent: namespace) + group = build(:group) - allow(nested).to receive(:ancestors).and_return(ancestors) + allow(group).to receive(:ancestors).and_return(ancestors) - expect(nested).not_to be_valid - expect(nested.errors[:parent_id].first).to eq('has too deep level of nesting') + expect(group).not_to be_valid + expect(group.errors[:parent_id].first).to eq('has too deep level of nesting') end describe 'reserved path validation' do @@ -116,6 +170,28 @@ RSpec.describe Namespace do it { is_expected.to include_module(Namespaces::Traversal::Recursive) } end + describe 'callbacks' do + describe 'before_save :ensure_delayed_project_removal_assigned_to_namespace_settings' do + it 'sets the matching value in namespace_settings' do + expect { namespace.update!(delayed_project_removal: true) }.to change { + namespace.namespace_settings.delayed_project_removal + }.from(false).to(true) + end + + context 'when the feature flag is disabled' do + before do + stub_feature_flags(migrate_delayed_project_removal: false) + end + + it 'does not set the matching value in namespace_settings' do + expect { namespace.update!(delayed_project_removal: true) }.not_to change { + namespace.namespace_settings.delayed_project_removal + } + end + end + end + end + describe '#visibility_level_field' do it { expect(namespace.visibility_level_field).to eq(:visibility_level) } end @@ -150,45 +226,45 @@ RSpec.describe Namespace do end describe '.search' do - let_it_be(:first_namespace) { build(:namespace, name: 'my first namespace', path: 'old-path').tap(&:save!) } - let_it_be(:parent_namespace) { build(:namespace, name: 'my parent namespace', path: 'parent-path').tap(&:save!) } - let_it_be(:second_namespace) { build(:namespace, name: 'my second namespace', path: 'new-path', parent: parent_namespace).tap(&:save!) } - let_it_be(:project_with_same_path) { create(:project, id: second_namespace.id, path: first_namespace.path) } + let_it_be(:first_group) { build(:group, name: 'my first namespace', path: 'old-path').tap(&:save!) } + let_it_be(:parent_group) { build(:group, name: 'my parent namespace', path: 'parent-path').tap(&:save!) } + let_it_be(:second_group) { build(:group, name: 'my second namespace', path: 'new-path', parent: parent_group).tap(&:save!) } + let_it_be(:project_with_same_path) { create(:project, id: second_group.id, path: first_group.path) } it 'returns namespaces with a matching name' do - expect(described_class.search('my first namespace')).to eq([first_namespace]) + expect(described_class.search('my first namespace')).to eq([first_group]) end it 'returns namespaces with a partially matching name' do - expect(described_class.search('first')).to eq([first_namespace]) + expect(described_class.search('first')).to eq([first_group]) end it 'returns namespaces with a matching name regardless of the casing' do - expect(described_class.search('MY FIRST NAMESPACE')).to eq([first_namespace]) + expect(described_class.search('MY FIRST NAMESPACE')).to eq([first_group]) end it 'returns namespaces with a matching path' do - expect(described_class.search('old-path')).to eq([first_namespace]) + expect(described_class.search('old-path')).to eq([first_group]) end it 'returns namespaces with a partially matching path' do - expect(described_class.search('old')).to eq([first_namespace]) + expect(described_class.search('old')).to eq([first_group]) end it 'returns namespaces with a matching path regardless of the casing' do - expect(described_class.search('OLD-PATH')).to eq([first_namespace]) + expect(described_class.search('OLD-PATH')).to eq([first_group]) end it 'returns namespaces with a matching route path' do - expect(described_class.search('parent-path/new-path', include_parents: true)).to eq([second_namespace]) + expect(described_class.search('parent-path/new-path', include_parents: true)).to eq([second_group]) end it 'returns namespaces with a partially matching route path' do - expect(described_class.search('parent-path/new', include_parents: true)).to eq([second_namespace]) + expect(described_class.search('parent-path/new', include_parents: true)).to eq([second_group]) end it 'returns namespaces with a matching route path regardless of the casing' do - expect(described_class.search('PARENT-PATH/NEW-PATH', include_parents: true)).to eq([second_namespace]) + expect(described_class.search('PARENT-PATH/NEW-PATH', include_parents: true)).to eq([second_group]) end end @@ -285,6 +361,18 @@ RSpec.describe Namespace do end end + describe '.top_most' do + let_it_be(:namespace) { create(:namespace) } + let_it_be(:group) { create(:group) } + let_it_be(:subgroup) { create(:group, parent: group) } + + subject { described_class.top_most.ids } + + it 'only contains root namespaces' do + is_expected.to contain_exactly(group.id, namespace.id) + end + end + describe '#ancestors_upto' do let(:parent) { create(:group) } let(:child) { create(:group, parent: parent) } @@ -800,7 +888,7 @@ RSpec.describe Namespace do end describe '#all_projects' do - shared_examples 'all projects for a group' do + context 'when namespace is a group' do let(:namespace) { create(:group) } let(:child) { create(:group, parent: namespace) } let!(:project1) { create(:project_empty_repo, namespace: namespace) } @@ -808,49 +896,39 @@ RSpec.describe Namespace do it { expect(namespace.all_projects.to_a).to match_array([project2, project1]) } it { expect(child.all_projects.to_a).to match_array([project2]) } - end - - shared_examples 'all projects for personal namespace' do - let_it_be(:user) { create(:user) } - let_it_be(:user_namespace) { create(:namespace, owner: user) } - let_it_be(:project) { create(:project, namespace: user_namespace) } - it { expect(user_namespace.all_projects.to_a).to match_array([project]) } - end - - context 'with recursive approach' do - context 'when namespace is a group' do - include_examples 'all projects for a group' + context 'when recursive_namespace_lookup_as_inner_join feature flag is on' do + before do + stub_feature_flags(recursive_namespace_lookup_as_inner_join: true) + end it 'queries for the namespace and its descendants' do - expect(Project).to receive(:where).with(namespace: [namespace, child]) - - namespace.all_projects + expect(namespace.all_projects).to match_array([project1, project2]) end end - context 'when namespace is a user namespace' do - include_examples 'all projects for personal namespace' - - it 'only queries for the namespace itself' do - expect(Project).to receive(:where).with(namespace: user_namespace) + context 'when recursive_namespace_lookup_as_inner_join feature flag is off' do + before do + stub_feature_flags(recursive_namespace_lookup_as_inner_join: false) + end - user_namespace.all_projects + it 'queries for the namespace and its descendants' do + expect(namespace.all_projects).to match_array([project1, project2]) end end end - context 'with route path wildcard approach' do - before do - stub_feature_flags(recursive_approach_for_all_projects: false) - end + context 'when namespace is a user namespace' do + let_it_be(:user) { create(:user) } + let_it_be(:user_namespace) { create(:namespace, owner: user) } + let_it_be(:project) { create(:project, namespace: user_namespace) } - context 'when namespace is a group' do - include_examples 'all projects for a group' - end + it { expect(user_namespace.all_projects.to_a).to match_array([project]) } + + it 'only queries for the namespace itself' do + expect(Project).to receive(:where).with(namespace: user_namespace) - context 'when namespace is a user namespace' do - include_examples 'all projects for personal namespace' + user_namespace.all_projects end end end @@ -1250,14 +1328,14 @@ RSpec.describe Namespace do using RSpec::Parameterized::TableSyntax shared_examples_for 'fetching closest setting' do - let!(:root_namespace) { create(:namespace) } - let!(:namespace) { create(:namespace, parent: root_namespace) } + let!(:parent) { create(:group) } + let!(:group) { create(:group, parent: parent) } - let(:setting) { namespace.closest_setting(setting_name) } + let(:setting) { group.closest_setting(setting_name) } before do - root_namespace.update_attribute(setting_name, root_setting) - namespace.update_attribute(setting_name, child_setting) + parent.update_attribute(setting_name, root_setting) + group.update_attribute(setting_name, child_setting) end it 'returns closest non-nil value' do @@ -1348,30 +1426,30 @@ RSpec.describe Namespace do context 'with a parent' do context 'when parent has shared runners disabled' do - let(:parent) { create(:namespace, :shared_runners_disabled) } - let(:sub_namespace) { build(:namespace, shared_runners_enabled: true, parent_id: parent.id) } + let(:parent) { create(:group, :shared_runners_disabled) } + let(:group) { build(:group, shared_runners_enabled: true, parent_id: parent.id) } it 'is invalid' do - expect(sub_namespace).to be_invalid - expect(sub_namespace.errors[:shared_runners_enabled]).to include('cannot be enabled because parent group has shared Runners disabled') + expect(group).to be_invalid + expect(group.errors[:shared_runners_enabled]).to include('cannot be enabled because parent group has shared Runners disabled') end end context 'when parent has shared runners disabled but allows override' do - let(:parent) { create(:namespace, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners) } - let(:sub_namespace) { build(:namespace, shared_runners_enabled: true, parent_id: parent.id) } + let(:parent) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners) } + let(:group) { build(:group, shared_runners_enabled: true, parent_id: parent.id) } it 'is valid' do - expect(sub_namespace).to be_valid + expect(group).to be_valid end end context 'when parent has shared runners enabled' do - let(:parent) { create(:namespace, shared_runners_enabled: true) } - let(:sub_namespace) { build(:namespace, shared_runners_enabled: true, parent_id: parent.id) } + let(:parent) { create(:group, shared_runners_enabled: true) } + let(:group) { build(:group, shared_runners_enabled: true, parent_id: parent.id) } it 'is valid' do - expect(sub_namespace).to be_valid + expect(group).to be_valid end end end @@ -1401,30 +1479,30 @@ RSpec.describe Namespace do context 'with a parent' do context 'when parent does not allow shared runners' do - let(:parent) { create(:namespace, :shared_runners_disabled) } - let(:sub_namespace) { build(:namespace, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent_id: parent.id) } + let(:parent) { create(:group, :shared_runners_disabled) } + let(:group) { build(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent_id: parent.id) } it 'is invalid' do - expect(sub_namespace).to be_invalid - expect(sub_namespace.errors[:allow_descendants_override_disabled_shared_runners]).to include('cannot be enabled because parent group does not allow it') + expect(group).to be_invalid + expect(group.errors[:allow_descendants_override_disabled_shared_runners]).to include('cannot be enabled because parent group does not allow it') end end context 'when parent allows shared runners and setting to true' do - let(:parent) { create(:namespace, shared_runners_enabled: true) } - let(:sub_namespace) { build(:namespace, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent_id: parent.id) } + let(:parent) { create(:group, shared_runners_enabled: true) } + let(:group) { build(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent_id: parent.id) } it 'is valid' do - expect(sub_namespace).to be_valid + expect(group).to be_valid end end context 'when parent allows shared runners and setting to false' do - let(:parent) { create(:namespace, shared_runners_enabled: true) } - let(:sub_namespace) { build(:namespace, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false, parent_id: parent.id) } + let(:parent) { create(:group, shared_runners_enabled: true) } + let(:group) { build(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false, parent_id: parent.id) } it 'is valid' do - expect(sub_namespace).to be_valid + expect(group).to be_valid end end end @@ -1449,4 +1527,24 @@ RSpec.describe Namespace do end end end + + describe '#recent?' do + subject { namespace.recent? } + + context 'when created more than 90 days ago' do + before do + namespace.update_attribute(:created_at, 91.days.ago) + end + + it { is_expected.to be(false) } + end + + context 'when created less than 90 days ago' do + before do + namespace.update_attribute(:created_at, 89.days.ago) + end + + it { is_expected.to be(true) } + end + end end |