3 * Copyright (C) 2009-2023 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.ce.task.projectanalysis.issue;
22 import java.util.Date;
23 import org.junit.Before;
24 import org.junit.Rule;
25 import org.junit.Test;
26 import org.mockito.Mock;
27 import org.mockito.MockitoAnnotations;
28 import org.sonar.api.issue.Issue;
29 import org.sonar.api.rule.RuleKey;
30 import org.sonar.core.issue.DefaultIssue;
31 import org.sonar.core.issue.tracking.BlockHashSequence;
32 import org.sonar.core.issue.tracking.Input;
33 import org.sonar.core.issue.tracking.LineHashSequence;
34 import org.sonar.core.issue.tracking.NonClosedTracking;
35 import org.sonar.core.issue.tracking.Tracker;
36 import org.sonar.db.DbTester;
37 import org.sonar.db.component.BranchType;
38 import org.sonar.db.component.ComponentDto;
39 import org.sonar.db.rule.RuleDto;
41 import static java.util.Collections.singletonList;
42 import static java.util.Collections.singletonMap;
43 import static org.mockito.ArgumentMatchers.any;
44 import static org.mockito.Mockito.mock;
45 import static org.mockito.Mockito.verify;
46 import static org.mockito.Mockito.verifyNoInteractions;
47 import static org.mockito.Mockito.when;
48 import static org.sonar.ce.task.projectanalysis.component.ReportComponent.builder;
49 import static org.sonar.db.component.ComponentTesting.newFileDto;
51 public class PullRequestSourceBranchMergerTest {
52 private static final String PROJECT_KEY = "project";
53 private static final String PROJECT_UUID = "projectUuid";
54 private static final int FILE_1_REF = 12341;
55 private static final String FILE_1_KEY = "fileKey";
56 private static final String FILE_1_UUID = "fileUuid";
57 private static final org.sonar.ce.task.projectanalysis.component.Component FILE_1 = builder(
58 org.sonar.ce.task.projectanalysis.component.Component.Type.FILE, FILE_1_REF)
64 private Tracker<DefaultIssue, DefaultIssue> tracker;
67 private IssueLifecycle issueLifecycle;
70 private TrackerSourceBranchInputFactory sourceBranchInputFactory;
73 private NonClosedTracking<DefaultIssue, DefaultIssue> prTracking;
76 public DbTester db = DbTester.create();
78 private PullRequestSourceBranchMerger underTest;
80 private DefaultIssue rawIssue;
81 private Input<DefaultIssue> rawIssuesInput;
85 MockitoAnnotations.initMocks(this);
86 underTest = new PullRequestSourceBranchMerger(
89 sourceBranchInputFactory);
91 ComponentDto projectDto = db.components().insertPublicProject(p -> p.setKey(PROJECT_KEY).setUuid(PROJECT_UUID));
92 ComponentDto branch1Dto = db.components().insertProjectBranch(projectDto, b -> b.setKey("myBranch1")
93 .setBranchType(BranchType.PULL_REQUEST)
94 .setMergeBranchUuid(projectDto.uuid()));
95 ComponentDto branch2Dto = db.components().insertProjectBranch(projectDto, b -> b.setKey("myBranch2")
96 .setBranchType(BranchType.PULL_REQUEST)
97 .setMergeBranchUuid(projectDto.uuid()));
98 ComponentDto branch3Dto = db.components().insertProjectBranch(projectDto, b -> b.setKey("myBranch3")
99 .setBranchType(BranchType.PULL_REQUEST)
100 .setMergeBranchUuid(projectDto.uuid()));
101 db.components().insertComponent(newFileDto(branch1Dto).setKey(FILE_1_KEY + ":PULL_REQUEST:myBranch1"));
102 db.components().insertComponent(newFileDto(branch2Dto).setKey(FILE_1_KEY + ":PULL_REQUEST:myBranch2"));
103 db.components().insertComponent(newFileDto(branch3Dto).setKey(FILE_1_KEY + ":PULL_REQUEST:myBranch3"));
104 rule = db.rules().insert();
105 rawIssue = createIssue("issue1", rule.getKey(), Issue.STATUS_OPEN, new Date());
106 rawIssuesInput = new DefaultTrackingInput(singletonList(rawIssue), mock(LineHashSequence.class), mock(BlockHashSequence.class));
110 public void tryMergeIssuesFromSourceBranchOfPullRequest_does_nothing_if_source_branch_was_not_analyzed() {
111 when(sourceBranchInputFactory.hasSourceBranchAnalysis()).thenReturn(false);
113 underTest.tryMergeIssuesFromSourceBranchOfPullRequest(FILE_1, rawIssuesInput.getIssues(), rawIssuesInput);
115 verifyNoInteractions(issueLifecycle);
119 public void tryMergeIssuesFromSourceBranchOfPullRequest_merges_issue_state_from_source_branch_into_pull_request() {
120 DefaultIssue sourceBranchIssue = createIssue("issue2", rule.getKey(), Issue.STATUS_CONFIRMED, new Date());
121 Input<DefaultIssue> sourceBranchInput = new DefaultTrackingInput(singletonList(sourceBranchIssue), mock(LineHashSequence.class), mock(BlockHashSequence.class));
122 when(sourceBranchInputFactory.hasSourceBranchAnalysis()).thenReturn(true);
123 when(sourceBranchInputFactory.createForSourceBranch(any())).thenReturn(sourceBranchInput);
124 when(tracker.trackNonClosed(any(), any())).thenReturn(prTracking);
125 when(prTracking.getMatchedRaws()).thenReturn(singletonMap(rawIssue, sourceBranchIssue));
127 underTest.tryMergeIssuesFromSourceBranchOfPullRequest(FILE_1, rawIssuesInput.getIssues(), rawIssuesInput);
129 verify(issueLifecycle).copyExistingIssueFromSourceBranchToPullRequest(rawIssue, sourceBranchIssue);
132 private static DefaultIssue createIssue(String key, RuleKey ruleKey, String status, Date creationDate) {
133 DefaultIssue issue = new DefaultIssue();
135 issue.setRuleKey(ruleKey);
136 issue.setMessage("msg");
138 issue.setStatus(status);
139 issue.setResolution(null);
140 issue.setCreationDate(creationDate);
141 issue.setChecksum("checksum");