]> source.dussan.org Git - sonarqube.git/blob
c3b720e872cea877a59740d9324d1e699257fbcb
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2017 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
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.
10  *
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.
15  *
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.
19  */
20 package org.sonar.server.computation.task.projectanalysis.issue;
21
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;
41
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;
47
48 public class ShortBranchIssueMergerTest {
49   @Mock
50   private ShortBranchIssuesLoader resolvedShortBranchIssuesLoader;
51   @Mock
52   private IssueLifecycle issueLifecycle;
53   @Mock
54   private Component component;
55
56   private SimpleTracker<DefaultIssue, ShortBranchIssue> tracker = new SimpleTracker<>();
57   private ShortBranchIssueMerger copier;
58
59   @Before
60   public void setUp() {
61     MockitoAnnotations.initMocks(this);
62     copier = new ShortBranchIssueMerger(resolvedShortBranchIssuesLoader, tracker, issueLifecycle);
63   }
64
65   @Test
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));
70
71     verify(resolvedShortBranchIssuesLoader).loadCandidateIssuesForMergingInTargetBranch(component);
72     verifyZeroInteractions(issueLifecycle);
73   }
74
75   @Test
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());
80
81     verify(resolvedShortBranchIssuesLoader).loadCandidateIssuesForMergingInTargetBranch(component);
82     verifyZeroInteractions(issueLifecycle);
83   }
84
85   @Test
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());
90
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");
98   }
99
100   @Test
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());
107
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");
112   }
113
114   @Test
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());
121
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");
126   }
127
128   @Test
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());
136
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");
141   }
142
143   private static DefaultIssue createIssue(String key, String ruleKey, String status, @Nullable String resolution, Date creationDate) {
144     DefaultIssue issue = new DefaultIssue();
145     issue.setKey(key);
146     issue.setRuleKey(RuleKey.of("repo", ruleKey));
147     issue.setMessage("msg");
148     issue.setLine(1);
149     issue.setStatus(status);
150     issue.setResolution(resolution);
151     issue.setCreationDate(creationDate);
152     return issue;
153   }
154
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());
157   }
158 }