]> source.dussan.org Git - sonarqube.git/blob
7880c222538d6a5f926d549b959cb8e8a981605f
[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.technicaldebt;
22
23 import org.apache.commons.lang.ObjectUtils;
24 import org.junit.Before;
25 import org.junit.Test;
26 import org.junit.runner.RunWith;
27 import org.mockito.ArgumentMatcher;
28 import org.mockito.Mock;
29 import org.mockito.runners.MockitoJUnitRunner;
30 import org.sonar.api.batch.DecoratorContext;
31 import org.sonar.api.component.ResourcePerspectives;
32 import org.sonar.api.issue.Issuable;
33 import org.sonar.api.issue.Issue;
34 import org.sonar.api.issue.internal.DefaultIssue;
35 import org.sonar.api.issue.internal.FieldDiffs;
36 import org.sonar.api.issue.internal.WorkDayDuration;
37 import org.sonar.api.measures.CoreMetrics;
38 import org.sonar.api.measures.Measure;
39 import org.sonar.api.measures.Metric;
40 import org.sonar.api.resources.Resource;
41 import org.sonar.api.test.IsMeasure;
42 import org.sonar.batch.components.Period;
43 import org.sonar.batch.components.TimeMachineConfiguration;
44 import org.sonar.core.technicaldebt.TechnicalDebtConverter;
45
46 import java.util.Date;
47
48 import static com.google.common.collect.Lists.newArrayList;
49 import static org.fest.assertions.Assertions.assertThat;
50 import static org.mockito.Matchers.argThat;
51 import static org.mockito.Mockito.*;
52
53 @RunWith(MockitoJUnitRunner.class)
54 public class NewTechnicalDebtDecoratorTest {
55
56   NewTechnicalDebtDecorator decorator;
57
58   @Mock
59   TimeMachineConfiguration timeMachineConfiguration;
60
61   @Mock
62   Resource resource;
63
64   @Mock
65   Issuable issuable;
66
67   @Mock
68   DecoratorContext context;
69
70   @Mock
71   TechnicalDebtConverter technicalDebtConverter;
72
73   Date rightNow;
74   Date elevenDaysAgo;
75   Date tenDaysAgo;
76   Date nineDaysAgo;
77   Date fiveDaysAgo;
78   Date fourDaysAgo;
79
80   WorkDayDuration oneDaysDebt = WorkDayDuration.of(0, 0, 1);
81   WorkDayDuration twoDaysDebt = WorkDayDuration.of(0, 0, 2);
82   WorkDayDuration fiveDaysDebt = WorkDayDuration.of(0, 0, 5);
83
84   @Before
85   public void setup() {
86     when(technicalDebtConverter.toDays(oneDaysDebt)).thenReturn(1d);
87     when(technicalDebtConverter.toDays(twoDaysDebt)).thenReturn(2d);
88     when(technicalDebtConverter.toDays(fiveDaysDebt)).thenReturn(5d);
89
90     ResourcePerspectives perspectives = mock(ResourcePerspectives.class);
91     when(perspectives.as(Issuable.class, resource)).thenReturn(issuable);
92
93     rightNow = new Date();
94     elevenDaysAgo = org.apache.commons.lang.time.DateUtils.addDays(rightNow, -11);
95     tenDaysAgo = org.apache.commons.lang.time.DateUtils.addDays(rightNow, -10);
96     nineDaysAgo = org.apache.commons.lang.time.DateUtils.addDays(rightNow, -9);
97     fiveDaysAgo = org.apache.commons.lang.time.DateUtils.addDays(rightNow, -5);
98     fourDaysAgo = org.apache.commons.lang.time.DateUtils.addDays(rightNow, -4);
99
100     when(timeMachineConfiguration.periods()).thenReturn(newArrayList(new Period(1, fiveDaysAgo, fiveDaysAgo), new Period(2, tenDaysAgo, tenDaysAgo)));
101
102     decorator = new NewTechnicalDebtDecorator(perspectives, timeMachineConfiguration, technicalDebtConverter);
103   }
104
105   @Test
106   public void generates_metrics() throws Exception {
107     assertThat(decorator.generatesMetrics()).hasSize(1);
108   }
109
110   @Test
111   public void execute_on_project() throws Exception {
112     assertThat(decorator.shouldExecuteOnProject(null)).isTrue();
113   }
114
115   @Test
116   public void save_on_one_issue_with_one_new_changelog() {
117     Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setTechnicalDebt(twoDaysDebt).setChanges(
118       newArrayList(
119         // changelog created at is null because it has just been created on the current analysis
120         new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysDebt), fromWorkDayDuration(twoDaysDebt)).setCreationDate(null)
121       )
122     );
123     when(issuable.issues()).thenReturn(newArrayList(issue));
124
125     decorator.decorate(resource, context);
126
127     // remember : period1 is 5daysAgo, period2 is 10daysAgo
128     verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 1.0, 1.0)));
129   }
130
131   @Test
132   public void save_on_one_issue_with_changelog() {
133     Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setTechnicalDebt(fiveDaysDebt).setChanges(
134       newArrayList(
135         new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(twoDaysDebt), fromWorkDayDuration(fiveDaysDebt)).setCreationDate(null),
136         new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysDebt), fromWorkDayDuration(twoDaysDebt)).setCreationDate(fourDaysAgo)
137       )
138     );
139     when(issuable.issues()).thenReturn(newArrayList(issue));
140
141     decorator.decorate(resource, context);
142
143     // remember : period1 is 5daysAgo, period2 is 10daysAgo
144     verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 4.0, 4.0)));
145   }
146
147   @Test
148   public void save_on_one_issue_with_changelog_only_in_the_past() {
149     Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setTechnicalDebt(oneDaysDebt).setChanges(
150       newArrayList(
151         // Change before all periods
152         new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysDebt)).setCreationDate(elevenDaysAgo)
153       )
154     );
155     when(issuable.issues()).thenReturn(newArrayList(issue));
156
157     decorator.decorate(resource, context);
158
159     // remember : period1 is 5daysAgo, period2 is 10daysAgo
160     verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0, 0.0)));
161   }
162
163   @Test
164   public void save_on_one_issue_with_changelog_having_null_value() {
165     Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setTechnicalDebt(fiveDaysDebt).setChanges(
166       newArrayList(
167         new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(fiveDaysDebt)).setCreationDate(null),
168         new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysDebt), null).setCreationDate(fourDaysAgo),
169         new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysDebt)).setCreationDate(nineDaysAgo)
170       )
171     );
172     when(issuable.issues()).thenReturn(newArrayList(issue));
173
174     decorator.decorate(resource, context);
175
176     // remember : period1 is 5daysAgo, period2 is 10daysAgo
177     verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 4.0, 5.0)));
178   }
179
180   @Test
181   public void save_on_one_issue_with_changelog_and_periods_have_no_dates() {
182     when(timeMachineConfiguration.periods()).thenReturn(newArrayList(new Period(1, null, null), new Period(2, null, null)));
183
184     Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setTechnicalDebt(fiveDaysDebt).setChanges(
185       newArrayList(
186         new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(fiveDaysDebt)).setCreationDate(null),
187         new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysDebt), null).setCreationDate(fourDaysAgo),
188         new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysDebt)).setCreationDate(nineDaysAgo)
189       )
190     );
191     when(issuable.issues()).thenReturn(newArrayList(issue));
192
193     decorator.decorate(resource, context);
194
195     // remember : period1 is 5daysAgo, period2 is 10daysAgo
196     verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 5.0, 5.0)));
197   }
198
199   @Test
200   public void save_on_one_issue_with_changelog_having_not_only_technical_debt_changes() {
201     Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setTechnicalDebt(fiveDaysDebt).setChanges(
202       newArrayList(
203         new FieldDiffs()
204           .setDiff("actionPlan", "1.0", "1.1").setCreationDate(fourDaysAgo)
205           .setDiff("technicalDebt", fromWorkDayDuration(oneDaysDebt), fromWorkDayDuration(twoDaysDebt)).setCreationDate(fourDaysAgo)
206       )
207     );
208     when(issuable.issues()).thenReturn(newArrayList(issue));
209
210     decorator.decorate(resource, context);
211
212     // remember : period1 is 5daysAgo, period2 is 10daysAgo
213     verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 4.0, 4.0)));
214   }
215
216   @Test
217   public void save_on_issues_with_changelog() {
218     Issue issue1 = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setTechnicalDebt(fiveDaysDebt).setChanges(
219       newArrayList(
220         new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(twoDaysDebt), fromWorkDayDuration(fiveDaysDebt)).setCreationDate(rightNow),
221         new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysDebt), fromWorkDayDuration(twoDaysDebt)).setCreationDate(fourDaysAgo),
222         new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysDebt)).setCreationDate(nineDaysAgo)
223       )
224     );
225     Issue issue2 = new DefaultIssue().setKey("B").setCreationDate(tenDaysAgo).setTechnicalDebt(twoDaysDebt).setChanges(
226       newArrayList(
227         new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysDebt), fromWorkDayDuration(twoDaysDebt)).setCreationDate(rightNow),
228         new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysDebt)).setCreationDate(nineDaysAgo)
229       )
230     );
231     when(issuable.issues()).thenReturn(newArrayList(issue1, issue2));
232
233     decorator.decorate(resource, context);
234
235     // remember : period1 is 5daysAgo, period2 is 10daysAgo
236     verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 5.0, 7.0)));
237   }
238
239   @Test
240   public void save_on_one_issue_without_changelog() {
241     when(issuable.issues()).thenReturn(newArrayList(
242       (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setTechnicalDebt(fiveDaysDebt))
243     );
244
245     decorator.decorate(resource, context);
246
247     // remember : period1 is 5daysAgo, period2 is 10daysAgo
248     verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0, 5.0)));
249   }
250
251   @Test
252   public void save_on_one_issue_without_technical_debt_and_without_changelog() {
253     when(issuable.issues()).thenReturn(newArrayList(
254       (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setTechnicalDebt(null))
255     );
256
257     decorator.decorate(resource, context);
258
259     // remember : period1 is 5daysAgo, period2 is 10daysAgo
260     verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0, 0.0)));
261   }
262
263   @Test
264   public void save_on_one_issue_without_changelog_and_periods_have_no_dates() {
265     when(timeMachineConfiguration.periods()).thenReturn(newArrayList(new Period(1, null, null), new Period(2, null, null)));
266
267     when(issuable.issues()).thenReturn(newArrayList(
268       (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setTechnicalDebt(fiveDaysDebt))
269     );
270
271     decorator.decorate(resource, context);
272
273     // remember : period1 is null, period2 is null
274     verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 5.0, 5.0)));
275   }
276
277   @Test
278   public void save_on_issues_without_changelog() {
279     when(issuable.issues()).thenReturn(newArrayList(
280       (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setTechnicalDebt(fiveDaysDebt),
281       new DefaultIssue().setKey("B").setCreationDate(fiveDaysAgo).setTechnicalDebt(twoDaysDebt)
282     ));
283
284     decorator.decorate(resource, context);
285
286     // remember : period1 is 5daysAgo, period2 is 10daysAgo
287     verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0, 7.0)));
288   }
289
290   @Test
291   public void save_on_issues_with_changelog_and_issues_without_changelog() {
292     // issue1 and issue2 have changelog
293     Issue issue1 = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setTechnicalDebt(fiveDaysDebt).setChanges(
294       newArrayList(
295         new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(twoDaysDebt), fromWorkDayDuration(fiveDaysDebt)).setCreationDate(rightNow),
296         new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysDebt), fromWorkDayDuration(twoDaysDebt)).setCreationDate(fourDaysAgo),
297         new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysDebt)).setCreationDate(nineDaysAgo)
298       )
299     );
300     Issue issue2 = new DefaultIssue().setKey("B").setCreationDate(tenDaysAgo).setTechnicalDebt(twoDaysDebt).setChanges(
301       newArrayList(
302         new FieldDiffs().setDiff("technicalDebt", fromWorkDayDuration(oneDaysDebt), fromWorkDayDuration(twoDaysDebt)).setCreationDate(rightNow),
303         new FieldDiffs().setDiff("technicalDebt", null, fromWorkDayDuration(oneDaysDebt)).setCreationDate(nineDaysAgo)
304       )
305     );
306
307     // issue3 and issue4 have no changelog
308     Issue issue3 = new DefaultIssue().setKey("C").setCreationDate(nineDaysAgo).setTechnicalDebt(fiveDaysDebt);
309     Issue issue4 = new DefaultIssue().setKey("D").setCreationDate(fiveDaysAgo).setTechnicalDebt(twoDaysDebt);
310     when(issuable.issues()).thenReturn(newArrayList(issue1, issue2, issue3, issue4));
311
312     decorator.decorate(resource, context);
313
314     // remember : period1 is 5daysAgo, period2 is 10daysAgo
315     verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 5.0, 14.0)));
316   }
317
318   @Test
319   public void not_save_if_measure_already_computed() {
320     when(context.getMeasure(CoreMetrics.NEW_TECHNICAL_DEBT)).thenReturn(new Measure());
321     when(issuable.issues()).thenReturn(newArrayList(
322       (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setTechnicalDebt(fiveDaysDebt),
323       new DefaultIssue().setKey("B").setCreationDate(fiveDaysAgo).setTechnicalDebt(twoDaysDebt)
324     ));
325
326     decorator.decorate(resource, context);
327
328     verify(context, never()).saveMeasure(argThat(new IsMeasure(CoreMetrics.NEW_TECHNICAL_DEBT)));
329   }
330
331   private Long fromWorkDayDuration(WorkDayDuration workDayDuration){
332     return workDayDuration.toLong();
333   }
334
335
336   class IsVariationMeasure extends ArgumentMatcher<Measure> {
337     Metric metric = null;
338     Double var1 = null;
339     Double var2 = null;
340
341     public IsVariationMeasure(Metric metric, Double var1, Double var2) {
342       this.metric = metric;
343       this.var1 = var1;
344       this.var2 = var2;
345     }
346
347     public boolean matches(Object o) {
348       if (!(o instanceof Measure)) {
349         return false;
350       }
351       Measure m = (Measure) o;
352       return ObjectUtils.equals(metric, m.getMetric()) &&
353         ObjectUtils.equals(var1, m.getVariation1()) &&
354         ObjectUtils.equals(var2, m.getVariation2());
355     }
356   }
357
358 }