3 * Copyright (C) 2009-2017 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.server.computation.task.projectanalysis.issue;
22 import com.google.common.collect.ImmutableMap;
23 import java.time.Instant;
24 import java.time.temporal.ChronoUnit;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.Date;
29 import javax.annotation.Nullable;
30 import org.junit.Before;
31 import org.junit.Test;
32 import org.mockito.ArgumentCaptor;
33 import org.mockito.Mock;
34 import org.mockito.MockitoAnnotations;
35 import org.sonar.api.issue.Issue;
36 import org.sonar.api.rule.RuleKey;
37 import org.sonar.core.issue.DefaultIssue;
38 import org.sonar.core.issue.ShortBranchIssue;
39 import org.sonar.core.issue.tracking.SimpleTracker;
40 import org.sonar.server.computation.task.projectanalysis.component.Component;
42 import static org.assertj.core.api.Assertions.assertThat;
43 import static org.mockito.Matchers.anyListOf;
44 import static org.mockito.Mockito.verify;
45 import static org.mockito.Mockito.verifyZeroInteractions;
46 import static org.mockito.Mockito.when;
48 public class ShortBranchIssueMergerTest {
50 private ShortBranchIssuesLoader resolvedShortBranchIssuesLoader;
52 private IssueLifecycle issueLifecycle;
54 private Component component;
56 private SimpleTracker<DefaultIssue, ShortBranchIssue> tracker = new SimpleTracker<>();
57 private ShortBranchIssueMerger copier;
61 MockitoAnnotations.initMocks(this);
62 copier = new ShortBranchIssueMerger(resolvedShortBranchIssuesLoader, tracker, issueLifecycle);
66 public void do_nothing_if_no_match() {
67 when(resolvedShortBranchIssuesLoader.loadCandidateIssuesForMergingInTargetBranch(component)).thenReturn(Collections.emptyList());
68 DefaultIssue i = createIssue("issue1", "rule1", Issue.STATUS_CONFIRMED, null, new Date());
69 copier.tryMerge(component, Collections.singleton(i));
71 verify(resolvedShortBranchIssuesLoader).loadCandidateIssuesForMergingInTargetBranch(component);
72 verifyZeroInteractions(issueLifecycle);
76 public void do_nothing_if_no_new_issue() {
77 DefaultIssue i = createIssue("issue1", "rule1", Issue.STATUS_CONFIRMED, null, new Date());
78 when(resolvedShortBranchIssuesLoader.loadCandidateIssuesForMergingInTargetBranch(component)).thenReturn(Collections.singleton(newShortBranchIssue(i, "myBranch")));
79 copier.tryMerge(component, Collections.emptyList());
81 verify(resolvedShortBranchIssuesLoader).loadCandidateIssuesForMergingInTargetBranch(component);
82 verifyZeroInteractions(issueLifecycle);
86 public void update_status_on_matches() {
87 DefaultIssue issue1 = createIssue("issue1", "rule1", Issue.STATUS_CONFIRMED, null, new Date());
88 ShortBranchIssue shortBranchIssue = newShortBranchIssue(issue1, "myBranch");
89 DefaultIssue newIssue = createIssue("issue2", "rule1", Issue.STATUS_OPEN, null, new Date());
91 when(resolvedShortBranchIssuesLoader.loadCandidateIssuesForMergingInTargetBranch(component)).thenReturn(Collections.singleton(shortBranchIssue));
92 when(resolvedShortBranchIssuesLoader.loadDefaultIssuesWithChanges(anyListOf(ShortBranchIssue.class))).thenReturn(ImmutableMap.of(shortBranchIssue, issue1));
93 copier.tryMerge(component, Collections.singleton(newIssue));
94 ArgumentCaptor<Collection> captor = ArgumentCaptor.forClass(Collection.class);
95 verify(resolvedShortBranchIssuesLoader).loadDefaultIssuesWithChanges(captor.capture());
96 assertThat(captor.getValue()).containsOnly(shortBranchIssue);
97 verify(issueLifecycle).mergeConfirmedOrResolvedFromShortLivingBranch(newIssue, issue1, "myBranch");
101 public void prefer_resolved_issues() {
102 ShortBranchIssue shortBranchIssue1 = newShortBranchIssue(createIssue("issue1", "rule1", Issue.STATUS_REOPENED, null, new Date()), "myBranch1");
103 ShortBranchIssue shortBranchIssue2 = newShortBranchIssue(createIssue("issue2", "rule1", Issue.STATUS_CONFIRMED, null, new Date()), "myBranch2");
104 DefaultIssue issue3 = createIssue("issue3", "rule1", Issue.STATUS_RESOLVED, Issue.RESOLUTION_FALSE_POSITIVE, new Date());
105 ShortBranchIssue shortBranchIssue3 = newShortBranchIssue(issue3, "myBranch3");
106 DefaultIssue newIssue = createIssue("newIssue", "rule1", Issue.STATUS_OPEN, null, new Date());
108 when(resolvedShortBranchIssuesLoader.loadCandidateIssuesForMergingInTargetBranch(component)).thenReturn(Arrays.asList(shortBranchIssue1, shortBranchIssue2, shortBranchIssue3));
109 when(resolvedShortBranchIssuesLoader.loadDefaultIssuesWithChanges(anyListOf(ShortBranchIssue.class))).thenReturn(ImmutableMap.of(shortBranchIssue3, issue3));
110 copier.tryMerge(component, Collections.singleton(newIssue));
111 verify(issueLifecycle).mergeConfirmedOrResolvedFromShortLivingBranch(newIssue, issue3, "myBranch3");
115 public void prefer_confirmed_issues() {
116 ShortBranchIssue shortBranchIssue1 = newShortBranchIssue(createIssue("issue1", "rule1", Issue.STATUS_REOPENED, null, new Date()), "myBranch1");
117 ShortBranchIssue shortBranchIssue2 = newShortBranchIssue(createIssue("issue2", "rule1", Issue.STATUS_OPEN, null, new Date()), "myBranch2");
118 DefaultIssue issue3 = createIssue("issue3", "rule1", Issue.STATUS_CONFIRMED, null, new Date());
119 ShortBranchIssue shortBranchIssue3 = newShortBranchIssue(issue3, "myBranch3");
120 DefaultIssue newIssue = createIssue("newIssue", "rule1", Issue.STATUS_OPEN, null, new Date());
122 when(resolvedShortBranchIssuesLoader.loadCandidateIssuesForMergingInTargetBranch(component)).thenReturn(Arrays.asList(shortBranchIssue1, shortBranchIssue2, shortBranchIssue3));
123 when(resolvedShortBranchIssuesLoader.loadDefaultIssuesWithChanges(anyListOf(ShortBranchIssue.class))).thenReturn(ImmutableMap.of(shortBranchIssue3, issue3));
124 copier.tryMerge(component, Collections.singleton(newIssue));
125 verify(issueLifecycle).mergeConfirmedOrResolvedFromShortLivingBranch(newIssue, issue3, "myBranch3");
129 public void prefer_older_issues() {
130 Instant now = Instant.now();
131 ShortBranchIssue shortBranchIssue1 = newShortBranchIssue(createIssue("issue1", "rule1", Issue.STATUS_REOPENED, null, Date.from(now.plus(2, ChronoUnit.SECONDS))), "myBranch1");
132 ShortBranchIssue shortBranchIssue2 = newShortBranchIssue(createIssue("issue2", "rule1", Issue.STATUS_OPEN, null, Date.from(now.plus(1, ChronoUnit.SECONDS))), "myBranch2");
133 DefaultIssue issue3 = createIssue("issue3", "rule1", Issue.STATUS_OPEN, null, Date.from(now));
134 ShortBranchIssue shortBranchIssue3 = newShortBranchIssue(issue3, "myBranch3");
135 DefaultIssue newIssue = createIssue("newIssue", "rule1", Issue.STATUS_OPEN, null, new Date());
137 when(resolvedShortBranchIssuesLoader.loadCandidateIssuesForMergingInTargetBranch(component)).thenReturn(Arrays.asList(shortBranchIssue1, shortBranchIssue2, shortBranchIssue3));
138 when(resolvedShortBranchIssuesLoader.loadDefaultIssuesWithChanges(anyListOf(ShortBranchIssue.class))).thenReturn(ImmutableMap.of(shortBranchIssue3, issue3));
139 copier.tryMerge(component, Collections.singleton(newIssue));
140 verify(issueLifecycle).mergeConfirmedOrResolvedFromShortLivingBranch(newIssue, issue3, "myBranch3");
143 private static DefaultIssue createIssue(String key, String ruleKey, String status, @Nullable String resolution, Date creationDate) {
144 DefaultIssue issue = new DefaultIssue();
146 issue.setRuleKey(RuleKey.of("repo", ruleKey));
147 issue.setMessage("msg");
149 issue.setStatus(status);
150 issue.setResolution(resolution);
151 issue.setCreationDate(creationDate);
155 private ShortBranchIssue newShortBranchIssue(DefaultIssue i, String originBranch) {
156 return new ShortBranchIssue(i.key(), i.line(), i.message(), i.getLineHash(), i.ruleKey(), i.status(), originBranch, i.creationDate());