2 * SonarQube, open source software quality management tool.
3 * Copyright (C) 2008-2013 SonarSource
4 * mailto:contact AT sonarsource DOT com
6 * SonarQube 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 * SonarQube 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.
21 package org.sonar.plugins.core.issue;
23 import com.google.common.collect.Lists;
24 import org.apache.commons.lang.ObjectUtils;
25 import org.apache.commons.lang.time.DateUtils;
26 import org.junit.Before;
27 import org.junit.Test;
28 import org.mockito.ArgumentMatcher;
29 import org.sonar.api.batch.DecoratorContext;
30 import org.sonar.api.component.ResourcePerspectives;
31 import org.sonar.api.issue.Issuable;
32 import org.sonar.api.issue.Issue;
33 import org.sonar.api.measures.*;
34 import org.sonar.api.resources.Project;
35 import org.sonar.api.resources.Resource;
36 import org.sonar.api.resources.Scopes;
37 import org.sonar.api.rule.RuleKey;
38 import org.sonar.api.rule.Severity;
39 import org.sonar.api.rules.Rule;
40 import org.sonar.api.rules.RuleFinder;
41 import org.sonar.api.rules.RulePriority;
42 import org.sonar.api.test.IsRuleMeasure;
43 import org.sonar.batch.components.PastSnapshot;
44 import org.sonar.batch.components.TimeMachineConfiguration;
45 import org.sonar.core.issue.DefaultIssue;
47 import java.util.Arrays;
48 import java.util.Collections;
49 import java.util.Date;
50 import java.util.List;
52 import static com.google.common.collect.Lists.newArrayList;
53 import static org.fest.assertions.Assertions.assertThat;
54 import static org.mockito.Mockito.*;
56 public class CountUnresolvedIssuesDecoratorTest {
58 CountUnresolvedIssuesDecorator decorator;
59 TimeMachineConfiguration timeMachineConfiguration;
60 RuleFinder ruleFinder;
62 DecoratorContext context;
73 public void before() {
74 ruleA1 = Rule.create().setRepositoryKey("ruleA1").setKey("ruleA1").setName("nameA1");
75 ruleA2 = Rule.create().setRepositoryKey("ruleA2").setKey("ruleA2").setName("nameA2");
76 ruleB1 = Rule.create().setRepositoryKey("ruleB1").setKey("ruleB1").setName("nameB1");
78 ruleFinder = mock(RuleFinder.class);
79 when(ruleFinder.findByKey(ruleA1.getRepositoryKey(), ruleA1.getKey())).thenReturn(ruleA1);
80 when(ruleFinder.findByKey(ruleA2.getRepositoryKey(), ruleA2.getKey())).thenReturn(ruleA2);
81 when(ruleFinder.findByKey(ruleB1.getRepositoryKey(), ruleB1.getKey())).thenReturn(ruleB1);
83 rightNow = new Date();
84 tenDaysAgo = DateUtils.addDays(rightNow, -10);
85 fiveDaysAgo = DateUtils.addDays(rightNow, -5);
87 PastSnapshot pastSnapshot = mock(PastSnapshot.class);
88 when(pastSnapshot.getIndex()).thenReturn(1);
89 when(pastSnapshot.getTargetDate()).thenReturn(fiveDaysAgo);
91 PastSnapshot pastSnapshot2 = mock(PastSnapshot.class);
92 when(pastSnapshot2.getIndex()).thenReturn(2);
93 when(pastSnapshot2.getTargetDate()).thenReturn(tenDaysAgo);
95 timeMachineConfiguration = mock(TimeMachineConfiguration.class);
96 when(timeMachineConfiguration.getProjectPastSnapshots()).thenReturn(Arrays.asList(pastSnapshot, pastSnapshot2));
98 project = mock(Project.class);
99 resource = mock(Resource.class);
100 context = mock(DecoratorContext.class);
101 when(context.getResource()).thenReturn(resource);
102 when(context.getProject()).thenReturn(project);
103 when(context.getMeasure(CoreMetrics.NEW_VIOLATIONS)).thenReturn(null);
105 issuable = mock(Issuable.class);
106 ResourcePerspectives perspectives = mock(ResourcePerspectives.class);
107 when(perspectives.as(Issuable.class, resource)).thenReturn(issuable);
108 decorator = new CountUnresolvedIssuesDecorator(perspectives, ruleFinder, timeMachineConfiguration);
112 public void should_be_depended_upon_metric() {
113 assertThat(decorator.generatesIssuesMetrics()).hasSize(15);
117 public void should_count_issues() {
118 when(resource.getScope()).thenReturn(Scopes.PROJECT);
119 when(issuable.unresolvedIssues()).thenReturn(createIssues());
120 when(context.getChildrenMeasures(any(MeasuresFilter.class))).thenReturn(Collections.<Measure>emptyList());
122 decorator.decorate(resource, context);
124 verify(context).saveMeasure(CoreMetrics.VIOLATIONS, 4.0);
128 public void should_do_nothing_when_issuable_is_null() {
129 ResourcePerspectives perspectives = mock(ResourcePerspectives.class);
130 when(perspectives.as(Issuable.class, resource)).thenReturn(null);
131 CountUnresolvedIssuesDecorator decorator = new CountUnresolvedIssuesDecorator(perspectives, ruleFinder, timeMachineConfiguration);
133 decorator.decorate(resource, context);
135 verifyZeroInteractions(context);
139 * See http://jira.codehaus.org/browse/SONAR-1729
142 public void should_not_count_issues_if_measure_already_exists() {
143 when(resource.getScope()).thenReturn(Scopes.PROJECT);
144 when(issuable.unresolvedIssues()).thenReturn(createIssues());
145 when(context.getChildrenMeasures(any(MeasuresFilter.class))).thenReturn(Collections.<Measure>emptyList());
146 when(context.getMeasure(CoreMetrics.VIOLATIONS)).thenReturn(new Measure(CoreMetrics.VIOLATIONS, 3000.0));
147 when(context.getMeasure(CoreMetrics.MAJOR_VIOLATIONS)).thenReturn(new Measure(CoreMetrics.MAJOR_VIOLATIONS, 500.0));
149 decorator.decorate(resource, context);
151 verify(context, never()).saveMeasure(eq(CoreMetrics.VIOLATIONS), anyDouble());// not changed
152 verify(context, never()).saveMeasure(eq(CoreMetrics.MAJOR_VIOLATIONS), anyDouble());// not changed
153 verify(context, times(1)).saveMeasure(eq(CoreMetrics.CRITICAL_VIOLATIONS), anyDouble());// did not exist
157 public void should_save_zero_on_projects() {
158 when(resource.getScope()).thenReturn(Scopes.PROJECT);
159 when(issuable.unresolvedIssues()).thenReturn(Lists.<Issue>newArrayList());
160 when(context.getChildrenMeasures(any(MeasuresFilter.class))).thenReturn(Collections.<Measure>emptyList());
162 decorator.decorate(resource, context);
164 verify(context).saveMeasure(CoreMetrics.VIOLATIONS, 0.0);
168 public void should_save_zero_on_directories() {
169 when(resource.getScope()).thenReturn(Scopes.DIRECTORY);
170 when(issuable.unresolvedIssues()).thenReturn(Lists.<Issue>newArrayList());
171 when(context.getChildrenMeasures(any(MeasuresFilter.class))).thenReturn(Collections.<Measure>emptyList());
173 decorator.decorate(resource, context);
175 verify(context).saveMeasure(CoreMetrics.VIOLATIONS, 0.0);
179 public void should_count_issues_by_severity() {
180 when(resource.getScope()).thenReturn(Scopes.PROJECT);
181 when(issuable.unresolvedIssues()).thenReturn(createIssues());
182 when(context.getChildrenMeasures(any(MeasuresFilter.class))).thenReturn(Collections.<Measure>emptyList());
184 decorator.decorate(resource, context);
186 verify(context).saveMeasure(CoreMetrics.BLOCKER_VIOLATIONS, 0.0);
187 verify(context).saveMeasure(CoreMetrics.CRITICAL_VIOLATIONS, 2.0);
188 verify(context).saveMeasure(CoreMetrics.MAJOR_VIOLATIONS, 1.0);
189 verify(context).saveMeasure(CoreMetrics.MINOR_VIOLATIONS, 1.0);
190 verify(context).saveMeasure(CoreMetrics.INFO_VIOLATIONS, 0.0);
194 public void should_count_issues_per_rule() {
195 List<Issue> issues = newArrayList();
196 issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()));
197 issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()));
198 issues.add(new DefaultIssue().setRuleKey(ruleA2.ruleKey()).setSeverity(RulePriority.MAJOR.name()));
199 when(issuable.unresolvedIssues()).thenReturn(issues);
201 decorator.decorate(resource, context);
203 verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.CRITICAL_VIOLATIONS, ruleA1, 2.0)));
204 verify(context, never()).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.MAJOR_VIOLATIONS, ruleA1, 0.0)));
205 verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.MAJOR_VIOLATIONS, ruleA2, 1.0)));
209 public void same_rule_should_have_different_severities() {
210 List<Issue> issues = newArrayList();
211 issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()));
212 issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()));
213 issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.MINOR.name()));
214 when(issuable.unresolvedIssues()).thenReturn(issues);
216 decorator.decorate(resource, context);
218 verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.CRITICAL_VIOLATIONS, ruleA1, 2.0)));
219 verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.MINOR_VIOLATIONS, ruleA1, 1.0)));
223 public void should_count_issues_after_date() {
224 List<Issue> issues = createIssuesForNewMetrics();
226 assertThat(decorator.countIssuesAfterDate(null, fiveDaysAgo)).isEqualTo(0);
227 assertThat(decorator.countIssuesAfterDate(issues, fiveDaysAgo)).isEqualTo(1); // 1 rightNow
228 assertThat(decorator.countIssuesAfterDate(issues, tenDaysAgo)).isEqualTo(3); // 1 rightNow + 2 fiveDaysAgo
232 public void should_clear_cache_after_execution() {
233 Issue issue1 = new DefaultIssue().setRuleKey(RuleKey.of(ruleA1.getRepositoryKey(), ruleA1.getKey())).setSeverity(RulePriority.CRITICAL.name()).setCreationDate(rightNow);
234 Issue issue2 = new DefaultIssue().setRuleKey(RuleKey.of(ruleA2.getRepositoryKey(), ruleA2.getKey())).setSeverity(RulePriority.CRITICAL.name()).setCreationDate(rightNow);
235 when(issuable.unresolvedIssues()).thenReturn(newArrayList(issue1)).thenReturn(newArrayList(issue2));
237 decorator.decorate(resource, context);
238 decorator.decorate(resource, context);
240 verify(context, times(2)).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 1.0, 1.0)));
241 verify(context, never()).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 2.0, 2.0)));
245 public void should_save_severity_new_issues() {
246 when(issuable.unresolvedIssues()).thenReturn(createIssuesForNewMetrics());
248 decorator.decorate(resource, context);
250 // remember : period1 is 5daysAgo, period2 is 10daysAgo
251 verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_BLOCKER_VIOLATIONS, 0.0, 0.0)));
252 verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 1.0, 1.0)));
253 verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_MAJOR_VIOLATIONS, 0.0, 1.0)));
254 verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_MINOR_VIOLATIONS, 0.0, 1.0)));
255 verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_INFO_VIOLATIONS, 0.0, 0.0)));
259 public void should_save_rule_new_issues() {
260 when(issuable.unresolvedIssues()).thenReturn(createIssuesForNewMetrics());
262 decorator.decorate(resource, context);
264 // remember : period1 is 5daysAgo, period2 is 10daysAgo
265 verify(context).saveMeasure(argThat(new IsVariationRuleMeasure(CoreMetrics.NEW_CRITICAL_VIOLATIONS, ruleA1, 1.0, 1.0)));
266 verify(context).saveMeasure(argThat(new IsVariationRuleMeasure(CoreMetrics.NEW_MAJOR_VIOLATIONS, ruleA2, 0.0, 1.0)));
267 verify(context).saveMeasure(argThat(new IsVariationRuleMeasure(CoreMetrics.NEW_MINOR_VIOLATIONS, ruleB1, 0.0, 1.0)));
271 public void should_not_save_new_issues_if_measure_already_computed() {
272 when(context.getMeasure(CoreMetrics.NEW_VIOLATIONS)).thenReturn(new Measure());
273 when(issuable.unresolvedIssues()).thenReturn(createIssuesForNewMetrics());
275 decorator.decorate(resource, context);
277 verify(context, never()).saveMeasure(argThat(new IsMetricMeasure(CoreMetrics.NEW_BLOCKER_VIOLATIONS)));
278 verify(context, never()).saveMeasure(argThat(new IsMetricMeasure(CoreMetrics.NEW_CRITICAL_VIOLATIONS)));
279 verify(context, never()).saveMeasure(argThat(new IsMetricMeasure(CoreMetrics.NEW_MAJOR_VIOLATIONS)));
280 verify(context, never()).saveMeasure(argThat(new IsMetricMeasure(CoreMetrics.NEW_MINOR_VIOLATIONS)));
281 verify(context, never()).saveMeasure(argThat(new IsMetricMeasure(CoreMetrics.NEW_INFO_VIOLATIONS)));
282 verify(context, never()).saveMeasure(argThat(new IsMetricMeasure(CoreMetrics.NEW_CRITICAL_VIOLATIONS)));
285 List<Issue> createIssues() {
286 List<Issue> issues = newArrayList();
287 issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(Severity.CRITICAL).setStatus(Issue.STATUS_OPEN));
288 issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(Severity.CRITICAL).setStatus(Issue.STATUS_REOPENED));
289 issues.add(new DefaultIssue().setRuleKey(ruleA2.ruleKey()).setSeverity(Severity.MAJOR).setStatus(Issue.STATUS_REOPENED));
290 issues.add(new DefaultIssue().setRuleKey(ruleB1.ruleKey()).setSeverity(Severity.MINOR).setStatus(Issue.STATUS_OPEN));
294 List<Issue> createIssuesForNewMetrics() {
295 List<Issue> issues = newArrayList();
296 issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()).setCreationDate(rightNow).setStatus(Issue.STATUS_OPEN));
297 issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()).setCreationDate(tenDaysAgo).setStatus(Issue.STATUS_OPEN));
298 issues.add(new DefaultIssue().setRuleKey(ruleA2.ruleKey()).setSeverity(RulePriority.MAJOR.name()).setCreationDate(fiveDaysAgo).setStatus(Issue.STATUS_REOPENED));
299 issues.add(new DefaultIssue().setRuleKey(ruleA2.ruleKey()).setSeverity(RulePriority.MAJOR.name()).setCreationDate(tenDaysAgo).setStatus(Issue.STATUS_REOPENED));
300 issues.add(new DefaultIssue().setRuleKey(ruleB1.ruleKey()).setSeverity(RulePriority.MINOR.name()).setCreationDate(fiveDaysAgo).setStatus(Issue.STATUS_OPEN));
301 issues.add(new DefaultIssue().setRuleKey(ruleB1.ruleKey()).setSeverity(RulePriority.MINOR.name()).setCreationDate(tenDaysAgo).setStatus(Issue.STATUS_OPEN));
305 class IsVariationRuleMeasure extends ArgumentMatcher<Measure> {
306 Metric metric = null;
311 public IsVariationRuleMeasure(Metric metric, Rule rule, Double var1, Double var2) {
312 this.metric = metric;
318 public boolean matches(Object o) {
319 if (!(o instanceof RuleMeasure)) {
322 RuleMeasure m = (RuleMeasure) o;
323 return ObjectUtils.equals(metric, m.getMetric()) &&
324 ObjectUtils.equals(rule, m.getRule()) &&
325 ObjectUtils.equals(var1, m.getVariation1()) &&
326 ObjectUtils.equals(var2, m.getVariation2());
330 class IsVariationMeasure extends ArgumentMatcher<Measure> {
331 Metric metric = null;
335 public IsVariationMeasure(Metric metric, Double var1, Double var2) {
336 this.metric = metric;
341 public boolean matches(Object o) {
342 if (!(o instanceof Measure)) {
345 Measure m = (Measure) o;
346 return ObjectUtils.equals(metric, m.getMetric()) &&
347 ObjectUtils.equals(var1, m.getVariation1()) &&
348 ObjectUtils.equals(var2, m.getVariation2()) &&
349 !(m instanceof RuleMeasure);
353 class IsMetricMeasure extends ArgumentMatcher<Measure> {
354 Metric metric = null;
356 public IsMetricMeasure(Metric metric) {
357 this.metric = metric;
360 public boolean matches(Object o) {
361 if (!(o instanceof Measure)) {
364 Measure m = (Measure) o;
365 return ObjectUtils.equals(metric, m.getMetric());