diff options
Diffstat (limited to 'spec/finders')
-rw-r--r-- | spec/finders/ci/auth_job_finder_spec.rb | 11 | ||||
-rw-r--r-- | spec/finders/ci/runners_finder_spec.rb | 28 | ||||
-rw-r--r-- | spec/finders/environments/environments_by_deployments_finder_spec.rb | 14 | ||||
-rw-r--r-- | spec/finders/group_descendants_finder_spec.rb | 345 | ||||
-rw-r--r-- | spec/finders/groups_finder_spec.rb | 15 | ||||
-rw-r--r-- | spec/finders/issuables/crm_contact_filter_spec.rb | 45 | ||||
-rw-r--r-- | spec/finders/issuables/crm_organization_filter_spec.rb | 48 | ||||
-rw-r--r-- | spec/finders/issues_finder_spec.rb | 39 | ||||
-rw-r--r-- | spec/finders/merge_requests_finder_spec.rb | 24 | ||||
-rw-r--r-- | spec/finders/packages/build_infos_finder_spec.rb | 64 | ||||
-rw-r--r-- | spec/finders/packages/group_packages_finder_spec.rb | 22 | ||||
-rw-r--r-- | spec/finders/packages/nuget/package_finder_spec.rb | 2 | ||||
-rw-r--r-- | spec/finders/personal_projects_finder_spec.rb | 34 | ||||
-rw-r--r-- | spec/finders/user_group_notification_settings_finder_spec.rb | 238 |
14 files changed, 611 insertions, 318 deletions
diff --git a/spec/finders/ci/auth_job_finder_spec.rb b/spec/finders/ci/auth_job_finder_spec.rb index 78827c9ddee..0a326699875 100644 --- a/spec/finders/ci/auth_job_finder_spec.rb +++ b/spec/finders/ci/auth_job_finder_spec.rb @@ -70,17 +70,6 @@ RSpec.describe Ci::AuthJobFinder do expect(subject.user).to be_from_ci_job_token expect(subject.user.ci_job_token_scope.source_project).to eq(job.project) end - - context 'when feature flag ci_scoped_job_token is disabled' do - before do - stub_feature_flags(ci_scoped_job_token: false) - end - - it 'does not set ci_job_token_scope on the job user' do - expect(subject).to eq(job) - expect(subject.user).not_to be_from_ci_job_token - end - end end end end diff --git a/spec/finders/ci/runners_finder_spec.rb b/spec/finders/ci/runners_finder_spec.rb index 10d3f641e02..7e3c1abd6d1 100644 --- a/spec/finders/ci/runners_finder_spec.rb +++ b/spec/finders/ci/runners_finder_spec.rb @@ -59,6 +59,20 @@ RSpec.describe Ci::RunnersFinder do end end + context 'by active status' do + it 'with active set as false calls the corresponding scope on Ci::Runner with false' do + expect(Ci::Runner).to receive(:active).with(false).and_call_original + + described_class.new(current_user: admin, params: { active: false }).execute + end + + it 'with active set as true calls the corresponding scope on Ci::Runner with true' do + expect(Ci::Runner).to receive(:active).with(true).and_call_original + + described_class.new(current_user: admin, params: { active: true }).execute + end + end + context 'by runner type' do it 'calls the corresponding scope on Ci::Runner' do expect(Ci::Runner).to receive(:project_type).and_call_original @@ -263,7 +277,15 @@ RSpec.describe Ci::RunnersFinder do let(:extra_params) { { search: 'runner_project_search' } } it 'returns correct runner' do - expect(subject).to eq([runner_project_3]) + expect(subject).to match_array([runner_project_3]) + end + end + + context 'by active status' do + let(:extra_params) { { active: false } } + + it 'returns correct runner' do + expect(subject).to match_array([runner_sub_group_1]) end end @@ -271,7 +293,7 @@ RSpec.describe Ci::RunnersFinder do let(:extra_params) { { status_status: 'paused' } } it 'returns correct runner' do - expect(subject).to eq([runner_sub_group_1]) + expect(subject).to match_array([runner_sub_group_1]) end end @@ -279,7 +301,7 @@ RSpec.describe Ci::RunnersFinder do let(:extra_params) { { tag_name: %w[runner_tag] } } it 'returns correct runner' do - expect(subject).to eq([runner_project_5]) + expect(subject).to match_array([runner_project_5]) end end diff --git a/spec/finders/environments/environments_by_deployments_finder_spec.rb b/spec/finders/environments/environments_by_deployments_finder_spec.rb index 7804ffa4ef1..1b86aced67d 100644 --- a/spec/finders/environments/environments_by_deployments_finder_spec.rb +++ b/spec/finders/environments/environments_by_deployments_finder_spec.rb @@ -11,7 +11,7 @@ RSpec.describe Environments::EnvironmentsByDeploymentsFinder do project.add_maintainer(user) end - shared_examples 'execute' do + describe '#execute' do context 'tagged deployment' do let(:environment_two) { create(:environment, project: project) } # Environments need to include commits, so rewind two commits to fit @@ -124,16 +124,4 @@ RSpec.describe Environments::EnvironmentsByDeploymentsFinder do end end end - - describe "#execute" do - include_examples 'execute' - - context 'when environments_by_deployments_finder_exists_optimization is disabled' do - before do - stub_feature_flags(environments_by_deployments_finder_exists_optimization: false) - end - - include_examples 'execute' - end - end end diff --git a/spec/finders/group_descendants_finder_spec.rb b/spec/finders/group_descendants_finder_spec.rb index 01c6eb05907..f6b87f7eeab 100644 --- a/spec/finders/group_descendants_finder_spec.rb +++ b/spec/finders/group_descendants_finder_spec.rb @@ -4,7 +4,12 @@ require 'spec_helper' RSpec.describe GroupDescendantsFinder do let_it_be(:user) { create(:user) } - let_it_be(:group) { create(:group) } + + let_it_be_with_reload(:group) do + create(:group).tap do |g| + g.add_owner(user) + end + end let(:params) { {} } @@ -12,254 +17,262 @@ RSpec.describe GroupDescendantsFinder do described_class.new(current_user: user, parent_group: group, params: params) end - before do - group.add_owner(user) - end - - describe '#has_children?' do - it 'is true when there are projects' do - create(:project, namespace: group) - - expect(finder.has_children?).to be_truthy - end - - context 'when there are subgroups' do + shared_examples 'group descentants finder examples' do + describe '#has_children?' do it 'is true when there are projects' do - create(:group, parent: group) + create(:project, namespace: group) expect(finder.has_children?).to be_truthy end - end - end - describe '#execute' do - it 'includes projects' do - project = create(:project, namespace: group) + context 'when there are subgroups' do + it 'is true when there are projects' do + create(:group, parent: group) - expect(finder.execute).to contain_exactly(project) + expect(finder.has_children?).to be_truthy + end + end end - context 'when archived is `true`' do - let(:params) { { archived: 'true' } } - - it 'includes archived projects' do - archived_project = create(:project, namespace: group, archived: true) + describe '#execute' do + it 'includes projects' do project = create(:project, namespace: group) - expect(finder.execute).to contain_exactly(archived_project, project) + expect(finder.execute).to contain_exactly(project) end - end - context 'when archived is `only`' do - let(:params) { { archived: 'only' } } + context 'when archived is `true`' do + let(:params) { { archived: 'true' } } - it 'includes only archived projects' do - archived_project = create(:project, namespace: group, archived: true) - _project = create(:project, namespace: group) + it 'includes archived projects' do + archived_project = create(:project, namespace: group, archived: true) + project = create(:project, namespace: group) - expect(finder.execute).to contain_exactly(archived_project) + expect(finder.execute).to contain_exactly(archived_project, project) + end end - end - it 'does not include archived projects' do - _archived_project = create(:project, :archived, namespace: group) + context 'when archived is `only`' do + let(:params) { { archived: 'only' } } - expect(finder.execute).to be_empty - end + it 'includes only archived projects' do + archived_project = create(:project, namespace: group, archived: true) + _project = create(:project, namespace: group) - context 'with a filter' do - let(:params) { { filter: 'test' } } + expect(finder.execute).to contain_exactly(archived_project) + end + end - it 'includes only projects matching the filter' do - _other_project = create(:project, namespace: group) - matching_project = create(:project, namespace: group, name: 'testproject') + it 'does not include archived projects' do + _archived_project = create(:project, :archived, namespace: group) - expect(finder.execute).to contain_exactly(matching_project) + expect(finder.execute).to be_empty end - end - it 'sorts elements by name as default' do - project1 = create(:project, namespace: group, name: 'z') - project2 = create(:project, namespace: group, name: 'a') + context 'with a filter' do + let(:params) { { filter: 'test' } } - expect(subject.execute).to eq([project2, project1]) - end + it 'includes only projects matching the filter' do + _other_project = create(:project, namespace: group) + matching_project = create(:project, namespace: group, name: 'testproject') - context 'sorting by name' do - let!(:project1) { create(:project, namespace: group, name: 'a', path: 'project-a') } - let!(:project2) { create(:project, namespace: group, name: 'z', path: 'project-z') } - let(:params) do - { - sort: 'name_asc' - } + expect(finder.execute).to contain_exactly(matching_project) + end end - it 'sorts elements by name' do - expect(subject.execute).to eq( - [ - project1, - project2 - ] - ) + it 'sorts elements by name as default' do + project1 = create(:project, namespace: group, name: 'z') + project2 = create(:project, namespace: group, name: 'a') + + expect(subject.execute).to match_array([project2, project1]) end - context 'with nested groups' do - let!(:subgroup1) { create(:group, parent: group, name: 'a', path: 'sub-a') } - let!(:subgroup2) { create(:group, parent: group, name: 'z', path: 'sub-z') } + context 'sorting by name' do + let!(:project1) { create(:project, namespace: group, name: 'a', path: 'project-a') } + let!(:project2) { create(:project, namespace: group, name: 'z', path: 'project-z') } + let(:params) do + { + sort: 'name_asc' + } + end it 'sorts elements by name' do expect(subject.execute).to eq( [ - subgroup1, - subgroup2, project1, project2 ] ) end - end - end - - it 'does not include projects shared with the group' do - project = create(:project, namespace: group) - other_project = create(:project) - other_project.project_group_links.create!(group: group, - group_access: Gitlab::Access::MAINTAINER) - expect(finder.execute).to contain_exactly(project) - end - end + context 'with nested groups' do + let!(:subgroup1) { create(:group, parent: group, name: 'a', path: 'sub-a') } + let!(:subgroup2) { create(:group, parent: group, name: 'z', path: 'sub-z') } + + it 'sorts elements by name' do + expect(subject.execute).to eq( + [ + subgroup1, + subgroup2, + project1, + project2 + ] + ) + end + end + end - context 'with shared groups' do - let_it_be(:other_group) { create(:group) } - let_it_be(:shared_group_link) do - create(:group_group_link, - shared_group: group, - shared_with_group: other_group) - end + it 'does not include projects shared with the group' do + project = create(:project, namespace: group) + other_project = create(:project) + other_project.project_group_links.create!(group: group, + group_access: Gitlab::Access::MAINTAINER) - context 'without common ancestor' do - it { expect(finder.execute).to be_empty } + expect(finder.execute).to contain_exactly(project) + end end - context 'with common ancestor' do - let_it_be(:common_ancestor) { create(:group) } - let_it_be(:other_group) { create(:group, parent: common_ancestor) } - let_it_be(:group) { create(:group, parent: common_ancestor) } + context 'with shared groups' do + let_it_be(:other_group) { create(:group) } + let_it_be(:shared_group_link) do + create(:group_group_link, + shared_group: group, + shared_with_group: other_group) + end - context 'querying under the common ancestor' do + context 'without common ancestor' do it { expect(finder.execute).to be_empty } end - context 'querying the common ancestor' do - subject(:finder) do - described_class.new(current_user: user, parent_group: common_ancestor, params: params) + context 'with common ancestor' do + let_it_be(:common_ancestor) { create(:group) } + let_it_be(:other_group) { create(:group, parent: common_ancestor) } + let_it_be(:group) { create(:group, parent: common_ancestor) } + + context 'querying under the common ancestor' do + it { expect(finder.execute).to be_empty } end - it 'contains shared subgroups' do - expect(finder.execute).to contain_exactly(group, other_group) + context 'querying the common ancestor' do + subject(:finder) do + described_class.new(current_user: user, parent_group: common_ancestor, params: params) + end + + it 'contains shared subgroups' do + expect(finder.execute).to contain_exactly(group, other_group) + end end end end - end - context 'with nested groups' do - let!(:project) { create(:project, namespace: group) } - let!(:subgroup) { create(:group, :private, parent: group) } + context 'with nested groups' do + let!(:project) { create(:project, namespace: group) } + let!(:subgroup) { create(:group, :private, parent: group) } - describe '#execute' do - it 'contains projects and subgroups' do - expect(finder.execute).to contain_exactly(subgroup, project) - end + describe '#execute' do + it 'contains projects and subgroups' do + expect(finder.execute).to contain_exactly(subgroup, project) + end - it 'does not include subgroups the user does not have access to' do - subgroup.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) + it 'does not include subgroups the user does not have access to' do + subgroup.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) - public_subgroup = create(:group, :public, parent: group, path: 'public-group') - other_subgroup = create(:group, :private, parent: group, path: 'visible-private-group') - other_user = create(:user) - other_subgroup.add_developer(other_user) + public_subgroup = create(:group, :public, parent: group, path: 'public-group') + other_subgroup = create(:group, :private, parent: group, path: 'visible-private-group') + other_user = create(:user) + other_subgroup.add_developer(other_user) - finder = described_class.new(current_user: other_user, parent_group: group) + finder = described_class.new(current_user: other_user, parent_group: group) - expect(finder.execute).to contain_exactly(public_subgroup, other_subgroup) - end + expect(finder.execute).to contain_exactly(public_subgroup, other_subgroup) + end - it 'only includes public groups when no user is given' do - public_subgroup = create(:group, :public, parent: group) - _private_subgroup = create(:group, :private, parent: group) + it 'only includes public groups when no user is given' do + public_subgroup = create(:group, :public, parent: group) + _private_subgroup = create(:group, :private, parent: group) - finder = described_class.new(current_user: nil, parent_group: group) + finder = described_class.new(current_user: nil, parent_group: group) - expect(finder.execute).to contain_exactly(public_subgroup) - end + expect(finder.execute).to contain_exactly(public_subgroup) + end - context 'when archived is `true`' do - let(:params) { { archived: 'true' } } + context 'when archived is `true`' do + let(:params) { { archived: 'true' } } - it 'includes archived projects in the count of subgroups' do - create(:project, namespace: subgroup, archived: true) + it 'includes archived projects in the count of subgroups' do + create(:project, namespace: subgroup, archived: true) - expect(finder.execute.first.preloaded_project_count).to eq(1) + expect(finder.execute.first.preloaded_project_count).to eq(1) + end end - end - context 'with a filter' do - let(:params) { { filter: 'test' } } + context 'with a filter' do + let(:params) { { filter: 'test' } } - it 'contains only matching projects and subgroups' do - matching_project = create(:project, namespace: group, name: 'Testproject') - matching_subgroup = create(:group, name: 'testgroup', parent: group) + it 'contains only matching projects and subgroups' do + matching_project = create(:project, namespace: group, name: 'Testproject') + matching_subgroup = create(:group, name: 'testgroup', parent: group) - expect(finder.execute).to contain_exactly(matching_subgroup, matching_project) - end + expect(finder.execute).to contain_exactly(matching_subgroup, matching_project) + end - it 'does not include subgroups the user does not have access to' do - _invisible_subgroup = create(:group, :private, parent: group, name: 'test1') - other_subgroup = create(:group, :private, parent: group, name: 'test2') - public_subgroup = create(:group, :public, parent: group, name: 'test3') - other_subsubgroup = create(:group, :private, parent: other_subgroup, name: 'test4') - other_user = create(:user) - other_subgroup.add_developer(other_user) + it 'does not include subgroups the user does not have access to' do + _invisible_subgroup = create(:group, :private, parent: group, name: 'test1') + other_subgroup = create(:group, :private, parent: group, name: 'test2') + public_subgroup = create(:group, :public, parent: group, name: 'test3') + other_subsubgroup = create(:group, :private, parent: other_subgroup, name: 'test4') + other_user = create(:user) + other_subgroup.add_developer(other_user) - finder = described_class.new(current_user: other_user, - parent_group: group, - params: params) + finder = described_class.new(current_user: other_user, + parent_group: group, + params: params) - expect(finder.execute).to contain_exactly(other_subgroup, public_subgroup, other_subsubgroup) - end + expect(finder.execute).to contain_exactly(other_subgroup, public_subgroup, other_subsubgroup) + end - context 'with matching children' do - it 'includes a group that has a subgroup matching the query and its parent' do - matching_subgroup = create(:group, :private, name: 'testgroup', parent: subgroup) + context 'with matching children' do + it 'includes a group that has a subgroup matching the query and its parent' do + matching_subgroup = create(:group, :private, name: 'testgroup', parent: subgroup) - expect(finder.execute).to contain_exactly(subgroup, matching_subgroup) - end + expect(finder.execute).to contain_exactly(subgroup, matching_subgroup) + end - it 'includes the parent of a matching project' do - matching_project = create(:project, namespace: subgroup, name: 'Testproject') + it 'includes the parent of a matching project' do + matching_project = create(:project, namespace: subgroup, name: 'Testproject') - expect(finder.execute).to contain_exactly(subgroup, matching_project) - end + expect(finder.execute).to contain_exactly(subgroup, matching_project) + end - context 'with a small page size' do - let(:params) { { filter: 'test', per_page: 1 } } + context 'with a small page size' do + let(:params) { { filter: 'test', per_page: 1 } } - it 'contains all the ancestors of a matching subgroup regardless the page size' do - subgroup = create(:group, :private, parent: group) - matching = create(:group, :private, name: 'testgroup', parent: subgroup) + it 'contains all the ancestors of a matching subgroup regardless the page size' do + subgroup = create(:group, :private, parent: group) + matching = create(:group, :private, name: 'testgroup', parent: subgroup) - expect(finder.execute).to contain_exactly(subgroup, matching) + expect(finder.execute).to contain_exactly(subgroup, matching) + end end - end - it 'does not include the parent itself' do - group.update!(name: 'test') + it 'does not include the parent itself' do + group.update!(name: 'test') - expect(finder.execute).not_to include(group) + expect(finder.execute).not_to include(group) + end end end end end end + + it_behaves_like 'group descentants finder examples' + + context 'when feature flag :linear_group_descendants_finder is disabled' do + before do + stub_feature_flags(linear_group_descendants_finder: false) + end + + it_behaves_like 'group descentants finder examples' + end end diff --git a/spec/finders/groups_finder_spec.rb b/spec/finders/groups_finder_spec.rb index 10a08d7326e..a4cbee6a124 100644 --- a/spec/finders/groups_finder_spec.rb +++ b/spec/finders/groups_finder_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' RSpec.describe GroupsFinder do include AdminModeHelper - describe '#execute' do + shared_examples '#execute' do let(:user) { create(:user) } describe 'root level groups' do @@ -20,6 +20,7 @@ RSpec.describe GroupsFinder do user_private_group) :regular | { all_available: false } | %i(user_public_group user_internal_group user_private_group) :regular | {} | %i(public_group internal_group user_public_group user_internal_group user_private_group) + :regular | { min_access_level: Gitlab::Access::DEVELOPER } | %i(user_public_group user_internal_group user_private_group) :external | { all_available: true } | %i(public_group user_public_group user_internal_group user_private_group) :external | { all_available: false } | %i(user_public_group user_internal_group user_private_group) @@ -261,4 +262,16 @@ RSpec.describe GroupsFinder do end end end + + describe '#execute' do + include_examples '#execute' + + context 'when use_traversal_ids_groups_finder feature flags is disabled' do + before do + stub_feature_flags(use_traversal_ids_groups_finder: false) + end + + include_examples '#execute' + end + end end diff --git a/spec/finders/issuables/crm_contact_filter_spec.rb b/spec/finders/issuables/crm_contact_filter_spec.rb new file mode 100644 index 00000000000..d6eccab39ad --- /dev/null +++ b/spec/finders/issuables/crm_contact_filter_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Issuables::CrmContactFilter do + let_it_be(:group) { create(:group) } + let_it_be(:project) { create(:project, group: group) } + + let_it_be(:contact1) { create(:contact, group: group) } + let_it_be(:contact2) { create(:contact, group: group) } + + let_it_be(:contact1_issue1) { create(:issue, project: project) } + let_it_be(:contact1_issue2) { create(:issue, project: project) } + let_it_be(:contact2_issue1) { create(:issue, project: project) } + let_it_be(:issues) { Issue.where(id: [contact1_issue1.id, contact1_issue2.id, contact2_issue1.id]) } + + before_all do + create(:issue_customer_relations_contact, issue: contact1_issue1, contact: contact1) + create(:issue_customer_relations_contact, issue: contact1_issue2, contact: contact1) + create(:issue_customer_relations_contact, issue: contact2_issue1, contact: contact2) + end + + describe 'when a contact has issues' do + it 'returns all contact1 issues' do + params = { crm_contact_id: contact1.id } + + expect(described_class.new(params: params).filter(issues)).to contain_exactly(contact1_issue1, contact1_issue2) + end + + it 'returns all contact2 issues' do + params = { crm_contact_id: contact2.id } + + expect(described_class.new(params: params).filter(issues)).to contain_exactly(contact2_issue1) + end + end + + describe 'when a contact has no issues' do + it 'returns no issues' do + contact3 = create(:contact, group: group) + params = { crm_contact_id: contact3.id } + + expect(described_class.new(params: params).filter(issues)).to be_empty + end + end +end diff --git a/spec/finders/issuables/crm_organization_filter_spec.rb b/spec/finders/issuables/crm_organization_filter_spec.rb new file mode 100644 index 00000000000..2a521dcf721 --- /dev/null +++ b/spec/finders/issuables/crm_organization_filter_spec.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Issuables::CrmOrganizationFilter do + let_it_be(:group) { create(:group) } + let_it_be(:project) { create(:project, group: group) } + + let_it_be(:organization1) { create(:organization, group: group) } + let_it_be(:organization2) { create(:organization, group: group) } + let_it_be(:contact1) { create(:contact, group: group, organization: organization1) } + let_it_be(:contact2) { create(:contact, group: group, organization: organization1) } + let_it_be(:contact3) { create(:contact, group: group, organization: organization2) } + + let_it_be(:contact1_issue) { create(:issue, project: project) } + let_it_be(:contact2_issue) { create(:issue, project: project) } + let_it_be(:contact3_issue) { create(:issue, project: project) } + let_it_be(:issues) { Issue.where(id: [contact1_issue.id, contact2_issue.id, contact3_issue.id]) } + + before_all do + create(:issue_customer_relations_contact, issue: contact1_issue, contact: contact1) + create(:issue_customer_relations_contact, issue: contact2_issue, contact: contact2) + create(:issue_customer_relations_contact, issue: contact3_issue, contact: contact3) + end + + describe 'when an organization has issues' do + it 'returns all organization1 issues' do + params = { crm_organization_id: organization1.id } + + expect(described_class.new(params: params).filter(issues)).to contain_exactly(contact1_issue, contact2_issue) + end + + it 'returns all organization2 issues' do + params = { crm_organization_id: organization2.id } + + expect(described_class.new(params: params).filter(issues)).to contain_exactly(contact3_issue) + end + end + + describe 'when an organization has no issues' do + it 'returns no issues' do + organization3 = create(:organization, group: group) + params = { crm_organization_id: organization3.id } + + expect(described_class.new(params: params).filter(issues)).to be_empty + end + end +end diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb index 9f12308013e..31563a6326d 100644 --- a/spec/finders/issues_finder_spec.rb +++ b/spec/finders/issues_finder_spec.rb @@ -910,6 +910,45 @@ RSpec.describe IssuesFinder do end end + context 'filtering by crm contact' do + let_it_be(:contact1) { create(:contact, group: group) } + let_it_be(:contact2) { create(:contact, group: group) } + + let_it_be(:contact1_issue1) { create(:issue, project: project1) } + let_it_be(:contact1_issue2) { create(:issue, project: project1) } + let_it_be(:contact2_issue1) { create(:issue, project: project1) } + + let(:params) { { crm_contact_id: contact1.id } } + + it 'returns for that contact' do + create(:issue_customer_relations_contact, issue: contact1_issue1, contact: contact1) + create(:issue_customer_relations_contact, issue: contact1_issue2, contact: contact1) + create(:issue_customer_relations_contact, issue: contact2_issue1, contact: contact2) + + expect(issues).to contain_exactly(contact1_issue1, contact1_issue2) + end + end + + context 'filtering by crm organization' do + let_it_be(:organization) { create(:organization, group: group) } + let_it_be(:contact1) { create(:contact, group: group, organization: organization) } + let_it_be(:contact2) { create(:contact, group: group, organization: organization) } + + let_it_be(:contact1_issue1) { create(:issue, project: project1) } + let_it_be(:contact1_issue2) { create(:issue, project: project1) } + let_it_be(:contact2_issue1) { create(:issue, project: project1) } + + let(:params) { { crm_organization_id: organization.id } } + + it 'returns for that contact' do + create(:issue_customer_relations_contact, issue: contact1_issue1, contact: contact1) + create(:issue_customer_relations_contact, issue: contact1_issue2, contact: contact1) + create(:issue_customer_relations_contact, issue: contact2_issue1, contact: contact2) + + expect(issues).to contain_exactly(contact1_issue1, contact1_issue2, contact2_issue1) + end + end + context 'when the user is unauthorized' do let(:search_user) { nil } diff --git a/spec/finders/merge_requests_finder_spec.rb b/spec/finders/merge_requests_finder_spec.rb index 42197a6b103..03639bc0b98 100644 --- a/spec/finders/merge_requests_finder_spec.rb +++ b/spec/finders/merge_requests_finder_spec.rb @@ -681,6 +681,18 @@ RSpec.describe MergeRequestsFinder do expect(mrs).to eq([mr1]) end + it 'filters merge requests ignoring empty deployed_before' do + mrs = described_class.new(user, deployed_before: '').execute + + expect(mrs.size).to eq(7) + end + + it 'filters merge requests ignoring invalid deployed_before' do + mrs = described_class.new(user, deployed_before: '2021-99-99').execute + + expect(mrs.size).to eq(7) + end + it 'filters merge requests deployed after a given date' do mrs = described_class .new(user, deployed_after: '2020-10-01 12:00') @@ -688,6 +700,18 @@ RSpec.describe MergeRequestsFinder do expect(mrs).to eq([mr2]) end + + it 'filters merge requests ignoring empty deployed_after' do + mrs = described_class.new(user, deployed_after: '').execute + + expect(mrs.size).to eq(7) + end + + it 'filters merge requests ignoring invalid deployed_after' do + mrs = described_class.new(user, deployed_after: '2021-99-99').execute + + expect(mrs.size).to eq(7) + end end it 'does not raise any exception with complex filters' do diff --git a/spec/finders/packages/build_infos_finder_spec.rb b/spec/finders/packages/build_infos_finder_spec.rb new file mode 100644 index 00000000000..23425de4316 --- /dev/null +++ b/spec/finders/packages/build_infos_finder_spec.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ::Packages::BuildInfosFinder do + using RSpec::Parameterized::TableSyntax + + let_it_be(:package) { create(:package) } + let_it_be(:build_infos) { create_list(:package_build_info, 5, :with_pipeline, package: package) } + let_it_be(:build_info_with_empty_pipeline) { create(:package_build_info, package: package) } + + let(:finder) { described_class.new(package, params) } + let(:params) do + { + first: first, + last: last, + after: after, + before: before, + max_page_size: max_page_size, + support_next_page: support_next_page + } + end + + describe '#execute' do + subject { finder.execute } + + where(:first, :last, :after_index, :before_index, :max_page_size, :support_next_page, :expected_build_infos_indexes) do + # F L AI BI MPS SNP + nil | nil | nil | nil | nil | false | [4, 3, 2, 1, 0] + nil | nil | nil | nil | 10 | false | [4, 3, 2, 1, 0] + nil | nil | nil | nil | 2 | false | [4, 3] + 2 | nil | nil | nil | nil | false | [4, 3] + 2 | nil | nil | nil | nil | true | [4, 3, 2] + 2 | nil | 3 | nil | nil | false | [2, 1] + 2 | nil | 3 | nil | nil | true | [2, 1, 0] + 3 | nil | 4 | nil | 2 | false | [3, 2] + 3 | nil | 4 | nil | 2 | true | [3, 2, 1] + nil | 2 | nil | nil | nil | false | [0, 1] + nil | 2 | nil | nil | nil | true | [0, 1, 2] + nil | 2 | nil | 1 | nil | false | [2, 3] + nil | 2 | nil | 1 | nil | true | [2, 3, 4] + nil | 3 | nil | 0 | 2 | false | [1, 2] + nil | 3 | nil | 0 | 2 | true | [1, 2, 3] + end + + with_them do + let(:expected_build_infos) do + expected_build_infos_indexes.map do |idx| + build_infos[idx] + end + end + + let(:after) do + build_infos[after_index].pipeline_id if after_index + end + + let(:before) do + build_infos[before_index].pipeline_id if before_index + end + + it { is_expected.to eq(expected_build_infos) } + end + end +end diff --git a/spec/finders/packages/group_packages_finder_spec.rb b/spec/finders/packages/group_packages_finder_spec.rb index 3254c436674..c2dbfb59eb2 100644 --- a/spec/finders/packages/group_packages_finder_spec.rb +++ b/spec/finders/packages/group_packages_finder_spec.rb @@ -107,6 +107,28 @@ RSpec.describe Packages::GroupPackagesFinder do end end + context 'deploy tokens' do + let(:add_user_to_group) { false } + + context 'group deploy token' do + let_it_be(:deploy_token_for_group) { create(:deploy_token, :group, read_package_registry: true) } + let_it_be(:group_deploy_token) { create(:group_deploy_token, deploy_token: deploy_token_for_group, group: group) } + + let(:user) { deploy_token_for_group } + + it { is_expected.to match_array([package1, package2, package4]) } + end + + context 'project deploy token' do + let_it_be(:deploy_token_for_project) { create(:deploy_token, read_package_registry: true) } + let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token_for_project, project: subproject) } + + let(:user) { deploy_token_for_project } + + it { is_expected.to match_array([package4]) } + end + end + context 'avoid N+1 query' do it 'avoids N+1 database queries' do count = ActiveRecord::QueryRecorder.new { subject } diff --git a/spec/finders/packages/nuget/package_finder_spec.rb b/spec/finders/packages/nuget/package_finder_spec.rb index 4ad02ce7da8..045dba295ac 100644 --- a/spec/finders/packages/nuget/package_finder_spec.rb +++ b/spec/finders/packages/nuget/package_finder_spec.rb @@ -71,7 +71,7 @@ RSpec.describe Packages::Nuget::PackageFinder do end context 'with prefix wildcard' do - let(:package_name) { "%#{package1.name[3..-1]}" } + let(:package_name) { "%#{package1.name[3..]}" } it { is_expected.to match_array([package1, package2]) } end diff --git a/spec/finders/personal_projects_finder_spec.rb b/spec/finders/personal_projects_finder_spec.rb index 493ec0e569e..af3b5bf894b 100644 --- a/spec/finders/personal_projects_finder_spec.rb +++ b/spec/finders/personal_projects_finder_spec.rb @@ -3,14 +3,16 @@ require 'spec_helper' RSpec.describe PersonalProjectsFinder do - let(:source_user) { create(:user) } - let(:current_user) { create(:user) } - let(:finder) { described_class.new(source_user) } + let_it_be(:source_user) { create(:user) } + let_it_be(:current_user) { create(:user) } + let_it_be(:admin) { create(:admin) } + + let(:finder) { described_class.new(source_user) } let!(:public_project) do - create(:project, :public, namespace: source_user.namespace, updated_at: 1.hour.ago) + create(:project, :public, namespace: source_user.namespace, updated_at: 1.hour.ago, path: 'pblc') end - let!(:private_project) do + let!(:private_project_shared) do create(:project, :private, namespace: source_user.namespace, updated_at: 3.hours.ago, path: 'mepmep') end @@ -18,8 +20,12 @@ RSpec.describe PersonalProjectsFinder do create(:project, :internal, namespace: source_user.namespace, updated_at: 2.hours.ago, path: 'C') end + let!(:private_project_self) do + create(:project, :private, namespace: source_user.namespace, updated_at: 3.hours.ago, path: 'D') + end + before do - private_project.add_developer(current_user) + private_project_shared.add_developer(current_user) end describe 'without a current user' do @@ -29,18 +35,26 @@ RSpec.describe PersonalProjectsFinder do end describe 'with a current user' do - subject { finder.execute(current_user) } - context 'normal user' do - it { is_expected.to eq([public_project, internal_project, private_project]) } + subject { finder.execute(current_user) } + + it { is_expected.to match_array([public_project, internal_project, private_project_shared]) } end context 'external' do + subject { finder.execute(current_user) } + before do current_user.update!(external: true) end - it { is_expected.to eq([public_project, private_project]) } + it { is_expected.to match_array([public_project, private_project_shared]) } + end + + context 'and searching with an admin user', :enable_admin_mode do + subject { finder.execute(admin) } + + it { is_expected.to match_array([public_project, internal_project, private_project_self, private_project_shared]) } end end end diff --git a/spec/finders/user_group_notification_settings_finder_spec.rb b/spec/finders/user_group_notification_settings_finder_spec.rb index b9d800d8e55..ea44688bc8d 100644 --- a/spec/finders/user_group_notification_settings_finder_spec.rb +++ b/spec/finders/user_group_notification_settings_finder_spec.rb @@ -11,155 +11,167 @@ RSpec.describe UserGroupNotificationSettingsFinder do subject.map(&proc).uniq end - context 'when the groups have no existing notification settings' do - context 'when the groups have no ancestors' do - let_it_be(:groups) { create_list(:group, 3) } - - it 'will be a default Global notification setting', :aggregate_failures do - expect(subject.count).to eq(3) - expect(attributes(&:notification_email)).to eq([nil]) - expect(attributes(&:level)).to eq(['global']) + shared_examples 'user group notifications settings tests' do + context 'when the groups have no existing notification settings' do + context 'when the groups have no ancestors' do + let_it_be(:groups) { create_list(:group, 3) } + + it 'will be a default Global notification setting', :aggregate_failures do + expect(subject.count).to eq(3) + expect(attributes(&:notification_email)).to match_array([nil]) + expect(attributes(&:level)).to match_array(['global']) + end end - end - context 'when the groups have ancestors' do - context 'when an ancestor has a level other than Global' do - let_it_be(:ancestor_a) { create(:group) } - let_it_be(:group_a) { create(:group, parent: ancestor_a) } - let_it_be(:ancestor_b) { create(:group) } - let_it_be(:group_b) { create(:group, parent: ancestor_b) } - let_it_be(:email) { create(:email, :confirmed, email: 'ancestor@example.com', user: user) } + context 'when the groups have ancestors' do + context 'when an ancestor has a level other than Global' do + let_it_be(:ancestor_a) { create(:group) } + let_it_be(:group_a) { create(:group, parent: ancestor_a) } + let_it_be(:ancestor_b) { create(:group) } + let_it_be(:group_b) { create(:group, parent: ancestor_b) } + let_it_be(:email) { create(:email, :confirmed, email: 'ancestor@example.com', user: user) } - let_it_be(:groups) { [group_a, group_b] } + let_it_be(:groups) { [group_a, group_b] } - before do - create(:notification_setting, user: user, source: ancestor_a, level: 'participating', notification_email: email.email) - create(:notification_setting, user: user, source: ancestor_b, level: 'participating', notification_email: email.email) - end + before do + create(:notification_setting, user: user, source: ancestor_a, level: 'participating', notification_email: email.email) + create(:notification_setting, user: user, source: ancestor_b, level: 'participating', notification_email: email.email) + end - it 'has the same level set' do - expect(attributes(&:level)).to eq(['participating']) - end + it 'has the same level set' do + expect(attributes(&:level)).to match_array(['participating']) + end - it 'has the same email set' do - expect(attributes(&:notification_email)).to eq(['ancestor@example.com']) + it 'has the same email set' do + expect(attributes(&:notification_email)).to match_array(['ancestor@example.com']) + end + + it 'only returns the two queried groups' do + expect(subject.count).to eq(2) + end end - it 'only returns the two queried groups' do - expect(subject.count).to eq(2) + context 'when an ancestor has a Global level but has an email set' do + let_it_be(:grand_ancestor) { create(:group) } + let_it_be(:ancestor) { create(:group, parent: grand_ancestor) } + let_it_be(:group) { create(:group, parent: ancestor) } + let_it_be(:ancestor_email) { create(:email, :confirmed, email: 'ancestor@example.com', user: user) } + let_it_be(:grand_email) { create(:email, :confirmed, email: 'grand@example.com', user: user) } + + let_it_be(:groups) { [group] } + + before do + create(:notification_setting, user: user, source: grand_ancestor, level: 'participating', notification_email: grand_email.email) + create(:notification_setting, user: user, source: ancestor, level: 'global', notification_email: ancestor_email.email) + end + + it 'has the same email and level set', :aggregate_failures do + expect(subject.count).to eq(1) + expect(attributes(&:level)).to match_array(['global']) + expect(attributes(&:notification_email)).to match_array(['ancestor@example.com']) + end end - end - context 'when an ancestor has a Global level but has an email set' do - let_it_be(:grand_ancestor) { create(:group) } - let_it_be(:ancestor) { create(:group, parent: grand_ancestor) } - let_it_be(:group) { create(:group, parent: ancestor) } - let_it_be(:ancestor_email) { create(:email, :confirmed, email: 'ancestor@example.com', user: user) } - let_it_be(:grand_email) { create(:email, :confirmed, email: 'grand@example.com', user: user) } + context 'when the group has parent_id set but that does not belong to any group' do + let_it_be(:group) { create(:group) } + let_it_be(:groups) { [group] } - let_it_be(:groups) { [group] } + before do + # Let's set a parent_id for a group that definitely doesn't exist + group.update_columns(parent_id: 19283746) + end - before do - create(:notification_setting, user: user, source: grand_ancestor, level: 'participating', notification_email: grand_email.email) - create(:notification_setting, user: user, source: ancestor, level: 'global', notification_email: ancestor_email.email) + it 'returns a default Global notification setting' do + expect(subject.count).to eq(1) + expect(attributes(&:level)).to match_array(['global']) + expect(attributes(&:notification_email)).to match_array([nil]) + end end - it 'has the same email and level set', :aggregate_failures do - expect(subject.count).to eq(1) - expect(attributes(&:level)).to eq(['global']) - expect(attributes(&:notification_email)).to eq(['ancestor@example.com']) + context 'when the group has a private parent' do + let_it_be(:ancestor) { create(:group, :private) } + let_it_be(:group) { create(:group, :private, parent: ancestor) } + let_it_be(:ancestor_email) { create(:email, :confirmed, email: 'ancestor@example.com', user: user) } + let_it_be(:groups) { [group] } + + before do + group.add_reporter(user) + # Adding the user creates a NotificationSetting, so we remove it here + user.notification_settings.where(source: group).delete_all + + create(:notification_setting, user: user, source: ancestor, level: 'participating', notification_email: ancestor_email.email) + end + + it 'still inherits the notification settings' do + expect(subject.count).to eq(1) + expect(attributes(&:level)).to match_array(['participating']) + expect(attributes(&:notification_email)).to match_array([ancestor_email.email]) + end end - end - context 'when the group has parent_id set but that does not belong to any group' do - let_it_be(:group) { create(:group) } - let_it_be(:groups) { [group] } + it 'does not cause an N+1', :aggregate_failures do + parent = create(:group) + child = create(:group, parent: parent) - before do - # Let's set a parent_id for a group that definitely doesn't exist - group.update_columns(parent_id: 19283746) - end + control = ActiveRecord::QueryRecorder.new do + described_class.new(user, Group.where(id: child.id)).execute + end - it 'returns a default Global notification setting' do - expect(subject.count).to eq(1) - expect(attributes(&:level)).to eq(['global']) - expect(attributes(&:notification_email)).to eq([nil]) - end - end + other_parent = create(:group) + other_children = create_list(:group, 2, parent: other_parent) - context 'when the group has a private parent' do - let_it_be(:ancestor) { create(:group, :private) } - let_it_be(:group) { create(:group, :private, parent: ancestor) } - let_it_be(:ancestor_email) { create(:email, :confirmed, email: 'ancestor@example.com', user: user) } - let_it_be(:groups) { [group] } + result = nil - before do - group.add_reporter(user) - # Adding the user creates a NotificationSetting, so we remove it here - user.notification_settings.where(source: group).delete_all - - create(:notification_setting, user: user, source: ancestor, level: 'participating', notification_email: ancestor_email.email) - end + expect do + result = described_class.new(user, Group.where(id: other_children.append(child).map(&:id))).execute + end.not_to exceed_query_limit(control) - it 'still inherits the notification settings' do - expect(subject.count).to eq(1) - expect(attributes(&:level)).to eq(['participating']) - expect(attributes(&:notification_email)).to eq([ancestor_email.email]) + expect(result.count).to eq(3) end end + end - it 'does not cause an N+1', :aggregate_failures do - parent = create(:group) - child = create(:group, parent: parent) - - control = ActiveRecord::QueryRecorder.new do - described_class.new(user, Group.where(id: child.id)).execute - end + context 'preloading `emails_disabled`' do + let_it_be(:root_group) { create(:group) } + let_it_be(:sub_group) { create(:group, parent: root_group) } + let_it_be(:sub_sub_group) { create(:group, parent: sub_group) } - other_parent = create(:group) - other_children = create_list(:group, 2, parent: other_parent) + let_it_be(:another_root_group) { create(:group) } + let_it_be(:sub_group_with_emails_disabled) { create(:group, emails_disabled: true, parent: another_root_group) } + let_it_be(:another_sub_sub_group) { create(:group, parent: sub_group_with_emails_disabled) } - result = nil + let_it_be(:root_group_with_emails_disabled) { create(:group, emails_disabled: true) } + let_it_be(:group) { create(:group, parent: root_group_with_emails_disabled) } - expect do - result = described_class.new(user, Group.where(id: other_children.append(child).map(&:id))).execute - end.not_to exceed_query_limit(control) + let(:groups) { Group.where(id: [sub_sub_group, another_sub_sub_group, group]) } - expect(result.count).to eq(3) + before do + described_class.new(user, groups).execute end - end - end - - context 'preloading `emails_disabled`' do - let_it_be(:root_group) { create(:group) } - let_it_be(:sub_group) { create(:group, parent: root_group) } - let_it_be(:sub_sub_group) { create(:group, parent: sub_group) } - - let_it_be(:another_root_group) { create(:group) } - let_it_be(:sub_group_with_emails_disabled) { create(:group, emails_disabled: true, parent: another_root_group) } - let_it_be(:another_sub_sub_group) { create(:group, parent: sub_group_with_emails_disabled) } - let_it_be(:root_group_with_emails_disabled) { create(:group, emails_disabled: true) } - let_it_be(:group) { create(:group, parent: root_group_with_emails_disabled) } + it 'preloads the `group.emails_disabled` method' do + recorder = ActiveRecord::QueryRecorder.new do + groups.each(&:emails_disabled?) + end - let(:groups) { Group.where(id: [sub_sub_group, another_sub_sub_group, group]) } + expect(recorder.count).to eq(0) + end - before do - described_class.new(user, groups).execute + it 'preloads the `group.emails_disabled` method correctly' do + groups.each do |group| + expect(group.emails_disabled?).to eq(Group.find(group.id).emails_disabled?) # compare the memoized and the freshly loaded value + end + end end + end - it 'preloads the `group.emails_disabled` method' do - recorder = ActiveRecord::QueryRecorder.new do - groups.each(&:emails_disabled?) - end + it_behaves_like 'user group notifications settings tests' - expect(recorder.count).to eq(0) + context 'when feature flag :linear_user_group_notification_settings_finder_ancestors_scopes is disabled' do + before do + stub_feature_flags(linear_user_group_notification_settings_finder_ancestors_scopes: false) end - it 'preloads the `group.emails_disabled` method correctly' do - groups.each do |group| - expect(group.emails_disabled?).to eq(Group.find(group.id).emails_disabled?) # compare the memoized and the freshly loaded value - end - end + it_behaves_like 'user group notifications settings tests' end end |