require 'spec_helper' describe IssuesFinder do let(:user) { create(:user) } let(:user2) { create(:user) } let(:project1) { create(:empty_project) } let(:project2) { create(:empty_project) } let(:milestone) { create(:milestone, project: project1) } let(:label) { create(:label, project: project2) } let(:issue1) { create(:issue, author: user, assignee: user, project: project1, milestone: milestone, title: 'gitlab') } let(:issue2) { create(:issue, author: user, assignee: user, project: project2, description: 'gitlab') } let(:issue3) { create(:issue, author: user2, assignee: user2, project: project2) } describe '#execute' do let(:closed_issue) { create(:issue, author: user2, assignee: user2, project: project2, state: 'closed') } let!(:label_link) { create(:label_link, label: label, target: issue2) } let(:search_user) { user } let(:params) { {} } let(:issues) { IssuesFinder.new(search_user, params.reverse_merge(scope: scope, state: 'opened')).execute } before do project1.team << [user, :master] project2.team << [user, :developer] project2.team << [user2, :developer] issue1 issue2 issue3 end context 'scope: all' do let(:scope) { 'all' } it 'returns all issues' do expect(issues).to contain_exactly(issue1, issue2, issue3) end context 'filtering by assignee ID' do let(:params) { { assignee_id: user.id } } it 'returns issues assigned to that user' do expect(issues).to contain_exactly(issue1, issue2) end end context 'filtering 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 '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 no milestone' do let(:params) { { milestone_title: Milestone::None.title } } it 'returns issues with no milestone' do expect(issues).to contain_exactly(issue2, issue3) end end context 'filtering by upcoming milestone' do let(:params) { { milestone_title: Milestone::Upcoming.name } } let(:project_no_upcoming_milestones) { create(:empty_project, :public) } let(:project_next_1_1) { create(:empty_project, :public) } let(:project_next_8_8) { create(:empty_project, :public) } let(:yesterday) { Date.today - 1.day } let(:tomorrow) { Date.today + 1.day } let(:two_days_from_now) { Date.today + 2.days } let(:ten_days_from_now) { Date.today + 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.8', due_date: ten_days_from_now), create(:milestone, project: project_next_8_8, title: '1.1', due_date: yesterday), create(:milestone, project: project_next_8_8, title: '8.8', due_date: tomorrow) ] end before do milestones.each do |milestone| create(:issue, project: milestone.project, milestone: milestone, author: user, assignee: user) end end it 'returns issues in the upcoming milestone for each project' do expect(issues.map { |issue| issue.milestone.title }).to contain_exactly('1.1', '8.8') expect(issues.map { |issue| issue.milestone.due_date }).to contain_exactly(tomorrow, two_days_from_now) 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 end context 'filtering by multiple labels' do let(:params) { { label_name: [label.title, label2.title].join(',') } } let(:label2) { create(:label, project: project2) } before { create(:label_link, label: label2, target: issue2) } it 'returns the unique issues with any of those labels' do expect(issues).to contain_exactly(issue2) end end context 'filtering by no label' do let(:params) { { label_name: Label::None.title } } it 'returns issues with no labels' do expect(issues).to contain_exactly(issue1, issue3) end end context 'filtering by issue term' do let(:params) { { search: 'git' } } it 'returns issues with title and description match for search term' do expect(issues).to contain_exactly(issue1, issue2) end end context 'filtering by issue iid' do let(:params) { { search: issue3.to_reference } } it 'returns issue with iid match' do expect(issues).to contain_exactly(issue3) 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) 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) 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) end 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(:empty_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) 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) 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(:empty_project, :public, issues_access_level: ProjectFeature::PRIVATE) issue = create(:issue, project: project) expect(issues).not_to include(issue) end it "doesn't return issues if feature disabled" do [project1, project2].each do |project| project.project_feature.update!(issues_access_level: ProjectFeature::DISABLED) end expect(issues.count).to eq 0 end end end describe '.not_restricted_by_confidentiality' do let(:authorized_user) { create(:user) } let(:project) { create(:empty_project, namespace: authorized_user.namespace) } let!(:public_issue) { create(:issue, project: project) } let!(:confidential_issue) { create(:issue, project: project, confidential: true) } it 'returns non confidential issues for nil user' do expect(IssuesFinder.send(:not_restricted_by_confidentiality, nil)).to include(public_issue) end it 'returns non confidential issues for user not authorized for the issues projects' do expect(IssuesFinder.send(:not_restricted_by_confidentiality, user)).to include(public_issue) end it 'returns all issues for user authorized for the issues projects' do expect(IssuesFinder.send(:not_restricted_by_confidentiality, authorized_user)).to include(public_issue, confidential_issue) end end end