diff options
Diffstat (limited to 'spec/finders')
-rw-r--r-- | spec/finders/crm/contacts_finder_spec.rb | 96 | ||||
-rw-r--r-- | spec/finders/crm/organizations_finder_spec.rb | 132 | ||||
-rw-r--r-- | spec/finders/issues_finder_spec.rb | 1448 | ||||
-rw-r--r-- | spec/finders/packages/pypi/packages_finder_spec.rb | 94 | ||||
-rw-r--r-- | spec/finders/work_items/work_items_finder_spec.rb | 10 |
5 files changed, 292 insertions, 1488 deletions
diff --git a/spec/finders/crm/contacts_finder_spec.rb b/spec/finders/crm/contacts_finder_spec.rb index 151af1ad825..dd5274a0574 100644 --- a/spec/finders/crm/contacts_finder_spec.rb +++ b/spec/finders/crm/contacts_finder_spec.rb @@ -26,16 +26,6 @@ RSpec.describe Crm::ContactsFinder do root_group.add_developer(user) end - context 'when feature flag is disabled' do - before do - stub_feature_flags(customer_relations: false) - end - - it 'returns an empty array' do - expect(subject).to be_empty - end - end - context 'when feature flag is enabled' do it 'returns all group contacts' do expect(subject).to match_array([contact_1, contact_2]) @@ -66,5 +56,91 @@ RSpec.describe Crm::ContactsFinder do expect(subject).to be_empty end end + + context 'with search informations' do + let_it_be(:search_test_group) { create(:group, :crm_enabled) } + + let_it_be(:search_test_a) do + create( + :contact, + group: search_test_group, + first_name: "ABC", + last_name: "DEF", + email: "ghi@test.com", + description: "LMNO", + state: "inactive" + ) + end + + let_it_be(:search_test_b) do + create( + :contact, + group: search_test_group, + first_name: "PQR", + last_name: "STU", + email: "vwx@test.com", + description: "YZ", + state: "active" + ) + end + + before do + search_test_group.add_developer(user) + end + + context 'when search term is empty' do + it 'returns all group contacts alphabetically ordered' do + finder = described_class.new(user, group: search_test_group, search: "") + expect(finder.execute).to eq([search_test_a, search_test_b]) + end + end + + context 'when search term is not empty' do + it 'searches for first name ignoring casing' do + finder = described_class.new(user, group: search_test_group, search: "aBc") + expect(finder.execute).to match_array([search_test_a]) + end + + it 'searches for last name ignoring casing' do + finder = described_class.new(user, group: search_test_group, search: "StU") + expect(finder.execute).to match_array([search_test_b]) + end + + it 'searches for email' do + finder = described_class.new(user, group: search_test_group, search: "ghi") + expect(finder.execute).to match_array([search_test_a]) + end + + it 'searches for description ignoring casing' do + finder = described_class.new(user, group: search_test_group, search: "Yz") + expect(finder.execute).to match_array([search_test_b]) + end + + it 'fuzzy searches for email and last name' do + finder = described_class.new(user, group: search_test_group, search: "s") + expect(finder.execute).to match_array([search_test_a, search_test_b]) + end + end + + context 'when searching for contacts state' do + it 'returns only inactive contacts' do + finder = described_class.new(user, group: search_test_group, state: :inactive) + expect(finder.execute).to match_array([search_test_a]) + end + + it 'returns only active contacts' do + finder = described_class.new(user, group: search_test_group, state: :active) + expect(finder.execute).to match_array([search_test_b]) + end + end + + context 'when searching for contacts ids' do + it 'returns the expected contacts' do + finder = described_class.new(user, group: search_test_group, ids: [search_test_b.id]) + + expect(finder.execute).to match_array([search_test_b]) + end + end + end end end diff --git a/spec/finders/crm/organizations_finder_spec.rb b/spec/finders/crm/organizations_finder_spec.rb new file mode 100644 index 00000000000..f227fcd3748 --- /dev/null +++ b/spec/finders/crm/organizations_finder_spec.rb @@ -0,0 +1,132 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Crm::OrganizationsFinder do + let_it_be(:user) { create(:user) } + + describe '#execute' do + subject { described_class.new(user, group: group).execute } + + context 'when customer relations feature is enabled for the group' do + let_it_be(:root_group) { create(:group, :crm_enabled) } + let_it_be(:group) { create(:group, parent: root_group) } + + let_it_be(:organization_1) { create(:organization, group: root_group) } + let_it_be(:organization_2) { create(:organization, group: root_group) } + + context 'when user does not have permissions to see organizations in the group' do + it 'returns an empty array' do + expect(subject).to be_empty + end + end + + context 'when user is member of the root group' do + before do + root_group.add_developer(user) + end + + context 'when feature flag is enabled' do + it 'returns all group organizations' do + expect(subject).to match_array([organization_1, organization_2]) + end + end + end + + context 'when user is member of the sub group' do + before do + group.add_developer(user) + end + + it 'returns an empty array' do + expect(subject).to be_empty + end + end + end + + context 'when customer relations feature is disabled for the group' do + let_it_be(:group) { create(:group) } + let_it_be(:organization) { create(:organization, group: group) } + + before do + group.add_developer(user) + end + + it 'returns an empty array' do + expect(subject).to be_empty + end + end + + context 'with search informations' do + let_it_be(:search_test_group) { create(:group, :crm_enabled) } + + let_it_be(:search_test_a) do + create( + :organization, + group: search_test_group, + name: "DEF", + description: "ghi_st", + state: "inactive" + ) + end + + let_it_be(:search_test_b) do + create( + :organization, + group: search_test_group, + name: "ABC_st", + description: "JKL", + state: "active" + ) + end + + before do + search_test_group.add_developer(user) + end + + context 'when search term is empty' do + it 'returns all group organizations alphabetically ordered' do + finder = described_class.new(user, group: search_test_group, search: "") + expect(finder.execute).to eq([search_test_b, search_test_a]) + end + end + + context 'when search term is not empty' do + it 'searches for name' do + finder = described_class.new(user, group: search_test_group, search: "aBc") + expect(finder.execute).to match_array([search_test_b]) + end + + it 'searches for description' do + finder = described_class.new(user, group: search_test_group, search: "ghI") + expect(finder.execute).to match_array([search_test_a]) + end + + it 'searches for name and description' do + finder = described_class.new(user, group: search_test_group, search: "_st") + expect(finder.execute).to eq([search_test_b, search_test_a]) + end + end + + context 'when searching for organizations state' do + it 'returns only inactive organizations' do + finder = described_class.new(user, group: search_test_group, state: :inactive) + expect(finder.execute).to match_array([search_test_a]) + end + + it 'returns only active organizations' do + finder = described_class.new(user, group: search_test_group, state: :active) + expect(finder.execute).to match_array([search_test_b]) + end + end + + context 'when searching for organizations ids' do + it 'returns the expected organizations' do + finder = described_class.new(user, group: search_test_group, ids: [search_test_a.id]) + + expect(finder.execute).to match_array([search_test_a]) + end + end + end + end +end diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb index 3f5a55410d2..704171a737b 100644 --- a/spec/finders/issues_finder_spec.rb +++ b/spec/finders/issues_finder_spec.rb @@ -3,1453 +3,7 @@ require 'spec_helper' RSpec.describe IssuesFinder do - using RSpec::Parameterized::TableSyntax include_context 'IssuesFinder context' - describe '#execute' do - include_context 'IssuesFinder#execute context' - - context 'scope: all' do - let(:scope) { 'all' } - - it 'returns all issues' do - expect(issues).to contain_exactly(issue1, issue2, issue3, issue4, issue5) - end - - context 'user does not have read permissions' do - let(:search_user) { user2 } - - context 'when filtering by project id' do - let(:params) { { project_id: project1.id } } - - it 'returns no issues' do - expect(issues).to be_empty - end - end - - context 'when filtering by group id' do - let(:params) { { group_id: group.id } } - - it 'returns no issues' do - expect(issues).to be_empty - end - end - end - - context 'assignee filtering' do - let(:issuables) { issues } - - it_behaves_like 'assignee ID filter' do - let(:params) { { assignee_id: user.id } } - let(:expected_issuables) { [issue1, issue2, issue5] } - end - - it_behaves_like 'assignee NOT ID filter' do - let(:params) { { not: { assignee_id: user.id } } } - let(:expected_issuables) { [issue3, issue4] } - end - - it_behaves_like 'assignee OR filter' do - let(:params) { { or: { assignee_id: [user.id, user2.id] } } } - let(:expected_issuables) { [issue1, issue2, issue3, issue5] } - end - - context 'when assignee_id does not exist' do - it_behaves_like 'assignee NOT ID filter' do - let(:params) { { not: { assignee_id: -100 } } } - let(:expected_issuables) { [issue1, issue2, issue3, issue4, issue5] } - end - end - - context 'filter by username' do - let_it_be(:user3) { create(:user) } - - before do - project2.add_developer(user3) - issue2.assignees = [user2] - issue3.assignees = [user3] - end - - it_behaves_like 'assignee username filter' do - let(:params) { { assignee_username: [user2.username] } } - let(:expected_issuables) { [issue2] } - end - - it_behaves_like 'assignee NOT username filter' do - before do - issue2.assignees = [user2] - end - - let(:params) { { not: { assignee_username: [user.username, user2.username] } } } - let(:expected_issuables) { [issue3, issue4] } - end - - it_behaves_like 'assignee OR filter' do - let(:params) { { or: { assignee_username: [user2.username, user3.username] } } } - let(:expected_issuables) { [issue2, issue3] } - end - - context 'when assignee_username does not exist' do - it_behaves_like 'assignee NOT username filter' do - before do - issue2.assignees = [user2] - end - - let(:params) { { not: { assignee_username: 'non_existent_username' } } } - let(:expected_issuables) { [issue1, issue2, issue3, issue4, issue5] } - end - end - end - - it_behaves_like 'no assignee filter' do - let_it_be(:user3) { create(:user) } - let(:expected_issuables) { [issue4] } - end - - it_behaves_like 'any assignee filter' do - let(:expected_issuables) { [issue1, issue2, issue3, issue5] } - end - end - - context 'filtering by release' do - context 'when the release tag is none' do - let(:params) { { release_tag: 'none' } } - - it 'returns issues without releases' do - expect(issues).to contain_exactly(issue2, issue3, issue4, issue5) - end - end - - context 'when the release tag exists' do - let(:params) { { project_id: project1.id, release_tag: release.tag } } - - it 'returns the issues associated with that release' do - expect(issues).to contain_exactly(issue1) - end - end - end - - context 'filtering by projects' do - context 'when projects are passed in a list of ids' do - let(:params) { { projects: [project1.id] } } - - it 'returns the issue belonging to the projects' do - expect(issues).to contain_exactly(issue1, issue5) - end - end - - context 'when projects are passed in a subquery' do - let(:params) { { projects: Project.id_in(project1.id) } } - - it 'returns the issue belonging to the projects' do - expect(issues).to contain_exactly(issue1, issue5) - end - end - end - - context 'filtering by group_id' do - let(:params) { { group_id: group.id } } - - context 'when include_subgroup param not set' do - it 'returns all group issues' do - expect(issues).to contain_exactly(issue1, issue5) - end - - context 'when projects outside the group are passed' do - let(:params) { { group_id: group.id, projects: [project2.id] } } - - it 'returns no issues' do - expect(issues).to be_empty - end - end - - context 'when projects of the group are passed' do - let(:params) { { group_id: group.id, projects: [project1.id] } } - - it 'returns the issue within the group and projects' do - expect(issues).to contain_exactly(issue1, issue5) - end - end - - context 'when projects of the group are passed as a subquery' do - let(:params) { { group_id: group.id, projects: Project.id_in(project1.id) } } - - it 'returns the issue within the group and projects' do - expect(issues).to contain_exactly(issue1, issue5) - end - end - - context 'when release_tag is passed as a parameter' do - let(:params) { { group_id: group.id, release_tag: 'dne-release-tag' } } - - it 'ignores the release_tag parameter' do - expect(issues).to contain_exactly(issue1, issue5) - end - end - end - - context 'when include_subgroup param is true' do - before do - params[:include_subgroups] = true - end - - it 'returns all group and subgroup issues' do - expect(issues).to contain_exactly(issue1, issue4, issue5) - end - - context 'when mixed projects are passed' do - let(:params) { { group_id: group.id, projects: [project2.id, project3.id] } } - - it 'returns the issue within the group and projects' do - expect(issues).to contain_exactly(issue4) - end - end - end - end - - context 'filtering by author' do - context 'by author ID' do - let(:params) { { author_id: user2.id } } - - it 'returns issues created by that user' do - expect(issues).to contain_exactly(issue3) - end - end - - context 'using OR' do - let(:issue6) { create(:issue, project: project2) } - let(:params) { { or: { author_username: [issue3.author.username, issue6.author.username] } } } - - it 'returns issues created by any of the given users' do - expect(issues).to contain_exactly(issue3, issue6) - end - - context 'when feature flag is disabled' do - before do - stub_feature_flags(or_issuable_queries: false) - end - - it 'does not add any filter' do - expect(issues).to contain_exactly(issue1, issue2, issue3, issue4, issue5, issue6) - end - end - end - - context 'filtering by NOT author ID' do - let(:params) { { not: { author_id: user2.id } } } - - it 'returns issues not created by that user' do - expect(issues).to contain_exactly(issue1, issue2, issue4, issue5) - end - end - - context 'filtering by nonexistent author ID and issue term using CTE for search' do - let(:params) do - { - author_id: 'does-not-exist', - search: 'git', - attempt_group_search_optimizations: true - } - end - - it 'returns no results' do - expect(issues).to be_empty - end - end - end - - context 'filtering by milestone' do - let(:params) { { milestone_title: milestone.title } } - - it 'returns issues assigned to that milestone' do - expect(issues).to contain_exactly(issue1) - end - end - - context 'filtering by not milestone' do - let(:params) { { not: { milestone_title: milestone.title } } } - - it 'returns issues not assigned to that milestone' do - expect(issues).to contain_exactly(issue2, issue3, issue4, issue5) - end - end - - context 'filtering by group milestone' do - let!(:group) { create(:group, :public) } - let(:group_milestone) { create(:milestone, group: group) } - let!(:group_member) { create(:group_member, group: group, user: user) } - let(:params) { { milestone_title: group_milestone.title } } - - before do - project2.update!(namespace: group) - issue2.update!(milestone: group_milestone) - issue3.update!(milestone: group_milestone) - end - - it 'returns issues assigned to that group milestone' do - expect(issues).to contain_exactly(issue2, issue3) - end - - context 'using NOT' do - let(:params) { { not: { milestone_title: group_milestone.title } } } - - it 'returns issues not assigned to that group milestone' do - expect(issues).to contain_exactly(issue1, issue4, issue5) - end - end - end - - context 'filtering by no milestone' do - let(:params) { { milestone_title: 'None' } } - - it 'returns issues with no milestone' do - expect(issues).to contain_exactly(issue2, issue3, issue4, issue5) - end - - it 'returns issues with no milestone (deprecated)' do - params[:milestone_title] = Milestone::None.title - - expect(issues).to contain_exactly(issue2, issue3, issue4, issue5) - end - end - - context 'filtering by any milestone' do - let(:params) { { milestone_title: 'Any' } } - - it 'returns issues with any assigned milestone' do - expect(issues).to contain_exactly(issue1) - end - - it 'returns issues with any assigned milestone (deprecated)' do - params[:milestone_title] = Milestone::Any.title - - expect(issues).to contain_exactly(issue1) - end - end - - context 'filtering by upcoming milestone' do - let(:params) { { milestone_title: Milestone::Upcoming.name } } - - let!(:group) { create(:group, :public) } - let!(:group_member) { create(:group_member, group: group, user: user) } - - let(:project_no_upcoming_milestones) { create(:project, :public) } - let(:project_next_1_1) { create(:project, :public) } - let(:project_next_8_8) { create(:project, :public) } - let(:project_in_group) { create(:project, :public, namespace: group) } - - let(:yesterday) { Date.current - 1.day } - let(:tomorrow) { Date.current + 1.day } - let(:two_days_from_now) { Date.current + 2.days } - let(:ten_days_from_now) { Date.current + 10.days } - - let(:milestones) do - [ - create(:milestone, :closed, project: project_no_upcoming_milestones), - create(:milestone, project: project_next_1_1, title: '1.1', due_date: two_days_from_now), - create(:milestone, project: project_next_1_1, title: '8.9', due_date: ten_days_from_now), - create(:milestone, project: project_next_8_8, title: '1.2', due_date: yesterday), - create(:milestone, project: project_next_8_8, title: '8.8', due_date: tomorrow), - create(:milestone, group: group, title: '9.9', due_date: tomorrow) - ] - end - - before do - @created_issues = milestones.map do |milestone| - create(:issue, project: milestone.project || project_in_group, milestone: milestone, author: user, assignees: [user]) - end - end - - it 'returns issues in the upcoming milestone for each project or group' do - expect(issues.map { |issue| issue.milestone.title }).to contain_exactly('1.1', '8.8', '9.9') - expect(issues.map { |issue| issue.milestone.due_date }).to contain_exactly(tomorrow, two_days_from_now, tomorrow) - end - - context 'using NOT' do - let(:params) { { not: { milestone_title: Milestone::Upcoming.name } } } - - it 'returns issues not in upcoming milestones for each project or group, but must have a due date' do - target_issues = @created_issues.select do |issue| - issue.milestone&.due_date && issue.milestone.due_date <= Date.current - end - - expect(issues).to contain_exactly(*target_issues) - end - end - end - - context 'filtering by started milestone' do - let(:params) { { milestone_title: Milestone::Started.name } } - - let(:project_no_started_milestones) { create(:project, :public) } - let(:project_started_1_and_2) { create(:project, :public) } - let(:project_started_8) { create(:project, :public) } - - let(:yesterday) { Date.current - 1.day } - let(:tomorrow) { Date.current + 1.day } - let(:two_days_ago) { Date.current - 2.days } - let(:three_days_ago) { Date.current - 3.days } - - let(:milestones) do - [ - create(:milestone, project: project_no_started_milestones, start_date: tomorrow), - create(:milestone, project: project_started_1_and_2, title: '1.0', start_date: two_days_ago), - create(:milestone, project: project_started_1_and_2, title: '2.0', start_date: yesterday), - create(:milestone, project: project_started_1_and_2, title: '3.0', start_date: tomorrow), - create(:milestone, :closed, project: project_started_1_and_2, title: '4.0', start_date: three_days_ago), - create(:milestone, :closed, project: project_started_8, title: '6.0', start_date: three_days_ago), - create(:milestone, project: project_started_8, title: '7.0'), - create(:milestone, project: project_started_8, title: '8.0', start_date: yesterday), - create(:milestone, project: project_started_8, title: '9.0', start_date: tomorrow) - ] - end - - before do - milestones.each do |milestone| - create(:issue, project: milestone.project, milestone: milestone, author: user, assignees: [user]) - end - end - - it 'returns issues in the started milestones for each project' do - expect(issues.map { |issue| issue.milestone.title }).to contain_exactly('1.0', '2.0', '8.0') - expect(issues.map { |issue| issue.milestone.start_date }).to contain_exactly(two_days_ago, yesterday, yesterday) - end - - context 'using NOT' do - let(:params) { { not: { milestone_title: Milestone::Started.name } } } - - it 'returns issues not in the started milestones for each project' do - target_issues = Issue.where(milestone: Milestone.not_started) - - expect(issues).to contain_exactly(*target_issues) - end - end - end - - context 'filtering by label' do - let(:params) { { label_name: label.title } } - - it 'returns issues with that label' do - expect(issues).to contain_exactly(issue2) - end - - context 'using NOT' do - let(:params) { { not: { label_name: label.title } } } - - it 'returns issues that do not have that label' do - expect(issues).to contain_exactly(issue1, issue3, issue4, issue5) - end - - # IssuableFinder first filters using the outer params (the ones not inside the `not` key.) - # Afterwards, it applies the `not` params to that resultset. This means that things inside the `not` param - # do not take precedence over the outer params with the same name. - context 'shadowing the same outside param' do - let(:params) { { label_name: label2.title, not: { label_name: label.title } } } - - it 'does not take precedence over labels outside NOT' do - expect(issues).to contain_exactly(issue3) - end - end - - context 'further filtering outside params' do - let(:params) { { label_name: label2.title, not: { assignee_username: user2.username } } } - - it 'further filters on the returned resultset' do - expect(issues).to be_empty - end - end - end - end - - context 'filtering by multiple labels' do - let(:params) { { label_name: [label.title, label2.title].join(',') } } - let(:label2) { create(:label, project: project2) } - - before do - create(:label_link, label: label2, target: issue2) - end - - it 'returns the unique issues with all those labels' do - expect(issues).to contain_exactly(issue2) - end - - context 'using NOT' do - let(:params) { { not: { label_name: [label.title, label2.title].join(',') } } } - - it 'returns issues that do not have any of the labels provided' do - expect(issues).to contain_exactly(issue1, issue4, issue5) - end - end - end - - context 'filtering by a label that includes any or none in the title' do - let(:params) { { label_name: [label.title, label2.title].join(',') } } - let(:label) { create(:label, title: 'any foo', project: project2) } - let(:label2) { create(:label, title: 'bar none', project: project2) } - - before do - create(:label_link, label: label2, target: issue2) - end - - it 'returns the unique issues with all those labels' do - expect(issues).to contain_exactly(issue2) - end - - context 'using NOT' do - let(:params) { { not: { label_name: [label.title, label2.title].join(',') } } } - - it 'returns issues that do not have ANY ONE of the labels provided' do - expect(issues).to contain_exactly(issue1, issue4, issue5) - end - end - end - - context 'filtering by no label' do - let(:params) { { label_name: described_class::Params::FILTER_NONE } } - - it 'returns issues with no labels' do - expect(issues).to contain_exactly(issue1, issue4, issue5) - end - end - - context 'filtering by any label' do - let(:params) { { label_name: described_class::Params::FILTER_ANY } } - - it 'returns issues that have one or more label' do - create_list(:label_link, 2, label: create(:label, project: project2), target: issue3) - - expect(issues).to contain_exactly(issue2, issue3) - end - end - - context 'when the same label exists on project and group levels' do - let(:issue1) { create(:issue, project: project1) } - let(:issue2) { create(:issue, project: project1) } - - # Skipping validation to reproduce a "real-word" scenario. - # We still have legacy labels on PRD that have the same title on the group and project levels, example: `bug` - let(:project_label) { build(:label, title: 'somelabel', project: project1).tap { |r| r.save!(validate: false) } } - let(:group_label) { create(:group_label, title: 'somelabel', group: project1.group) } - - let(:params) { { label_name: 'somelabel' } } - - before do - create(:label_link, label: group_label, target: issue1) - create(:label_link, label: project_label, target: issue2) - end - - it 'finds both issue records' do - expect(issues).to contain_exactly(issue1, issue2) - end - end - - context 'filtering by issue term' do - let(:params) { { search: search_term } } - - let_it_be(:english) { create(:issue, project: project1, title: 'title', description: 'something english') } - let_it_be(:japanese) { create(:issue, project: project1, title: '日本語 title', description: 'another english description') } - - context 'with latin search term' do - let(:search_term) { 'title english' } - - it 'returns matching issues' do - expect(issues).to contain_exactly(english, japanese) - end - end - - context 'with non-latin search term' do - let(:search_term) { '日本語' } - - it 'returns matching issues' do - expect(issues).to contain_exactly(japanese) - end - end - - context 'when full-text search is disabled' do - let(:search_term) { 'somet' } - - before do - stub_feature_flags(issues_full_text_search: false) - end - - it 'allows partial word matches' do - expect(issues).to contain_exactly(english) - end - end - - context 'with anonymous user' do - let_it_be(:public_project) { create(:project, :public, group: subgroup) } - let_it_be(:issue6) { create(:issue, project: public_project, title: 'tanuki') } - let_it_be(:issue7) { create(:issue, project: public_project, title: 'ikunat') } - - let(:search_user) { nil } - let(:params) { { search: 'tanuki' } } - - context 'with disable_anonymous_search feature flag enabled' do - before do - stub_feature_flags(disable_anonymous_search: true) - end - - it 'does not perform search' do - expect(issues).to contain_exactly(issue6, issue7) - end - end - - context 'with disable_anonymous_search feature flag disabled' do - before do - stub_feature_flags(disable_anonymous_search: false) - end - - it 'finds one public issue' do - expect(issues).to contain_exactly(issue6) - end - end - end - end - - context 'filtering by issue term in title' do - let(:params) { { search: 'git', in: 'title' } } - - it 'returns issues with title match for search term' do - expect(issues).to contain_exactly(issue1) - end - end - - context 'filtering by issues iids' do - let(:params) { { iids: [issue3.iid] } } - - it 'returns issues where iids match' do - expect(issues).to contain_exactly(issue3, issue5) - end - - context 'using NOT' do - let(:params) { { not: { iids: [issue3.iid] } } } - - it 'returns issues with no iids match' do - expect(issues).to contain_exactly(issue1, issue2, issue4) - end - end - end - - context 'filtering by state' do - context 'with opened' do - let(:params) { { state: 'opened' } } - - it 'returns only opened issues' do - expect(issues).to contain_exactly(issue1, issue2, issue3, issue4, issue5) - end - end - - context 'with closed' do - let(:params) { { state: 'closed' } } - - it 'returns only closed issues' do - expect(issues).to contain_exactly(closed_issue) - end - end - - context 'with all' do - let(:params) { { state: 'all' } } - - it 'returns all issues' do - expect(issues).to contain_exactly(issue1, issue2, issue3, closed_issue, issue4, issue5) - end - end - - context 'with invalid state' do - let(:params) { { state: 'invalid_state' } } - - it 'returns all issues' do - expect(issues).to contain_exactly(issue1, issue2, issue3, closed_issue, issue4, issue5) - end - end - end - - context 'filtering by created_at' do - context 'through created_after' do - let(:params) { { created_after: issue3.created_at } } - - it 'returns issues created on or after the given date' do - expect(issues).to contain_exactly(issue3) - end - end - - context 'through created_before' do - let(:params) { { created_before: issue1.created_at } } - - it 'returns issues created on or before the given date' do - expect(issues).to contain_exactly(issue1) - end - end - - context 'through created_after and created_before' do - let(:params) { { created_after: issue2.created_at, created_before: issue3.created_at } } - - it 'returns issues created between the given dates' do - expect(issues).to contain_exactly(issue2, issue3) - end - end - end - - context 'filtering by updated_at' do - context 'through updated_after' do - let(:params) { { updated_after: issue3.updated_at } } - - it 'returns issues updated on or after the given date' do - expect(issues).to contain_exactly(issue3) - end - end - - context 'through updated_before' do - let(:params) { { updated_before: issue1.updated_at } } - - it 'returns issues updated on or before the given date' do - expect(issues).to contain_exactly(issue1) - end - end - - context 'through updated_after and updated_before' do - let(:params) { { updated_after: issue2.updated_at, updated_before: issue3.updated_at } } - - it 'returns issues updated between the given dates' do - expect(issues).to contain_exactly(issue2, issue3) - end - end - end - - context 'filtering by closed_at' do - let!(:closed_issue1) { create(:issue, project: project1, state: :closed, closed_at: 1.week.ago) } - let!(:closed_issue2) { create(:issue, project: project2, state: :closed, closed_at: 1.week.from_now) } - let!(:closed_issue3) { create(:issue, project: project2, state: :closed, closed_at: 2.weeks.from_now) } - - context 'through closed_after' do - let(:params) { { state: :closed, closed_after: closed_issue3.closed_at } } - - it 'returns issues closed on or after the given date' do - expect(issues).to contain_exactly(closed_issue3) - end - end - - context 'through closed_before' do - let(:params) { { state: :closed, closed_before: closed_issue1.closed_at } } - - it 'returns issues closed on or before the given date' do - expect(issues).to contain_exactly(closed_issue1) - end - end - - context 'through closed_after and closed_before' do - let(:params) { { state: :closed, closed_after: closed_issue2.closed_at, closed_before: closed_issue3.closed_at } } - - it 'returns issues closed between the given dates' do - expect(issues).to contain_exactly(closed_issue2, closed_issue3) - end - end - end - - context 'filtering by reaction name' do - context 'user searches by no reaction' do - let(:params) { { my_reaction_emoji: 'None' } } - - it 'returns issues that the user did not react to' do - expect(issues).to contain_exactly(issue2, issue4, issue5) - end - end - - context 'user searches by any reaction' do - let(:params) { { my_reaction_emoji: 'Any' } } - - it 'returns issues that the user reacted to' do - expect(issues).to contain_exactly(issue1, issue3) - end - end - - context 'user searches by "thumbsup" reaction' do - let(:params) { { my_reaction_emoji: 'thumbsup' } } - - it 'returns issues that the user thumbsup to' do - expect(issues).to contain_exactly(issue1) - end - - context 'using NOT' do - let(:params) { { not: { my_reaction_emoji: 'thumbsup' } } } - - it 'returns issues that the user did not thumbsup to' do - expect(issues).to contain_exactly(issue2, issue3, issue4, issue5) - end - end - end - - context 'user2 searches by "thumbsup" reaction' do - let(:search_user) { user2 } - - let(:params) { { my_reaction_emoji: 'thumbsup' } } - - it 'returns issues that the user2 thumbsup to' do - expect(issues).to contain_exactly(issue2) - end - - context 'using NOT' do - let(:params) { { not: { my_reaction_emoji: 'thumbsup' } } } - - it 'returns issues that the user2 thumbsup to' do - expect(issues).to contain_exactly(issue3) - end - end - end - - context 'user searches by "thumbsdown" reaction' do - let(:params) { { my_reaction_emoji: 'thumbsdown' } } - - it 'returns issues that the user thumbsdown to' do - expect(issues).to contain_exactly(issue3) - end - - context 'using NOT' do - let(:params) { { not: { my_reaction_emoji: 'thumbsdown' } } } - - it 'returns issues that the user thumbsdown to' do - expect(issues).to contain_exactly(issue1, issue2, issue4, issue5) - end - end - end - end - - context 'filtering by confidential' do - let_it_be(:confidential_issue) { create(:issue, project: project1, confidential: true) } - - context 'no filtering' do - it 'returns all issues' do - expect(issues).to contain_exactly(issue1, issue2, issue3, issue4, issue5, confidential_issue) - end - end - - context 'user filters confidential issues' do - let(:params) { { confidential: true } } - - it 'returns only confidential issues' do - expect(issues).to contain_exactly(confidential_issue) - end - end - - context 'user filters only public issues' do - let(:params) { { confidential: false } } - - it 'returns only public issues' do - expect(issues).to contain_exactly(issue1, issue2, issue3, issue4, issue5) - end - end - end - - context 'filtering by issue type' do - let_it_be(:incident_issue) { create(:incident, project: project1) } - - context 'no type given' do - let(:params) { { issue_types: [] } } - - it 'returns all issues' do - expect(issues).to contain_exactly(incident_issue, issue1, issue2, issue3, issue4, issue5) - end - end - - context 'incident type' do - let(:params) { { issue_types: ['incident'] } } - - it 'returns incident issues' do - expect(issues).to contain_exactly(incident_issue) - end - end - - context 'issue type' do - let(:params) { { issue_types: ['issue'] } } - - it 'returns all issues with type issue' do - expect(issues).to contain_exactly(issue1, issue2, issue3, issue4, issue5) - end - end - - context 'multiple params' do - let(:params) { { issue_types: %w(issue incident) } } - - it 'returns all issues' do - expect(issues).to contain_exactly(incident_issue, issue1, issue2, issue3, issue4, issue5) - end - end - - context 'without array' do - let(:params) { { issue_types: 'incident' } } - - it 'returns incident issues' do - expect(issues).to contain_exactly(incident_issue) - end - end - - context 'invalid params' do - let(:params) { { issue_types: ['nonsense'] } } - - it 'returns no issues' do - expect(issues).to eq(Issue.none) - end - 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 } - - it 'returns no results' do - expect(issues).to be_empty - end - end - - context 'when the user can see some, but not all, issues' do - let(:search_user) { user2 } - - it 'returns only issues they can see' do - expect(issues).to contain_exactly(issue2, issue3) - end - end - - it 'finds issues user can access due to group' do - group = create(:group) - project = create(:project, group: group) - issue = create(:issue, project: project) - group.add_user(user, :owner) - - expect(issues).to include(issue) - end - end - - context 'personal scope' do - let(:scope) { 'assigned_to_me' } - - it 'returns issue assigned to the user' do - expect(issues).to contain_exactly(issue1, issue2, issue5) - end - - context 'filtering by project' do - let(:params) { { project_id: project1.id } } - - it 'returns issues assigned to the user in that project' do - expect(issues).to contain_exactly(issue1, issue5) - end - end - end - - context 'when project restricts issues' do - let(:scope) { nil } - - it "doesn't return team-only issues to non team members" do - project = create(:project, :public, :issues_private) - issue = create(:issue, project: project) - - expect(issues).not_to include(issue) - end - - it "doesn't return issues if feature disabled" do - [project1, project2, project3].each do |project| - project.project_feature.update!(issues_access_level: ProjectFeature::DISABLED) - end - - expect(issues.count).to eq 0 - end - end - - context 'external authorization' do - it_behaves_like 'a finder with external authorization service' do - let!(:subject) { create(:issue, project: project) } - let(:project_params) { { project_id: project.id } } - end - end - - context 'filtering by due date' do - let_it_be(:issue_due_today) { create(:issue, project: project1, due_date: Date.current) } - let_it_be(:issue_due_tomorrow) { create(:issue, project: project1, due_date: 1.day.from_now) } - let_it_be(:issue_overdue) { create(:issue, project: project1, due_date: 2.days.ago) } - let_it_be(:issue_due_soon) { create(:issue, project: project1, due_date: 2.days.from_now) } - - let(:scope) { 'all' } - let(:base_params) { { project_id: project1.id } } - - context 'with param set to no due date' do - let(:params) { base_params.merge(due_date: Issue::NoDueDate.name) } - - it 'returns issues with no due date' do - expect(issues).to contain_exactly(issue1, issue5) - end - end - - context 'with param set to any due date' do - let(:params) { base_params.merge(due_date: Issue::AnyDueDate.name) } - - it 'returns issues with any due date' do - expect(issues).to contain_exactly(issue_due_today, issue_due_tomorrow, issue_overdue, issue_due_soon) - end - end - - context 'with param set to due today' do - let(:params) { base_params.merge(due_date: Issue::DueToday.name) } - - it 'returns issues due today' do - expect(issues).to contain_exactly(issue_due_today) - end - end - - context 'with param set to due tomorrow' do - let(:params) { base_params.merge(due_date: Issue::DueTomorrow.name) } - - it 'returns issues due today' do - expect(issues).to contain_exactly(issue_due_tomorrow) - end - end - - context 'with param set to overdue' do - let(:params) { base_params.merge(due_date: Issue::Overdue.name) } - - it 'returns overdue issues' do - expect(issues).to contain_exactly(issue_overdue) - end - end - - context 'with param set to next month and previous two weeks' do - let(:params) { base_params.merge(due_date: Issue::DueNextMonthAndPreviousTwoWeeks.name) } - - it 'returns issues due in the previous two weeks and next month' do - expect(issues).to contain_exactly(issue_due_today, issue_due_tomorrow, issue_overdue, issue_due_soon) - end - end - - context 'with invalid param' do - let(:params) { base_params.merge(due_date: 'foo') } - - it 'returns no issues' do - expect(issues).to be_empty - end - end - end - end - - describe '#row_count', :request_store do - let_it_be(:admin) { create(:admin) } - - context 'when admin mode is enabled', :enable_admin_mode do - it 'returns the number of rows for the default state' do - finder = described_class.new(admin) - - expect(finder.row_count).to eq(5) - end - - it 'returns the number of rows for a given state' do - finder = described_class.new(admin, state: 'closed') - - expect(finder.row_count).to be_zero - end - end - - context 'when admin mode is disabled' do - it 'returns no rows' do - finder = described_class.new(admin) - - expect(finder.row_count).to be_zero - end - end - - it 'returns -1 if the query times out' do - finder = described_class.new(admin) - - expect_next_instance_of(described_class) do |subfinder| - expect(subfinder).to receive(:execute).and_raise(ActiveRecord::QueryCanceled) - end - - expect(finder.row_count).to eq(-1) - end - end - - describe '#with_confidentiality_access_check' do - let(:guest) { create(:user) } - - let_it_be(:authorized_user) { create(:user) } - let_it_be(:banned_user) { create(:user, :banned) } - let_it_be(:project) { create(:project, namespace: authorized_user.namespace) } - let_it_be(:public_issue) { create(:issue, project: project) } - let_it_be(:confidential_issue) { create(:issue, project: project, confidential: true) } - let_it_be(:hidden_issue) { create(:issue, project: project, author: banned_user) } - - shared_examples 'returns public, does not return hidden or confidential' do - it 'returns only public issues' do - expect(subject).to include(public_issue) - expect(subject).not_to include(confidential_issue, hidden_issue) - end - end - - shared_examples 'returns public and confidential, does not return hidden' do - it 'returns only public and confidential issues' do - expect(subject).to include(public_issue, confidential_issue) - expect(subject).not_to include(hidden_issue) - end - end - - shared_examples 'returns public and hidden, does not return confidential' do - it 'returns only public and hidden issues' do - expect(subject).to include(public_issue, hidden_issue) - expect(subject).not_to include(confidential_issue) - end - end - - shared_examples 'returns public, confidential, and hidden' do - it 'returns all issues' do - expect(subject).to include(public_issue, confidential_issue, hidden_issue) - end - end - - context 'when no project filter is given' do - let(:params) { {} } - - context 'for an anonymous user' do - subject { described_class.new(nil, params).with_confidentiality_access_check } - - it_behaves_like 'returns public, does not return hidden or confidential' - - context 'when feature flag is disabled' do - before do - stub_feature_flags(ban_user_feature_flag: false) - end - - it_behaves_like 'returns public and hidden, does not return confidential' - end - end - - context 'for a user without project membership' do - subject { described_class.new(user, params).with_confidentiality_access_check } - - it_behaves_like 'returns public, does not return hidden or confidential' - - context 'when feature flag is disabled' do - before do - stub_feature_flags(ban_user_feature_flag: false) - end - - it_behaves_like 'returns public and hidden, does not return confidential' - end - end - - context 'for a guest user' do - subject { described_class.new(guest, params).with_confidentiality_access_check } - - before do - project.add_guest(guest) - end - - it_behaves_like 'returns public, does not return hidden or confidential' - - context 'when feature flag is disabled' do - before do - stub_feature_flags(ban_user_feature_flag: false) - end - - it_behaves_like 'returns public and hidden, does not return confidential' - end - end - - context 'for a project member with access to view confidential issues' do - subject { described_class.new(authorized_user, params).with_confidentiality_access_check } - - it_behaves_like 'returns public and confidential, does not return hidden' - - context 'when feature flag is disabled' do - before do - stub_feature_flags(ban_user_feature_flag: false) - end - - it_behaves_like 'returns public, confidential, and hidden' - end - end - - context 'for an admin' do - let(:admin_user) { create(:user, :admin) } - - subject { described_class.new(admin_user, params).with_confidentiality_access_check } - - context 'when admin mode is enabled', :enable_admin_mode do - it_behaves_like 'returns public, confidential, and hidden' - - context 'when feature flag is disabled' do - before do - stub_feature_flags(ban_user_feature_flag: false) - end - - it_behaves_like 'returns public, confidential, and hidden' - end - end - - context 'when admin mode is disabled' do - it_behaves_like 'returns public, does not return hidden or confidential' - - context 'when feature flag is disabled' do - before do - stub_feature_flags(ban_user_feature_flag: false) - end - - it_behaves_like 'returns public and hidden, does not return confidential' - end - end - end - end - - context 'when searching within a specific project' do - let(:params) { { project_id: project.id } } - - context 'for an anonymous user' do - subject { described_class.new(nil, params).with_confidentiality_access_check } - - it_behaves_like 'returns public, does not return hidden or confidential' - - context 'when feature flag is disabled' do - before do - stub_feature_flags(ban_user_feature_flag: false) - end - - it_behaves_like 'returns public and hidden, does not return confidential' - end - - it 'does not filter by confidentiality' do - expect(Issue).not_to receive(:where).with(a_string_matching('confidential'), anything) - subject - end - end - - context 'for a user without project membership' do - subject { described_class.new(user, params).with_confidentiality_access_check } - - it_behaves_like 'returns public, does not return hidden or confidential' - - context 'when feature flag is disabled' do - before do - stub_feature_flags(ban_user_feature_flag: false) - end - - it_behaves_like 'returns public and hidden, does not return confidential' - end - - it 'filters by confidentiality' do - expect(subject.to_sql).to match("issues.confidential") - end - end - - context 'for a guest user' do - subject { described_class.new(guest, params).with_confidentiality_access_check } - - before do - project.add_guest(guest) - end - - it_behaves_like 'returns public, does not return hidden or confidential' - - context 'when feature flag is disabled' do - before do - stub_feature_flags(ban_user_feature_flag: false) - end - - it_behaves_like 'returns public and hidden, does not return confidential' - end - - it 'filters by confidentiality' do - expect(subject.to_sql).to match("issues.confidential") - end - end - - context 'for a project member with access to view confidential issues' do - subject { described_class.new(authorized_user, params).with_confidentiality_access_check } - - it_behaves_like 'returns public and confidential, does not return hidden' - - context 'when feature flag is disabled' do - before do - stub_feature_flags(ban_user_feature_flag: false) - end - - it_behaves_like 'returns public, confidential, and hidden' - end - - it 'does not filter by confidentiality' do - expect(Issue).not_to receive(:where).with(a_string_matching('confidential'), anything) - - subject - end - end - - context 'for an admin' do - let(:admin_user) { create(:user, :admin) } - - subject { described_class.new(admin_user, params).with_confidentiality_access_check } - - context 'when admin mode is enabled', :enable_admin_mode do - it_behaves_like 'returns public, confidential, and hidden' - - context 'when feature flag is disabled' do - before do - stub_feature_flags(ban_user_feature_flag: false) - end - - it_behaves_like 'returns public, confidential, and hidden' - end - - it 'does not filter by confidentiality' do - expect(Issue).not_to receive(:where).with(a_string_matching('confidential'), anything) - - subject - end - end - - context 'when admin mode is disabled' do - it_behaves_like 'returns public, does not return hidden or confidential' - - context 'when feature flag is disabled' do - before do - stub_feature_flags(ban_user_feature_flag: false) - end - - it_behaves_like 'returns public and hidden, does not return confidential' - end - - it 'filters by confidentiality' do - expect(subject.to_sql).to match("issues.confidential") - end - end - end - end - end - - describe '#use_cte_for_search?' do - let(:finder) { described_class.new(nil, params) } - - context 'when there is no search param' do - let(:params) { { attempt_group_search_optimizations: true } } - - it 'returns false' do - expect(finder.use_cte_for_search?).to be_falsey - end - end - - context 'when the force_cte param is falsey' do - let(:params) { { search: '日本語' } } - - it 'returns false' do - expect(finder.use_cte_for_search?).to be_falsey - end - end - - context 'when a non-simple sort is given' do - let(:params) { { search: '日本語', attempt_project_search_optimizations: true, sort: 'popularity' } } - - it 'returns false' do - expect(finder.use_cte_for_search?).to be_falsey - end - end - - context 'when all conditions are met' do - context "uses group search optimization" do - let(:params) { { search: '日本語', attempt_group_search_optimizations: true } } - - it 'returns true' do - expect(finder.use_cte_for_search?).to be_truthy - expect(finder.execute.to_sql).to match(/^WITH "issues" AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported}/) - end - end - - context "uses project search optimization" do - let(:params) { { search: '日本語', attempt_project_search_optimizations: true } } - - it 'returns true' do - expect(finder.use_cte_for_search?).to be_truthy - expect(finder.execute.to_sql).to match(/^WITH "issues" AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported}/) - end - end - - context 'with simple sort' do - let(:params) { { search: '日本語', attempt_project_search_optimizations: true, sort: 'updated_desc' } } - - it 'returns true' do - expect(finder.use_cte_for_search?).to be_truthy - expect(finder.execute.to_sql).to match(/^WITH "issues" AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported}/) - end - end - - context 'with simple sort as a symbol' do - let(:params) { { search: '日本語', attempt_project_search_optimizations: true, sort: :updated_desc } } - - it 'returns true' do - expect(finder.use_cte_for_search?).to be_truthy - expect(finder.execute.to_sql).to match(/^WITH "issues" AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported}/) - end - end - end - end - - describe '#parent_param=' do - let(:finder) { described_class.new(nil) } - - subject { finder.parent_param = obj } - - where(:klass, :param) do - :Project | :project_id - :Group | :group_id - end - - with_them do - let(:obj) { Object.const_get(klass, false).new } - - it 'sets the params' do - subject - - expect(finder.params[param]).to eq(obj) - end - end - - context 'unexpected parent' do - let(:obj) { MergeRequest.new } - - it 'raises an error' do - expect { subject }.to raise_error('Unexpected parent: MergeRequest') - end - end - end + it_behaves_like 'issues or work items finder', :issue, 'IssuesFinder#execute context' end diff --git a/spec/finders/packages/pypi/packages_finder_spec.rb b/spec/finders/packages/pypi/packages_finder_spec.rb index 1a44fb99009..3957eb188da 100644 --- a/spec/finders/packages/pypi/packages_finder_spec.rb +++ b/spec/finders/packages/pypi/packages_finder_spec.rb @@ -12,59 +12,91 @@ RSpec.describe Packages::Pypi::PackagesFinder do let_it_be(:package3) { create(:pypi_package, name: package2.name, project: project) } let_it_be(:package4) { create(:pypi_package, name: package2.name, project: project2) } - let(:package_name) { package2.name } + shared_examples 'when no package is found' do + context 'non-existing package' do + let(:package_name) { 'none' } - describe 'execute' do - subject { described_class.new(user, scope, package_name: package_name).execute } + it { expect(subject).to be_empty } + end + end - shared_examples 'when no package is found' do - context 'non-existing package' do - let(:package_name) { 'none' } + shared_examples 'when package_name param is a non-normalized name' do + context 'non-existing package' do + let(:package_name) { package2.name.upcase.tr('-', '.') } - it { expect(subject).to be_empty } - end + it { expect(subject).to be_empty } end + end - shared_examples 'when package_name param is a non-normalized name' do - context 'non-existing package' do - let(:package_name) { package2.name.upcase.tr('-', '.') } + describe '#execute' do + subject { described_class.new(user, scope, package_name: package_name).execute } - it { expect(subject).to be_empty } + context 'with package name param' do + let(:package_name) { package2.name } + + context 'within a project' do + let(:scope) { project } + + it { is_expected.to contain_exactly(package2, package3) } + + it_behaves_like 'when no package is found' + it_behaves_like 'when package_name param is a non-normalized name' end - end - context 'within a project' do - let(:scope) { project } + context 'within a group' do + let(:scope) { group } - it { is_expected.to contain_exactly(package2, package3) } + it { expect(subject).to be_empty } - it_behaves_like 'when no package is found' - it_behaves_like 'when package_name param is a non-normalized name' - end + context 'user with access to only one project' do + before do + project2.add_developer(user) + end - context 'within a group' do - let(:scope) { group } + it { is_expected.to contain_exactly(package4) } - it { expect(subject).to be_empty } + it_behaves_like 'when no package is found' + it_behaves_like 'when package_name param is a non-normalized name' - context 'user with access to only one project' do - before do - project2.add_developer(user) + context 'user with access to multiple projects' do + before do + project.add_developer(user) + end + + it { is_expected.to contain_exactly(package2, package3, package4) } + end end + end + end - it { is_expected.to contain_exactly(package4) } + context 'without package_name param' do + let(:package_name) { nil } - it_behaves_like 'when no package is found' - it_behaves_like 'when package_name param is a non-normalized name' + context 'within a group' do + let(:scope) { group } - context ' user with access to multiple projects' do + context 'user with access to only one project' do before do - project.add_developer(user) + project2.add_developer(user) end - it { is_expected.to contain_exactly(package2, package3, package4) } + it { is_expected.to contain_exactly(package4) } + + context 'user with access to multiple projects' do + before do + project.add_developer(user) + end + + it { is_expected.to contain_exactly(package1, package2, package3, package4) } + end end end + + context 'within a project' do + let(:scope) { project } + + it { is_expected.to contain_exactly(package1, package2, package3) } + end end end end diff --git a/spec/finders/work_items/work_items_finder_spec.rb b/spec/finders/work_items/work_items_finder_spec.rb new file mode 100644 index 00000000000..fe400688a23 --- /dev/null +++ b/spec/finders/work_items/work_items_finder_spec.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe WorkItems::WorkItemsFinder do + using RSpec::Parameterized::TableSyntax + include_context 'WorkItemsFinder context' + + it_behaves_like 'issues or work items finder', :work_item, 'WorkItemsFinder#execute context' +end |