]> source.dussan.org Git - sonarqube.git/blob
186d71d7432d4cfb47eea4dd3a4cef70e979df75
[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.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.rules.Rule;
39 import org.sonar.api.rules.RuleFinder;
40 import org.sonar.api.rules.RulePriority;
41 import org.sonar.api.test.IsRuleMeasure;
42 import org.sonar.batch.components.PastSnapshot;
43 import org.sonar.batch.components.TimeMachineConfiguration;
44 import org.sonar.core.issue.DefaultIssue;
45
46 import java.util.Arrays;
47 import java.util.Collections;
48 import java.util.Date;
49 import java.util.List;
50
51 import static com.google.common.collect.Lists.newArrayList;
52 import static org.fest.assertions.Assertions.assertThat;
53 import static org.mockito.Mockito.*;
54
55 public class CountOpenIssuesDecoratorTest {
56
57   CountOpenIssuesDecorator decorator;
58   TimeMachineConfiguration timeMachineConfiguration;
59   RuleFinder ruleFinder;
60   Issuable issuable;
61   DecoratorContext context;
62   Resource resource;
63   Project project;
64   Rule ruleA1;
65   Rule ruleA2;
66   Rule ruleB1;
67   Date rightNow;
68   Date tenDaysAgo;
69   Date fiveDaysAgo;
70
71   @Before
72   public void before() {
73     ruleA1 = Rule.create().setRepositoryKey("ruleA1").setKey("ruleA1").setName("nameA1");
74     ruleA2 = Rule.create().setRepositoryKey("ruleA2").setKey("ruleA2").setName("nameA2");
75     ruleB1 = Rule.create().setRepositoryKey("ruleB1").setKey("ruleB1").setName("nameB1");
76
77     ruleFinder = mock(RuleFinder.class);
78     when(ruleFinder.findByKey(ruleA1.getRepositoryKey(), ruleA1.getKey())).thenReturn(ruleA1);
79     when(ruleFinder.findByKey(ruleA2.getRepositoryKey(), ruleA2.getKey())).thenReturn(ruleA2);
80     when(ruleFinder.findByKey(ruleB1.getRepositoryKey(), ruleB1.getKey())).thenReturn(ruleB1);
81
82     rightNow = new Date();
83     tenDaysAgo = DateUtils.addDays(rightNow, -10);
84     fiveDaysAgo = DateUtils.addDays(rightNow, -5);
85
86     PastSnapshot pastSnapshot = mock(PastSnapshot.class);
87     when(pastSnapshot.getIndex()).thenReturn(1);
88     when(pastSnapshot.getTargetDate()).thenReturn(fiveDaysAgo);
89
90     PastSnapshot pastSnapshot2 = mock(PastSnapshot.class);
91     when(pastSnapshot2.getIndex()).thenReturn(2);
92     when(pastSnapshot2.getTargetDate()).thenReturn(tenDaysAgo);
93
94     timeMachineConfiguration = mock(TimeMachineConfiguration.class);
95     when(timeMachineConfiguration.getProjectPastSnapshots()).thenReturn(Arrays.asList(pastSnapshot, pastSnapshot2));
96
97     project = mock(Project.class);
98     when(project.isLatestAnalysis()).thenReturn(true);
99
100     resource = mock(Resource.class);
101     context = mock(DecoratorContext.class);
102     when(context.getResource()).thenReturn(resource);
103     when(context.getProject()).thenReturn(project);
104     when(context.getMeasure(CoreMetrics.NEW_ISSUES)).thenReturn(null);
105
106     issuable = mock(Issuable.class);
107     ResourcePerspectives perspectives = mock(ResourcePerspectives.class);
108     when(perspectives.as(Issuable.class, resource)).thenReturn(issuable);
109     decorator = new CountOpenIssuesDecorator(perspectives, ruleFinder, timeMachineConfiguration);
110   }
111
112   @Test
113   public void should_be_depended_upon_metric() {
114     assertThat(decorator.generatesIssuesMetrics()).hasSize(16);
115   }
116
117   @Test
118   public void should_count_issues() {
119     when(resource.getScope()).thenReturn(Scopes.PROJECT);
120     when(issuable.issues()).thenReturn(createIssues());
121     when(context.getChildrenMeasures(any(MeasuresFilter.class))).thenReturn(Collections.<Measure>emptyList());
122
123     decorator.decorate(resource, context);
124
125     verify(context).saveMeasure(CoreMetrics.ISSUES, 4.0);
126   }
127
128   @Test
129   public void should_do_nothing_when_issuable_is_null() {
130     ResourcePerspectives perspectives = mock(ResourcePerspectives.class);
131     when(perspectives.as(Issuable.class, resource)).thenReturn(null);
132     CountOpenIssuesDecorator decorator = new CountOpenIssuesDecorator(perspectives, ruleFinder, timeMachineConfiguration);
133
134     decorator.decorate(resource, context);
135
136     verifyZeroInteractions(context);
137   }
138
139   /**
140    * See http://jira.codehaus.org/browse/SONAR-1729
141    */
142   @Test
143   public void should_not_count_issues_if_measure_already_exists() {
144     when(resource.getScope()).thenReturn(Scopes.PROJECT);
145     when(issuable.issues()).thenReturn(createIssues());
146     when(context.getChildrenMeasures(any(MeasuresFilter.class))).thenReturn(Collections.<Measure>emptyList());
147     when(context.getMeasure(CoreMetrics.ISSUES)).thenReturn(new Measure(CoreMetrics.ISSUES, 3000.0));
148     when(context.getMeasure(CoreMetrics.MAJOR_ISSUES)).thenReturn(new Measure(CoreMetrics.MAJOR_ISSUES, 500.0));
149
150     decorator.decorate(resource, context);
151
152     verify(context, never()).saveMeasure(eq(CoreMetrics.ISSUES), anyDouble());// not changed
153     verify(context, never()).saveMeasure(eq(CoreMetrics.MAJOR_ISSUES), anyDouble());// not changed
154     verify(context, times(1)).saveMeasure(eq(CoreMetrics.CRITICAL_ISSUES), anyDouble());// did not exist
155   }
156
157   @Test
158   public void should_save_zero_on_projects() {
159     when(resource.getScope()).thenReturn(Scopes.PROJECT);
160     when(issuable.issues()).thenReturn(Lists.<Issue>newArrayList());
161     when(context.getChildrenMeasures(any(MeasuresFilter.class))).thenReturn(Collections.<Measure>emptyList());
162
163     decorator.decorate(resource, context);
164
165     verify(context).saveMeasure(CoreMetrics.ISSUES, 0.0);
166   }
167
168   @Test
169   public void should_save_zero_on_directories() {
170     when(resource.getScope()).thenReturn(Scopes.DIRECTORY);
171     when(issuable.issues()).thenReturn(Lists.<Issue>newArrayList());
172     when(context.getChildrenMeasures(any(MeasuresFilter.class))).thenReturn(Collections.<Measure>emptyList());
173
174     decorator.decorate(resource, context);
175
176     verify(context).saveMeasure(CoreMetrics.ISSUES, 0.0);
177   }
178
179   @Test
180   public void should_count_issues_by_severity() {
181     when(resource.getScope()).thenReturn(Scopes.PROJECT);
182     when(issuable.issues()).thenReturn(createIssues());
183     when(context.getChildrenMeasures(any(MeasuresFilter.class))).thenReturn(Collections.<Measure>emptyList());
184
185     decorator.decorate(resource, context);
186
187     verify(context).saveMeasure(CoreMetrics.BLOCKER_ISSUES, 0.0);
188     verify(context).saveMeasure(CoreMetrics.CRITICAL_ISSUES, 2.0);
189     verify(context).saveMeasure(CoreMetrics.MAJOR_ISSUES, 1.0);
190     verify(context).saveMeasure(CoreMetrics.MINOR_ISSUES, 1.0);
191     verify(context).saveMeasure(CoreMetrics.INFO_ISSUES, 0.0);
192   }
193
194   @Test
195   public void should_count_issues_per_rule() {
196     List<Issue> issues = newArrayList();
197     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()));
198     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()));
199     issues.add(new DefaultIssue().setRuleKey(ruleA2.ruleKey()).setSeverity(RulePriority.MAJOR.name()));
200     when(issuable.issues()).thenReturn(issues);
201
202     decorator.decorate(resource, context);
203
204     verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.CRITICAL_ISSUES, ruleA1, 2.0)));
205     verify(context, never()).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.MAJOR_ISSUES, ruleA1, 0.0)));
206     verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.MAJOR_ISSUES, ruleA2, 1.0)));
207   }
208
209   @Test
210   public void should_save_unassigned_issues() {
211     List<Issue> issues = newArrayList();
212     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setStatus(Issue.STATUS_OPEN).setSeverity(RulePriority.CRITICAL.name()));
213     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setStatus(Issue.STATUS_REOPENED).setSeverity(RulePriority.CRITICAL.name()));
214     issues.add(new DefaultIssue().setRuleKey(ruleA2.ruleKey()).setStatus(Issue.STATUS_OPEN).setAssignee("arthur").setSeverity(RulePriority.CRITICAL.name()));
215     when(issuable.issues()).thenReturn(issues);
216
217     decorator.decorate(resource, context);
218
219     verify(context).saveMeasure(CoreMetrics.UNASSIGNED_ISSUES, 2.0);
220   }
221
222   @Test
223   public void should_save_open_issues() {
224     List<Issue> issues = newArrayList();
225     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setStatus(Issue.STATUS_OPEN).setSeverity(RulePriority.CRITICAL.name()));
226     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setStatus(Issue.STATUS_REOPENED).setSeverity(RulePriority.CRITICAL.name()));
227     issues.add(new DefaultIssue().setRuleKey(ruleA2.ruleKey()).setStatus(Issue.STATUS_OPEN).setSeverity(RulePriority.CRITICAL.name()));
228     when(issuable.issues()).thenReturn(issues);
229
230     decorator.decorate(resource, context);
231
232     verify(context).saveMeasure(CoreMetrics.OPEN_ISSUES, 2.0);
233   }
234
235   @Test
236   public void should_save_reopened_issues() {
237     List<Issue> issues = newArrayList();
238     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setStatus(Issue.STATUS_OPEN).setSeverity(RulePriority.CRITICAL.name()));
239     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setStatus(Issue.STATUS_REOPENED).setSeverity(RulePriority.CRITICAL.name()));
240     issues.add(new DefaultIssue().setRuleKey(ruleA2.ruleKey()).setStatus(Issue.STATUS_OPEN).setSeverity(RulePriority.CRITICAL.name()));
241     when(issuable.issues()).thenReturn(issues);
242
243     decorator.decorate(resource, context);
244
245     verify(context).saveMeasure(CoreMetrics.REOPENED_ISSUES, 1.0);
246   }
247
248
249   @Test
250   public void should_save_confirmed_issues() {
251     List<Issue> issues = newArrayList();
252     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setStatus(Issue.STATUS_CONFIRMED).setSeverity(RulePriority.CRITICAL.name()));
253     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setStatus(Issue.STATUS_REOPENED).setSeverity(RulePriority.CRITICAL.name()));
254     issues.add(new DefaultIssue().setRuleKey(ruleA2.ruleKey()).setStatus(Issue.STATUS_CONFIRMED).setSeverity(RulePriority.CRITICAL.name()));
255     when(issuable.issues()).thenReturn(issues);
256
257     decorator.decorate(resource, context);
258
259     verify(context).saveMeasure(CoreMetrics.CONFIRMED_ISSUES, 2.0);
260   }
261
262   @Test
263   public void same_rule_should_have_different_severities() {
264     List<Issue> issues = newArrayList();
265     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()));
266     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()));
267     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.MINOR.name()));
268     when(issuable.issues()).thenReturn(issues);
269
270     decorator.decorate(resource, context);
271
272     verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.CRITICAL_ISSUES, ruleA1, 2.0)));
273     verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.MINOR_ISSUES, ruleA1, 1.0)));
274   }
275
276   @Test
277   public void should_count_issues_after_date() {
278     List<Issue> issues = createIssuesForNewMetrics();
279
280     assertThat(decorator.countIssuesAfterDate(null, fiveDaysAgo)).isEqualTo(0);
281     assertThat(decorator.countIssuesAfterDate(issues, fiveDaysAgo)).isEqualTo(1); // 1 rightNow
282     assertThat(decorator.countIssuesAfterDate(issues, tenDaysAgo)).isEqualTo(3); // 1 rightNow + 2 fiveDaysAgo
283   }
284
285   @Test
286   public void should_clear_cache_after_execution() {
287     Issue issue1 = new DefaultIssue().setRuleKey(RuleKey.of(ruleA1.getRepositoryKey(), ruleA1.getKey())).setSeverity(RulePriority.CRITICAL.name()).setCreationDate(rightNow);
288     Issue issue2 = new DefaultIssue().setRuleKey(RuleKey.of(ruleA2.getRepositoryKey(), ruleA2.getKey())).setSeverity(RulePriority.CRITICAL.name()).setCreationDate(rightNow);
289     when(issuable.issues()).thenReturn(newArrayList(issue1)).thenReturn(newArrayList(issue2));
290
291     decorator.decorate(resource, context);
292     decorator.decorate(resource, context);
293
294     verify(context, times(2)).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_CRITICAL_ISSUES, 1.0, 1.0)));
295     verify(context, never()).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_CRITICAL_ISSUES, 2.0, 2.0)));
296   }
297
298   @Test
299   public void should_save_severity_new_issues() {
300     when(issuable.issues()).thenReturn(createIssuesForNewMetrics());
301
302     decorator.decorate(resource, context);
303
304     // remember : period1 is 5daysAgo, period2 is 10daysAgo
305     verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_BLOCKER_ISSUES, 0.0, 0.0)));
306     verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_CRITICAL_ISSUES, 1.0, 1.0)));
307     verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_MAJOR_ISSUES, 0.0, 1.0)));
308     verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_MINOR_ISSUES, 0.0, 1.0)));
309     verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_INFO_ISSUES, 0.0, 0.0)));
310   }
311
312   @Test
313   public void should_save_rule_new_issues() {
314     when(issuable.issues()).thenReturn(createIssuesForNewMetrics());
315
316     decorator.decorate(resource, context);
317
318     // remember : period1 is 5daysAgo, period2 is 10daysAgo
319     verify(context).saveMeasure(argThat(new IsVariationRuleMeasure(CoreMetrics.NEW_CRITICAL_ISSUES, ruleA1, 1.0, 1.0)));
320     verify(context).saveMeasure(argThat(new IsVariationRuleMeasure(CoreMetrics.NEW_MAJOR_ISSUES, ruleA2, 0.0, 1.0)));
321     verify(context).saveMeasure(argThat(new IsVariationRuleMeasure(CoreMetrics.NEW_MINOR_ISSUES, ruleB1, 0.0, 1.0)));
322   }
323
324   @Test
325   public void should_not_save_new_issues_if_not_last_analysis() {
326     when(project.isLatestAnalysis()).thenReturn(false);
327     when(issuable.issues()).thenReturn(createIssuesForNewMetrics());
328
329     decorator.decorate(resource, context);
330
331     verify(context, never()).saveMeasure(argThat(new IsMetricMeasure(CoreMetrics.NEW_BLOCKER_ISSUES)));
332     verify(context, never()).saveMeasure(argThat(new IsMetricMeasure(CoreMetrics.NEW_CRITICAL_ISSUES)));
333     verify(context, never()).saveMeasure(argThat(new IsMetricMeasure(CoreMetrics.NEW_MAJOR_ISSUES)));
334     verify(context, never()).saveMeasure(argThat(new IsMetricMeasure(CoreMetrics.NEW_MINOR_ISSUES)));
335     verify(context, never()).saveMeasure(argThat(new IsMetricMeasure(CoreMetrics.NEW_INFO_ISSUES)));
336     verify(context, never()).saveMeasure(argThat(new IsMetricMeasure(CoreMetrics.NEW_CRITICAL_ISSUES)));
337   }
338
339   List<Issue> createIssues() {
340     List<Issue> issues = newArrayList();
341     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()).setStatus(Issue.STATUS_OPEN));
342     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()).setStatus(Issue.STATUS_REOPENED));
343     issues.add(new DefaultIssue().setRuleKey(ruleA2.ruleKey()).setSeverity(RulePriority.MAJOR.name()).setStatus(Issue.STATUS_REOPENED));
344     issues.add(new DefaultIssue().setRuleKey(ruleB1.ruleKey()).setSeverity(RulePriority.MINOR.name()).setStatus(Issue.STATUS_OPEN));
345
346     // resolved
347     issues.add(new DefaultIssue().setRuleKey(ruleB1.ruleKey()).setResolution(Issue.RESOLUTION_FIXED).setStatus(Issue.STATUS_RESOLVED));
348     return issues;
349   }
350
351   List<Issue> createIssuesForNewMetrics() {
352     List<Issue> issues = newArrayList();
353     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()).setCreationDate(rightNow).setStatus(Issue.STATUS_OPEN));
354     issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()).setCreationDate(tenDaysAgo).setStatus(Issue.STATUS_OPEN));
355     issues.add(new DefaultIssue().setRuleKey(ruleA2.ruleKey()).setSeverity(RulePriority.MAJOR.name()).setCreationDate(fiveDaysAgo).setStatus(Issue.STATUS_REOPENED));
356     issues.add(new DefaultIssue().setRuleKey(ruleA2.ruleKey()).setSeverity(RulePriority.MAJOR.name()).setCreationDate(tenDaysAgo).setStatus(Issue.STATUS_REOPENED));
357     issues.add(new DefaultIssue().setRuleKey(ruleB1.ruleKey()).setSeverity(RulePriority.MINOR.name()).setCreationDate(fiveDaysAgo).setStatus(Issue.STATUS_OPEN));
358     issues.add(new DefaultIssue().setRuleKey(ruleB1.ruleKey()).setSeverity(RulePriority.MINOR.name()).setCreationDate(tenDaysAgo).setStatus(Issue.STATUS_OPEN));
359     return issues;
360   }
361
362   class IsVariationRuleMeasure extends ArgumentMatcher<Measure> {
363     Metric metric = null;
364     Rule rule = null;
365     Double var1 = null;
366     Double var2 = null;
367
368     public IsVariationRuleMeasure(Metric metric, Rule rule, Double var1, Double var2) {
369       this.metric = metric;
370       this.rule = rule;
371       this.var1 = var1;
372       this.var2 = var2;
373     }
374
375     public boolean matches(Object o) {
376       if (!(o instanceof RuleMeasure)) {
377         return false;
378       }
379       RuleMeasure m = (RuleMeasure) o;
380       return ObjectUtils.equals(metric, m.getMetric()) &&
381         ObjectUtils.equals(rule, m.getRule()) &&
382         ObjectUtils.equals(var1, m.getVariation1()) &&
383         ObjectUtils.equals(var2, m.getVariation2());
384     }
385   }
386
387   class IsVariationMeasure extends ArgumentMatcher<Measure> {
388     Metric metric = null;
389     Double var1 = null;
390     Double var2 = null;
391
392     public IsVariationMeasure(Metric metric, Double var1, Double var2) {
393       this.metric = metric;
394       this.var1 = var1;
395       this.var2 = var2;
396     }
397
398     public boolean matches(Object o) {
399       if (!(o instanceof Measure)) {
400         return false;
401       }
402       Measure m = (Measure) o;
403       return ObjectUtils.equals(metric, m.getMetric()) &&
404         ObjectUtils.equals(var1, m.getVariation1()) &&
405         ObjectUtils.equals(var2, m.getVariation2()) &&
406         !(m instanceof RuleMeasure);
407     }
408   }
409
410   class IsMetricMeasure extends ArgumentMatcher<Measure> {
411     Metric metric = null;
412
413     public IsMetricMeasure(Metric metric) {
414       this.metric = metric;
415     }
416
417     public boolean matches(Object o) {
418       if (!(o instanceof Measure)) {
419         return false;
420       }
421       Measure m = (Measure) o;
422       return ObjectUtils.equals(metric, m.getMetric());
423     }
424   }
425 }