]> source.dussan.org Git - sonarqube.git/blob
6ea2df98b522c08240dde67baedc68588ae4de9b
[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.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;
46
47 import java.util.Arrays;
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.Mockito.*;
55
56 public class CountUnresolvedIssuesDecoratorTest {
57
58   CountUnresolvedIssuesDecorator decorator;
59   TimeMachineConfiguration timeMachineConfiguration;
60   RuleFinder ruleFinder;
61   Issuable issuable;
62   DecoratorContext context;
63   Resource resource;
64   Project project;
65   Rule ruleA1;
66   Rule ruleA2;
67   Rule ruleB1;
68   Date rightNow;
69   Date tenDaysAgo;
70   Date fiveDaysAgo;
71
72   @Before
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");
77
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);
82
83     rightNow = new Date();
84     tenDaysAgo = DateUtils.addDays(rightNow, -10);
85     fiveDaysAgo = DateUtils.addDays(rightNow, -5);
86
87     PastSnapshot pastSnapshot = mock(PastSnapshot.class);
88     when(pastSnapshot.getIndex()).thenReturn(1);
89     when(pastSnapshot.getTargetDate()).thenReturn(fiveDaysAgo);
90
91     PastSnapshot pastSnapshot2 = mock(PastSnapshot.class);
92     when(pastSnapshot2.getIndex()).thenReturn(2);
93     when(pastSnapshot2.getTargetDate()).thenReturn(tenDaysAgo);
94
95     timeMachineConfiguration = mock(TimeMachineConfiguration.class);
96     when(timeMachineConfiguration.getProjectPastSnapshots()).thenReturn(Arrays.asList(pastSnapshot, pastSnapshot2));
97
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);
104
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);
109   }
110
111   @Test
112   public void should_be_depended_upon_metric() {
113     assertThat(decorator.generatesIssuesMetrics()).hasSize(15);
114   }
115
116   @Test
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());
121
122     decorator.decorate(resource, context);
123
124     verify(context).saveMeasure(CoreMetrics.VIOLATIONS, 4.0);
125   }
126
127   @Test
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);
132
133     decorator.decorate(resource, context);
134
135     verifyZeroInteractions(context);
136   }
137
138   /**
139    * See http://jira.codehaus.org/browse/SONAR-1729
140    */
141   @Test
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));
148
149     decorator.decorate(resource, context);
150
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
154   }
155
156   @Test
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());
161
162     decorator.decorate(resource, context);
163
164     verify(context).saveMeasure(CoreMetrics.VIOLATIONS, 0.0);
165   }
166
167   @Test
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());
172
173     decorator.decorate(resource, context);
174
175     verify(context).saveMeasure(CoreMetrics.VIOLATIONS, 0.0);
176   }
177
178   @Test
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());
183
184     decorator.decorate(resource, context);
185
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);
191   }
192
193   @Test
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);
200
201     decorator.decorate(resource, context);
202
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)));
206   }
207
208   @Test
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);
215
216     decorator.decorate(resource, context);
217
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)));
220   }
221
222   @Test
223   public void should_count_issues_after_date() {
224     List<Issue> issues = createIssuesForNewMetrics();
225
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
229   }
230
231   @Test
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));
236
237     decorator.decorate(resource, context);
238     decorator.decorate(resource, context);
239
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)));
242   }
243
244   @Test
245   public void should_save_severity_new_issues() {
246     when(issuable.unresolvedIssues()).thenReturn(createIssuesForNewMetrics());
247
248     decorator.decorate(resource, context);
249
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)));
256   }
257
258   @Test
259   public void should_save_rule_new_issues() {
260     when(issuable.unresolvedIssues()).thenReturn(createIssuesForNewMetrics());
261
262     decorator.decorate(resource, context);
263
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)));
268   }
269
270   @Test
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());
274
275     decorator.decorate(resource, context);
276
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)));
283   }
284
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));
291     return issues;
292   }
293
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));
302     return issues;
303   }
304
305   class IsVariationRuleMeasure extends ArgumentMatcher<Measure> {
306     Metric metric = null;
307     Rule rule = null;
308     Double var1 = null;
309     Double var2 = null;
310
311     public IsVariationRuleMeasure(Metric metric, Rule rule, Double var1, Double var2) {
312       this.metric = metric;
313       this.rule = rule;
314       this.var1 = var1;
315       this.var2 = var2;
316     }
317
318     public boolean matches(Object o) {
319       if (!(o instanceof RuleMeasure)) {
320         return false;
321       }
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());
327     }
328   }
329
330   class IsVariationMeasure extends ArgumentMatcher<Measure> {
331     Metric metric = null;
332     Double var1 = null;
333     Double var2 = null;
334
335     public IsVariationMeasure(Metric metric, Double var1, Double var2) {
336       this.metric = metric;
337       this.var1 = var1;
338       this.var2 = var2;
339     }
340
341     public boolean matches(Object o) {
342       if (!(o instanceof Measure)) {
343         return false;
344       }
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);
350     }
351   }
352
353   class IsMetricMeasure extends ArgumentMatcher<Measure> {
354     Metric metric = null;
355
356     public IsMetricMeasure(Metric metric) {
357       this.metric = metric;
358     }
359
360     public boolean matches(Object o) {
361       if (!(o instanceof Measure)) {
362         return false;
363       }
364       Measure m = (Measure) o;
365       return ObjectUtils.equals(metric, m.getMetric());
366     }
367   }
368 }