]> source.dussan.org Git - sonarqube.git/blob
12db0e0bd17ef0cd8d3147414cfc51276dd55e66
[sonarqube.git] /
1 /*
2  * SonarQube, open source software quality management tool.
3  * Copyright (C) 2008-2013 SonarSource
4  * mailto:contact AT sonarsource DOT com
5  *
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.
10  *
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.
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
21 package org.sonar.plugins.core.issue;
22
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.issue.internal.DefaultIssue;
34 import org.sonar.api.measures.*;
35 import org.sonar.api.resources.Project;
36 import org.sonar.api.resources.Resource;
37 import org.sonar.api.resources.Scopes;
38 import org.sonar.api.rule.RuleKey;
39 import org.sonar.api.rule.Severity;
40 import org.sonar.api.rules.Rule;
41 import org.sonar.api.rules.RuleFinder;
42 import org.sonar.api.rules.RulePriority;
43 import org.sonar.api.test.IsRuleMeasure;
44 import org.sonar.batch.components.Period;
45 import org.sonar.batch.components.TimeMachineConfiguration;
46
47 import java.util.Calendar;
48 import java.util.Collections;
49 import java.util.Date;
50 import java.util.List;
51
52 import static com.google.common.collect.Lists.newArrayList;
53 import static org.fest.assertions.Assertions.assertThat;
54 import static org.mockito.Matchers.any;
55 import static org.mockito.Matchers.anyDouble;
56 import static org.mockito.Matchers.argThat;
57 import static org.mockito.Matchers.eq;
58 import static org.mockito.Mockito.*;
59
60 public class CountUnresolvedIssuesDecoratorTest {
61
62   CountUnresolvedIssuesDecorator decorator;
63   TimeMachineConfiguration timeMachineConfiguration;
64   RuleFinder ruleFinder;
65   Issuable issuable;
66   DecoratorContext context;
67   Resource resource;
68   Project project;
69   Rule ruleA1;
70   Rule ruleA2;
71   Rule ruleB1;
72   Date rightNow;
73   Date tenDaysAgo;
74   Date afterTenDaysAgo;
75   Date fiveDaysAgo;
76   Date afterFiveDaysAgo;
77   Date sameSecond;
78
79   @Before
80   public void before() {
81     ruleA1 = Rule.create().setRepositoryKey("ruleA1").setKey("ruleA1").setName("nameA1");
82     ruleA2 = Rule.create().setRepositoryKey("ruleA2").setKey("ruleA2").setName("nameA2");
83     ruleB1 = Rule.create().setRepositoryKey("ruleB1").setKey("ruleB1").setName("nameB1");
84
85     ruleFinder = mock(RuleFinder.class);
86     when(ruleFinder.findByKey(ruleA1.getRepositoryKey(), ruleA1.getKey())).thenReturn(ruleA1);
87     when(ruleFinder.findByKey(ruleA2.getRepositoryKey(), ruleA2.getKey())).thenReturn(ruleA2);
88     when(ruleFinder.findByKey(ruleB1.getRepositoryKey(), ruleB1.getKey())).thenReturn(ruleB1);
89
90     rightNow = new Date();
91     tenDaysAgo = DateUtils.addDays(rightNow, -10);
92     afterTenDaysAgo = DateUtils.addDays(tenDaysAgo, 1);
93     fiveDaysAgo = DateUtils.addDays(rightNow, -5);
94     afterFiveDaysAgo = DateUtils.addDays(fiveDaysAgo, 1);
95     sameSecond = DateUtils.truncate(rightNow, Calendar.SECOND);
96
97     timeMachineConfiguration = mock(TimeMachineConfiguration.class);
98     when(timeMachineConfiguration.periods()).thenReturn(newArrayList(new Period(1, fiveDaysAgo, afterFiveDaysAgo), new Period(2, tenDaysAgo, afterTenDaysAgo)));
99
100     project = mock(Project.class);
101     resource = mock(Resource.class);
102     context = mock(DecoratorContext.class);
103     when(context.getResource()).thenReturn(resource);
104     when(context.getProject()).thenReturn(project);
105     when(context.getMeasure(CoreMetrics.NEW_VIOLATIONS)).thenReturn(null);
106
107     issuable = mock(Issuable.class);
108     ResourcePerspectives perspectives = mock(ResourcePerspectives.class);
109     when(perspectives.as(Issuable.class, resource)).thenReturn(issuable);
110     decorator = new CountUnresolvedIssuesDecorator(perspectives, ruleFinder, timeMachineConfiguration);
111   }
112
113   @Test
114   public void should_be_depended_upon_metric() {
115     assertThat(decorator.generatesIssuesMetrics()).hasSize(15);
116   }
117
118   @Test
119   public void should_count_issues() {
120     when(resource.getScope()).thenReturn(Scopes.PROJECT);
121     when(issuable.issues()).thenReturn(createIssues());
122     when(context.getChildrenMeasures(any(MeasuresFilter.class))).thenReturn(Collections.<Measure>emptyList());
123
124     decorator.decorate(resource, context);
125
126     verify(context).saveMeasure(CoreMetrics.VIOLATIONS, 4.0);
127   }
128
129   @Test
130   public void should_do_nothing_when_issuable_is_null() {
131     ResourcePerspectives perspectives = mock(ResourcePerspectives.class);
132     when(perspectives.as(Issuable.class, resource)).thenReturn(null);
133     CountUnresolvedIssuesDecorator decorator = new CountUnresolvedIssuesDecorator(perspectives, ruleFinder, timeMachineConfiguration);
134
135     decorator.decorate(resource, context);
136
137     verifyZeroInteractions(context);
138   }
139
140   /**
141    * See http://jira.codehaus.org/browse/SONAR-1729
142    */
143   @Test
144   public void should_not_count_issues_if_measure_already_exists() {
145     when(resource.getScope()).thenReturn(Scopes.PROJECT);
146     when(issuable.issues()).thenReturn(createIssues());
147     when(context.getChildrenMeasures(any(MeasuresFilter.class))).thenReturn(Collections.<Measure>emptyList());
148     when(context.getMeasure(CoreMetrics.VIOLATIONS)).thenReturn(new Measure(CoreMetrics.VIOLATIONS, 3000.0));
149     when(context.getMeasure(CoreMetrics.MAJOR_VIOLATIONS)).thenReturn(new Measure(CoreMetrics.MAJOR_VIOLATIONS, 500.0));
150
151     decorator.decorate(resource, context);
152
153     verify(context, never()).saveMeasure(eq(CoreMetrics.VIOLATIONS), anyDouble());// not changed
154     verify(context, never()).saveMeasure(eq(CoreMetrics.MAJOR_VIOLATIONS), anyDouble());// not changed
155     verify(context, times(1)).saveMeasure(eq(CoreMetrics.CRITICAL_VIOLATIONS), anyDouble());// did not exist
156   }
157
158   @Test
159   public void should_save_zero_on_projects() {
160     when(resource.getScope()).thenReturn(Scopes.PROJECT);
161     when(issuable.issues()).thenReturn(Lists.<Issue>newArrayList());
162     when(context.getChildrenMeasures(any(MeasuresFilter.class))).thenReturn(Collections.<Measure>emptyList());
163
164     decorator.decorate(resource, context);
165
166     verify(context).saveMeasure(CoreMetrics.VIOLATIONS, 0.0);
167   }
168
169   @Test
170   public void should_save_zero_on_directories() {
171     when(resource.getScope()).thenReturn(Scopes.DIRECTORY);
172     when(issuable.issues()).thenReturn(Lists.<Issue>newArrayList());
173     when(context.getChildrenMeasures(any(MeasuresFilter.class))).thenReturn(Collections.<Measure>emptyList());
174
175     decorator.decorate(resource, context);
176
177     verify(context).saveMeasure(CoreMetrics.VIOLATIONS, 0.0);
178   }
179
180   @Test
181   public void should_count_issues_by_severity() {
182     when(resource.getScope()).thenReturn(Scopes.PROJECT);
183     when(issuable.issues()).thenReturn(createIssues());
184     when(context.getChildrenMeasures(any(MeasuresFilter.class))).thenReturn(Collections.<Measure>emptyList());
185
186     decorator.decorate(resource, context);
187
188     verify(context).saveMeasure(CoreMetrics.BLOCKER_VIOLATIONS, 0.0);
189     verify(context).saveMeasure(CoreMetrics.CRITICAL_VIOLATIONS, 2.0);
190     verify(context).saveMeasure(CoreMetrics.MAJOR_VIOLATIONS, 1.0);
191     verify(context).saveMeasure(CoreMetrics.MINOR_VIOLATIONS, 1.0);
192     verify(context).saveMeasure(CoreMetrics.INFO_VIOLATIONS, 0.0);
193   }
194
195   @Test
196   public void should_count_issues_per_rule() {
197     List<Issue> issues = newArrayList();
198     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()));
199     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()));
200     issues.add(new DefaultIssue().setRuleKey(ruleA2.ruleKey()).setSeverity(RulePriority.MAJOR.name()));
201     when(issuable.issues()).thenReturn(issues);
202
203     decorator.decorate(resource, context);
204
205     verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.CRITICAL_VIOLATIONS, ruleA1, 2.0)));
206     verify(context, never()).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.MAJOR_VIOLATIONS, ruleA1, 0.0)));
207     verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.MAJOR_VIOLATIONS, ruleA2, 1.0)));
208   }
209
210   @Test
211   public void same_rule_should_have_different_severities() {
212     List<Issue> issues = newArrayList();
213     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()));
214     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()));
215     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.MINOR.name()));
216     when(issuable.issues()).thenReturn(issues);
217
218     decorator.decorate(resource, context);
219
220     verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.CRITICAL_VIOLATIONS, ruleA1, 2.0)));
221     verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.MINOR_VIOLATIONS, ruleA1, 1.0)));
222   }
223
224   @Test
225   public void should_count_issues_after_date() {
226     List<Issue> issues = createIssuesForNewMetrics();
227
228     assertThat(decorator.countIssuesAfterDate(null, fiveDaysAgo)).isEqualTo(0);
229     assertThat(decorator.countIssuesAfterDate(issues, fiveDaysAgo)).isEqualTo(1); // 1 rightNow
230     assertThat(decorator.countIssuesAfterDate(issues, tenDaysAgo)).isEqualTo(3); // 1 rightNow + 2 fiveDaysAgo
231     assertThat(decorator.countIssuesAfterDate(issues, sameSecond)).isEqualTo(0); // 0
232   }
233
234   @Test
235   public void should_clear_cache_after_execution() {
236     Issue issue1 = new DefaultIssue().setRuleKey(RuleKey.of(ruleA1.getRepositoryKey(), ruleA1.getKey())).setSeverity(RulePriority.CRITICAL.name()).setCreationDate(rightNow);
237     Issue issue2 = new DefaultIssue().setRuleKey(RuleKey.of(ruleA2.getRepositoryKey(), ruleA2.getKey())).setSeverity(RulePriority.CRITICAL.name()).setCreationDate(rightNow);
238     when(issuable.issues()).thenReturn(newArrayList(issue1)).thenReturn(newArrayList(issue2));
239
240     decorator.decorate(resource, context);
241     decorator.decorate(resource, context);
242
243     verify(context, times(2)).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 1.0, 1.0)));
244     verify(context, never()).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 2.0, 2.0)));
245   }
246
247   @Test
248   public void should_save_severity_new_issues() {
249     when(issuable.issues()).thenReturn(createIssuesForNewMetrics());
250
251     decorator.decorate(resource, context);
252
253     // remember : period1 is 5daysAgo, period2 is 10daysAgo
254     verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_BLOCKER_VIOLATIONS, 0.0, 0.0)));
255     verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 1.0, 1.0)));
256     verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_MAJOR_VIOLATIONS, 0.0, 1.0)));
257     verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_MINOR_VIOLATIONS, 0.0, 1.0)));
258     verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_INFO_VIOLATIONS, 0.0, 0.0)));
259   }
260
261   @Test
262   public void should_save_rule_new_issues() {
263     when(issuable.issues()).thenReturn(createIssuesForNewMetrics());
264
265     decorator.decorate(resource, context);
266
267     // remember : period1 is 5daysAgo, period2 is 10daysAgo
268     verify(context).saveMeasure(argThat(new IsVariationRuleMeasure(CoreMetrics.NEW_CRITICAL_VIOLATIONS, ruleA1, 1.0, 1.0)));
269     verify(context).saveMeasure(argThat(new IsVariationRuleMeasure(CoreMetrics.NEW_MAJOR_VIOLATIONS, ruleA2, 0.0, 1.0)));
270     verify(context).saveMeasure(argThat(new IsVariationRuleMeasure(CoreMetrics.NEW_MINOR_VIOLATIONS, ruleB1, 0.0, 1.0)));
271   }
272
273   @Test
274   public void should_not_save_new_issues_if_measure_already_computed() {
275     when(context.getMeasure(CoreMetrics.NEW_VIOLATIONS)).thenReturn(new Measure());
276     when(issuable.issues()).thenReturn(createIssuesForNewMetrics());
277
278     decorator.decorate(resource, context);
279
280     verify(context, never()).saveMeasure(argThat(new IsMetricMeasure(CoreMetrics.NEW_BLOCKER_VIOLATIONS)));
281     verify(context, never()).saveMeasure(argThat(new IsMetricMeasure(CoreMetrics.NEW_CRITICAL_VIOLATIONS)));
282     verify(context, never()).saveMeasure(argThat(new IsMetricMeasure(CoreMetrics.NEW_MAJOR_VIOLATIONS)));
283     verify(context, never()).saveMeasure(argThat(new IsMetricMeasure(CoreMetrics.NEW_MINOR_VIOLATIONS)));
284     verify(context, never()).saveMeasure(argThat(new IsMetricMeasure(CoreMetrics.NEW_INFO_VIOLATIONS)));
285     verify(context, never()).saveMeasure(argThat(new IsMetricMeasure(CoreMetrics.NEW_CRITICAL_VIOLATIONS)));
286   }
287
288   List<Issue> createIssues() {
289     List<Issue> issues = newArrayList();
290     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(Severity.CRITICAL).setStatus(Issue.STATUS_OPEN));
291     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(Severity.CRITICAL).setStatus(Issue.STATUS_REOPENED));
292     issues.add(new DefaultIssue().setRuleKey(ruleA2.ruleKey()).setSeverity(Severity.MAJOR).setStatus(Issue.STATUS_REOPENED));
293     issues.add(new DefaultIssue().setRuleKey(ruleB1.ruleKey()).setSeverity(Severity.MINOR).setStatus(Issue.STATUS_OPEN));
294     return issues;
295   }
296
297   List<Issue> createIssuesForNewMetrics() {
298     List<Issue> issues = newArrayList();
299     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()).setCreationDate(rightNow).setStatus(Issue.STATUS_OPEN));
300     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()).setCreationDate(tenDaysAgo).setStatus(Issue.STATUS_OPEN));
301     issues.add(new DefaultIssue().setRuleKey(ruleA2.ruleKey()).setSeverity(RulePriority.MAJOR.name()).setCreationDate(fiveDaysAgo).setStatus(Issue.STATUS_REOPENED));
302     issues.add(new DefaultIssue().setRuleKey(ruleA2.ruleKey()).setSeverity(RulePriority.MAJOR.name()).setCreationDate(tenDaysAgo).setStatus(Issue.STATUS_REOPENED));
303     issues.add(new DefaultIssue().setRuleKey(ruleB1.ruleKey()).setSeverity(RulePriority.MINOR.name()).setCreationDate(fiveDaysAgo).setStatus(Issue.STATUS_OPEN));
304     issues.add(new DefaultIssue().setRuleKey(ruleB1.ruleKey()).setSeverity(RulePriority.MINOR.name()).setCreationDate(tenDaysAgo).setStatus(Issue.STATUS_OPEN));
305     return issues;
306   }
307
308   class IsVariationRuleMeasure extends ArgumentMatcher<Measure> {
309     Metric metric = null;
310     Rule rule = null;
311     Double var1 = null;
312     Double var2 = null;
313
314     public IsVariationRuleMeasure(Metric metric, Rule rule, Double var1, Double var2) {
315       this.metric = metric;
316       this.rule = rule;
317       this.var1 = var1;
318       this.var2 = var2;
319     }
320
321     public boolean matches(Object o) {
322       if (!(o instanceof RuleMeasure)) {
323         return false;
324       }
325       RuleMeasure m = (RuleMeasure) o;
326       return ObjectUtils.equals(metric, m.getMetric()) &&
327         ObjectUtils.equals(rule, m.getRule()) &&
328         ObjectUtils.equals(var1, m.getVariation1()) &&
329         ObjectUtils.equals(var2, m.getVariation2());
330     }
331   }
332
333   class IsVariationMeasure extends ArgumentMatcher<Measure> {
334     Metric metric = null;
335     Double var1 = null;
336     Double var2 = null;
337
338     public IsVariationMeasure(Metric metric, Double var1, Double var2) {
339       this.metric = metric;
340       this.var1 = var1;
341       this.var2 = var2;
342     }
343
344     public boolean matches(Object o) {
345       if (!(o instanceof Measure)) {
346         return false;
347       }
348       Measure m = (Measure) o;
349       return ObjectUtils.equals(metric, m.getMetric()) &&
350         ObjectUtils.equals(var1, m.getVariation1()) &&
351         ObjectUtils.equals(var2, m.getVariation2()) &&
352         !(m instanceof RuleMeasure);
353     }
354   }
355
356   class IsMetricMeasure extends ArgumentMatcher<Measure> {
357     Metric metric = null;
358
359     public IsMetricMeasure(Metric metric) {
360       this.metric = metric;
361     }
362
363     public boolean matches(Object o) {
364       if (!(o instanceof Measure)) {
365         return false;
366       }
367       Measure m = (Measure) o;
368       return ObjectUtils.equals(metric, m.getMetric());
369     }
370   }
371 }