]> source.dussan.org Git - sonarqube.git/blob
5e82b02daac1c530d7d6b74a10db41978f086411
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2017 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
6  * This program 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  * This program 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 package org.sonar.server.computation.task.projectanalysis.issue;
21
22 import org.junit.Test;
23 import org.mockito.Mockito;
24 import org.sonar.api.rules.RuleType;
25 import org.sonar.api.utils.Duration;
26 import org.sonar.core.issue.DefaultIssue;
27 import org.sonar.db.DbClient;
28 import org.sonar.server.computation.task.projectanalysis.component.Component;
29 import org.sonar.server.computation.task.projectanalysis.component.ReportComponent;
30 import org.sonar.server.computation.task.projectanalysis.measure.Measure;
31 import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepositoryRule;
32 import org.sonar.server.computation.task.projectanalysis.metric.MetricRepositoryRule;
33 import org.sonar.server.computation.task.projectanalysis.period.Period;
34 import org.sonar.server.computation.task.projectanalysis.period.PeriodHolderRule;
35
36 import static org.assertj.core.api.Assertions.assertThat;
37 import static org.assertj.guava.api.Assertions.assertThat;
38 import static org.mockito.Matchers.anyList;
39 import static org.mockito.Matchers.same;
40 import static org.mockito.Mockito.mock;
41 import static org.mockito.Mockito.verifyNoMoreInteractions;
42 import static org.mockito.Mockito.verifyZeroInteractions;
43 import static org.mockito.Mockito.when;
44 import static org.sonar.api.issue.Issue.RESOLUTION_FIXED;
45 import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT;
46 import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT_KEY;
47 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT;
48 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT_KEY;
49 import static org.sonar.api.measures.CoreMetrics.NEW_TECHNICAL_DEBT;
50 import static org.sonar.api.measures.CoreMetrics.NEW_TECHNICAL_DEBT_KEY;
51 import static org.sonar.api.rules.RuleType.BUG;
52 import static org.sonar.api.rules.RuleType.CODE_SMELL;
53 import static org.sonar.api.rules.RuleType.VULNERABILITY;
54 import static org.sonar.core.config.CorePropertyDefinitions.LEAK_PERIOD_MODE_PREVIOUS_ANALYSIS;
55
56 public class NewEffortAggregatorTest {
57
58   private static final Period PERIOD = new Period(LEAK_PERIOD_MODE_PREVIOUS_ANALYSIS, null, 1_500_000_000L, "U1");
59
60   private static final Component FILE = ReportComponent.builder(Component.Type.FILE, 1).setUuid("FILE").build();
61   private static final Component PROJECT = ReportComponent.builder(Component.Type.PROJECT, 2).addChildren(FILE).build();
62
63   private NewEffortCalculator calculator = mock(NewEffortCalculator.class);
64
65   @org.junit.Rule
66   public PeriodHolderRule periodsHolder = new PeriodHolderRule();
67
68   @org.junit.Rule
69   public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
70     .add(NEW_TECHNICAL_DEBT)
71     .add(NEW_RELIABILITY_REMEDIATION_EFFORT)
72     .add(NEW_SECURITY_REMEDIATION_EFFORT);
73
74   @org.junit.Rule
75   public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create();
76
77   private DbClient dbClient = mock(DbClient.class, Mockito.RETURNS_DEEP_STUBS);
78
79   private NewEffortAggregator underTest = new NewEffortAggregator(calculator, periodsHolder, dbClient, metricRepository, measureRepository);
80
81   @Test
82   public void sum_new_maintainability_effort_of_issues() {
83     periodsHolder.setPeriod(PERIOD);
84     DefaultIssue unresolved1 = newCodeSmellIssue(10L);
85     DefaultIssue unresolved2 = newCodeSmellIssue(30L);
86     DefaultIssue unresolvedWithoutDebt = newCodeSmellIssueWithoutEffort();
87     DefaultIssue resolved = newCodeSmellIssue(50L).setResolution(RESOLUTION_FIXED);
88
89     when(calculator.calculate(same(unresolved1), anyList(), same(PERIOD))).thenReturn(4L);
90     when(calculator.calculate(same(unresolved2), anyList(), same(PERIOD))).thenReturn(3L);
91     verifyNoMoreInteractions(calculator);
92
93     underTest.beforeComponent(FILE);
94     underTest.onIssue(FILE, unresolved1);
95     underTest.onIssue(FILE, unresolved2);
96     underTest.onIssue(FILE, unresolvedWithoutDebt);
97     underTest.onIssue(FILE, resolved);
98     underTest.afterComponent(FILE);
99
100     assertVariation(FILE, NEW_TECHNICAL_DEBT_KEY, 3 + 4);
101   }
102
103   @Test
104   public void new_maintainability_effort_is_only_computed_using_code_smell_issues() {
105     periodsHolder.setPeriod(PERIOD);
106     DefaultIssue codeSmellIssue = newCodeSmellIssue(10);
107     // Issues of type BUG and VULNERABILITY should be ignored
108     DefaultIssue bugIssue = newBugIssue(15);
109     DefaultIssue vulnerabilityIssue = newVulnerabilityIssue(12);
110
111     when(calculator.calculate(same(codeSmellIssue), anyList(), same(PERIOD))).thenReturn(4L);
112     when(calculator.calculate(same(bugIssue), anyList(), same(PERIOD))).thenReturn(3L);
113     when(calculator.calculate(same(vulnerabilityIssue), anyList(), same(PERIOD))).thenReturn(5L);
114
115     underTest.beforeComponent(FILE);
116     underTest.onIssue(FILE, codeSmellIssue);
117     underTest.onIssue(FILE, bugIssue);
118     underTest.onIssue(FILE, vulnerabilityIssue);
119     underTest.afterComponent(FILE);
120
121     // Only effort of CODE SMELL issue is used
122     assertVariation(FILE, NEW_TECHNICAL_DEBT_KEY, 4);
123   }
124
125   @Test
126   public void sum_new_reliability_effort_of_issues() {
127     periodsHolder.setPeriod(PERIOD);
128     DefaultIssue unresolved1 = newBugIssue(10L);
129     DefaultIssue unresolved2 = newBugIssue(30L);
130     DefaultIssue unresolvedWithoutDebt = newBugIssueWithoutEffort();
131     DefaultIssue resolved = newBugIssue(50L).setResolution(RESOLUTION_FIXED);
132
133     when(calculator.calculate(same(unresolved1), anyList(), same(PERIOD))).thenReturn(4L);
134     when(calculator.calculate(same(unresolved2), anyList(), same(PERIOD))).thenReturn(3L);
135     verifyNoMoreInteractions(calculator);
136
137     underTest.beforeComponent(FILE);
138     underTest.onIssue(FILE, unresolved1);
139     underTest.onIssue(FILE, unresolved2);
140     underTest.onIssue(FILE, unresolvedWithoutDebt);
141     underTest.onIssue(FILE, resolved);
142     underTest.afterComponent(FILE);
143
144     assertVariation(FILE, NEW_RELIABILITY_REMEDIATION_EFFORT_KEY, 3 + 4);
145   }
146
147   @Test
148   public void new_reliability_effort_is_only_computed_using_bug_issues() {
149     periodsHolder.setPeriod(PERIOD);
150     DefaultIssue bugIssue = newBugIssue(15);
151     // Issues of type CODE SMELL and VULNERABILITY should be ignored
152     DefaultIssue codeSmellIssue = newCodeSmellIssue(10);
153     DefaultIssue vulnerabilityIssue = newVulnerabilityIssue(12);
154
155     when(calculator.calculate(same(bugIssue), anyList(), same(PERIOD))).thenReturn(3L);
156     when(calculator.calculate(same(codeSmellIssue), anyList(), same(PERIOD))).thenReturn(4L);
157     when(calculator.calculate(same(vulnerabilityIssue), anyList(), same(PERIOD))).thenReturn(5L);
158
159     underTest.beforeComponent(FILE);
160     underTest.onIssue(FILE, bugIssue);
161     underTest.onIssue(FILE, codeSmellIssue);
162     underTest.onIssue(FILE, vulnerabilityIssue);
163     underTest.afterComponent(FILE);
164
165     // Only effort of BUG issue is used
166     assertVariation(FILE, NEW_RELIABILITY_REMEDIATION_EFFORT_KEY, 3);
167   }
168
169   @Test
170   public void sum_new_securtiy_effort_of_issues() {
171     periodsHolder.setPeriod(PERIOD);
172     DefaultIssue unresolved1 = newVulnerabilityIssue(10L);
173     DefaultIssue unresolved2 = newVulnerabilityIssue(30L);
174     DefaultIssue unresolvedWithoutDebt = newVulnerabilityIssueWithoutEffort();
175     DefaultIssue resolved = newVulnerabilityIssue(50L).setResolution(RESOLUTION_FIXED);
176
177     when(calculator.calculate(same(unresolved1), anyList(), same(PERIOD))).thenReturn(4L);
178     when(calculator.calculate(same(unresolved2), anyList(), same(PERIOD))).thenReturn(3L);
179     verifyNoMoreInteractions(calculator);
180
181     underTest.beforeComponent(FILE);
182     underTest.onIssue(FILE, unresolved1);
183     underTest.onIssue(FILE, unresolved2);
184     underTest.onIssue(FILE, unresolvedWithoutDebt);
185     underTest.onIssue(FILE, resolved);
186     underTest.afterComponent(FILE);
187
188     assertVariation(FILE, NEW_SECURITY_REMEDIATION_EFFORT_KEY, 3 + 4);
189   }
190
191   @Test
192   public void new_security_effort_is_only_computed_using_vulnerability_issues() {
193     periodsHolder.setPeriod(PERIOD);
194     DefaultIssue vulnerabilityIssue = newVulnerabilityIssue(12);
195     // Issues of type CODE SMELL and BUG should be ignored
196     DefaultIssue codeSmellIssue = newCodeSmellIssue(10);
197     DefaultIssue bugIssue = newBugIssue(15);
198
199     when(calculator.calculate(same(vulnerabilityIssue), anyList(), same(PERIOD))).thenReturn(5L);
200     when(calculator.calculate(same(codeSmellIssue), anyList(), same(PERIOD))).thenReturn(4L);
201     when(calculator.calculate(same(bugIssue), anyList(), same(PERIOD))).thenReturn(3L);
202
203     underTest.beforeComponent(FILE);
204     underTest.onIssue(FILE, codeSmellIssue);
205     underTest.onIssue(FILE, bugIssue);
206     underTest.onIssue(FILE, vulnerabilityIssue);
207     underTest.afterComponent(FILE);
208
209     // Only effort of VULNERABILITY issue is used
210     assertVariation(FILE, NEW_SECURITY_REMEDIATION_EFFORT_KEY, 5);
211   }
212
213   @Test
214   public void aggregate_new_characteristic_measures_of_children() {
215     periodsHolder.setPeriod(PERIOD);
216
217     DefaultIssue codeSmellIssue = newCodeSmellIssue(10);
218     when(calculator.calculate(same(codeSmellIssue), anyList(), same(PERIOD))).thenReturn(4L);
219     DefaultIssue bugIssue = newBugIssue(8);
220     when(calculator.calculate(same(bugIssue), anyList(), same(PERIOD))).thenReturn(3L);
221     DefaultIssue vulnerabilityIssue = newVulnerabilityIssue(12);
222     when(calculator.calculate(same(vulnerabilityIssue), anyList(), same(PERIOD))).thenReturn(6L);
223
224     DefaultIssue codeSmellProjectIssue = newCodeSmellIssue(30);
225     when(calculator.calculate(same(codeSmellProjectIssue), anyList(), same(PERIOD))).thenReturn(1L);
226     DefaultIssue bugProjectIssue = newBugIssue(28);
227     when(calculator.calculate(same(bugProjectIssue), anyList(), same(PERIOD))).thenReturn(2L);
228     DefaultIssue vulnerabilityProjectIssue = newVulnerabilityIssue(32);
229     when(calculator.calculate(same(vulnerabilityProjectIssue), anyList(), same(PERIOD))).thenReturn(4L);
230
231     underTest.beforeComponent(FILE);
232     underTest.onIssue(FILE, codeSmellIssue);
233     underTest.onIssue(FILE, bugIssue);
234     underTest.onIssue(FILE, vulnerabilityIssue);
235     underTest.afterComponent(FILE);
236     underTest.beforeComponent(PROJECT);
237     underTest.onIssue(PROJECT, codeSmellProjectIssue);
238     underTest.onIssue(PROJECT, bugProjectIssue);
239     underTest.onIssue(PROJECT, vulnerabilityProjectIssue);
240     underTest.afterComponent(PROJECT);
241
242     assertVariation(PROJECT, NEW_TECHNICAL_DEBT_KEY, 4 + 1);
243     assertVariation(PROJECT, NEW_RELIABILITY_REMEDIATION_EFFORT_KEY, 3 + 2);
244     assertVariation(PROJECT, NEW_SECURITY_REMEDIATION_EFFORT_KEY, 6 + 4);
245   }
246
247   @Test
248   public void no_measures_if_no_periods() {
249     periodsHolder.setPeriod(null);
250     DefaultIssue unresolved = new DefaultIssue().setEffort(Duration.create(10));
251     verifyZeroInteractions(calculator);
252
253     underTest.beforeComponent(FILE);
254     underTest.onIssue(FILE, unresolved);
255     underTest.afterComponent(FILE);
256
257     assertThat(measureRepository.getRawMeasures(FILE)).isEmpty();
258   }
259
260   private void assertVariation(Component component, String metricKey, int variation) {
261     Measure newMeasure = measureRepository.getRawMeasure(component, metricRepository.getByKey(metricKey)).get();
262     assertThat(newMeasure.getVariation()).isEqualTo(variation);
263   }
264
265   private static DefaultIssue newCodeSmellIssue(long effort) {
266     return newCodeSmellIssueWithoutEffort().setEffort(Duration.create(effort)).setType(RuleType.CODE_SMELL);
267   }
268
269   private static DefaultIssue newBugIssue(long effort) {
270     return newCodeSmellIssueWithoutEffort().setEffort(Duration.create(effort)).setType(RuleType.BUG);
271   }
272
273   private static DefaultIssue newVulnerabilityIssue(long effort) {
274     return newCodeSmellIssueWithoutEffort().setEffort(Duration.create(effort)).setType(RuleType.VULNERABILITY);
275   }
276
277   private static DefaultIssue newCodeSmellIssueWithoutEffort() {
278     return new DefaultIssue().setType(CODE_SMELL);
279   }
280
281   private static DefaultIssue newBugIssueWithoutEffort() {
282     return new DefaultIssue().setType(BUG);
283   }
284
285   private static DefaultIssue newVulnerabilityIssueWithoutEffort() {
286     return new DefaultIssue().setType(VULNERABILITY);
287   }
288 }