spec/lib/release_tools/security/issue_crawler_spec.rb (249 lines of code) (raw):

# frozen_string_literal: true require 'spec_helper' describe ReleaseTools::Security::IssueCrawler do let(:tracking_issue1) do create( :issue, project_id: 1, iid: 1, due_date: '2020-01-04', state: described_class::OPENED, web_url: 'https://gitlab.com/gitlab-org/security/gitlab/-/issues/1' ) end let(:issue1) do create( :issue, project_id: 1, iid: 2, due_date: '2020-01-01', labels: [], state: described_class::OPENED, web_url: 'https://gitlab.com/gitlab-org/security/gitlab/-/issues/2' ) end let(:issue2) do create( :issue, project_id: 1, iid: 3, due_date: nil, labels: [], state: described_class::OPENED, web_url: 'https://gitlab.com/gitlab-org/security/gitlab/-/issues/2' ) end let(:issue3) do create( :issue, project_id: 2, iid: 1, state: described_class::OPENED, web_url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/1' ) end let(:page) { Gitlab::PaginatedResponse.new([tracking_issue1, issue1, issue2]) } subject(:crawler) { described_class.new } describe '#upcoming_security_issues_and_merge_requests' do context 'when there are no security issues' do it 'returns an empty Array' do allow(ReleaseTools::GitlabClient).to receive(:next_security_tracking_issue).and_return(nil) expect(crawler.upcoming_security_issues_and_merge_requests).to eq([]) end end context 'when there are security issues' do it 'returns all security issues and merge requests for the most recent issue' do allow(ReleaseTools::GitlabClient) .to receive(:next_security_tracking_issue) .and_return(issue3) expect(crawler) .to receive(:related_security_issues) .and_return([tracking_issue1, issue1]) crawler.upcoming_security_issues_and_merge_requests end end end describe '#related_security_issues' do it 'returns issues related to the given release issue iid' do implementation_issue1 = create(:security_implementation_issue, issue: tracking_issue1) allow(crawler).to receive(:security_tracking_issue).and_return(tracking_issue1) expect(crawler).to receive(:security_issues_for).with(tracking_issue1.iid).and_return([tracking_issue1]) expect(crawler).to receive(:security_issues_and_merge_requests_for).with([tracking_issue1]) .and_return([implementation_issue1]) expect(crawler.related_security_issues).to eq([implementation_issue1]) end end describe '#security_issues_for' do it 'returns only the security issues related to the tracking release issue' do page = Gitlab::PaginatedResponse.new([issue1, issue2, issue3]) allow(ReleaseTools::GitlabClient.client) .to receive(:issue_links) .with(described_class::PUBLIC_PROJECT, tracking_issue1.iid) .and_return(page) issues = crawler.security_issues_for(tracking_issue1.iid) expect(issues.length).to eq(2) issues.each do |issue| expect(issue.web_url).to include('gitlab-org/security') end end it 'filters out closed issues' do issue4 = create( :issue, project_id: 1, iid: 2, state: 'closed', web_url: 'https://gitlab.com/gitlab-org/security/gitlab/-/issues/2' ) page = Gitlab::PaginatedResponse.new([issue1, issue2, issue3, issue4]) allow(ReleaseTools::GitlabClient.client) .to receive(:issue_links) .with(described_class::PUBLIC_PROJECT, tracking_issue1.iid) .and_return(page) issues = crawler.security_issues_for(tracking_issue1.iid) expect(issues).not_to include(issue4) end end describe '#evaluable_security_issues' do let(:issue4) { create(:issue, project_id: 2, iid: 1) } let(:project1_issue_page) { Gitlab::PaginatedResponse.new([tracking_issue1, issue1, issue3]) } let(:project2_issue_page) { Gitlab::PaginatedResponse.new([issue4]) } it 'returns the security issues with the specified label' do stub_const('ReleaseTools::ManagedVersioning::PROJECTS', [ReleaseTools::Project::GitlabEe, ReleaseTools::Project::Gitaly, ReleaseTools::Project::GitlabPages]) implementation_issue1 = create(:security_implementation_issue, issue: tracking_issue1) implementation_issue2 = create(:security_implementation_issue, issue: issue1) implementation_issue3 = create(:security_implementation_issue, issue: issue3) implementation_issue4 = create(:security_implementation_issue, issue: issue4) results = [implementation_issue1, implementation_issue2, implementation_issue3, implementation_issue4] allow(ReleaseTools::GitlabClient) .to receive(:issues) .with(ReleaseTools::Project::GitlabEe.security_path, labels: [described_class::SECURITY_TARGET_LABEL], state: described_class::OPENED) .and_return(project1_issue_page) allow(ReleaseTools::GitlabClient) .to receive(:issues) .with(ReleaseTools::Project::Gitaly.security_path, labels: [described_class::SECURITY_TARGET_LABEL], state: described_class::OPENED) .and_return(project2_issue_page) allow(ReleaseTools::GitlabClient) .to receive(:issues) .with(ReleaseTools::Project::GitlabPages.security_path, labels: [described_class::SECURITY_TARGET_LABEL], state: described_class::OPENED) .and_return(nil) expect(crawler) .to receive(:security_issues_and_merge_requests_for) .with([tracking_issue1, issue1, issue3, issue4]).and_return(results) issues = crawler.evaluable_security_issues expect(issues).to eq(results) end end describe '#notifiable_security_issues_for' do let(:issue1) { build(:issue, project_id: 1) } let(:issue2) { build(:issue, project_id: 1) } let(:issue3) { build(:issue, project_id: 1) } let(:issue4) { build(:issue, project_id: 2) } let(:project1_issue_page) { Gitlab::PaginatedResponse.new([issue1, issue2, issue3]) } let(:project2_issue_page) { Gitlab::PaginatedResponse.new([issue4]) } before do allow(ReleaseTools::GitlabClient) .to receive(:issues) .with( ReleaseTools::Project::GitlabEe.security_path, labels: [described_class::SECURITY_NOTIFICATIONS_LABEL], state: described_class::OPENED ) .and_return(project1_issue_page) allow(ReleaseTools::GitlabClient) .to receive(:issues) .with( ReleaseTools::Project::Gitaly.security_path, labels: [described_class::SECURITY_NOTIFICATIONS_LABEL], state: described_class::OPENED ) .and_return(project2_issue_page) allow(ReleaseTools::GitlabClient) .to receive(:issues) .with( ReleaseTools::Project::GitlabPages.security_path, labels: [described_class::SECURITY_NOTIFICATIONS_LABEL], state: described_class::OPENED ) .and_return([]) allow(ReleaseTools::GitlabClient) .to receive(:related_merge_requests) .and_return(Gitlab::PaginatedResponse.new([])) end it 'returns the security issues with the specified label' do gitlab_issues = crawler.notifiable_security_issues_for(ReleaseTools::Project::GitlabEe) gitaly_issues = crawler.notifiable_security_issues_for(ReleaseTools::Project::Gitaly) gitlab_pages_issues = crawler.notifiable_security_issues_for(ReleaseTools::Project::GitlabPages) expect(gitlab_issues.map(&:issue)).to eq([issue1, issue2, issue3]) expect(gitaly_issues.map(&:issue)).to eq([issue4]) expect(gitlab_pages_issues).to eq([]) end end describe '#security_issues_and_merge_requests_for' do it 'returns the security issues and merge requests related to the given issues' do mr1 = create( :merge_request, state: described_class::OPENED, web_url: 'https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/1' ) mr2 = create( :merge_request, state: described_class::OPENED, web_url: 'https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/1' ) mr3 = create( :merge_request, state: described_class::OPENED, web_url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/1' ) issue_page = Gitlab::PaginatedResponse.new([issue1, issue3]) mr_page = Gitlab::PaginatedResponse.new([mr1, mr2, mr3]) allow(ReleaseTools::GitlabClient.client) .to receive(:issue_links) .with(described_class::PUBLIC_PROJECT, tracking_issue1.iid) .and_return(issue_page) allow(ReleaseTools::GitlabClient) .to receive(:related_merge_requests) .with(1, 1) .and_return(mr_page) allow(ReleaseTools::GitlabClient) .to receive(:related_merge_requests) .with(1, 2) .and_return(mr_page) allow(ReleaseTools::GitlabClient) .to receive(:related_merge_requests) .with(2, 1) .and_return(mr_page) issues = crawler.security_issues_and_merge_requests_for(issue_page) expect(issues.length).to eq(2) expect(issues[0].project_id).to eq(1) expect(issues[0].iid).to eq(issue1.iid) expect(issues[0].merge_requests).to eq([mr1, mr2]) end it 'filters out closed merge requests' do mr1 = create( :merge_request, state: described_class::OPENED, web_url: 'https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/1' ) mr2 = create( :merge_request, state: described_class::CLOSED, web_url: 'https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/2' ) mr3 = create( :merge_request, state: 'merged', web_url: 'https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/3' ) issue_page = Gitlab::PaginatedResponse.new([tracking_issue1]) mr_page = Gitlab::PaginatedResponse.new([mr1, mr2, mr3]) allow(ReleaseTools::GitlabClient) .to receive(:related_merge_requests) .with(tracking_issue1.project_id, tracking_issue1.iid) .and_return(mr_page) issues = crawler.security_issues_and_merge_requests_for(issue_page) expect(issues[0].merge_requests.length).to eq(2) expect(issues[0].merge_requests).to contain_exactly(mr1, mr3) expect(issues[0].merge_requests).not_to include(mr2) end end end