3 * Copyright (C) 2009-2019 SonarSource SA
4 * mailto:info AT sonarsource DOT com
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.
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.
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.
20 package org.sonar.ce.task.projectanalysis.issue;
22 import java.util.Date;
23 import java.util.Random;
24 import org.junit.Test;
25 import org.sonar.api.rules.RuleType;
26 import org.sonar.api.utils.Duration;
27 import org.sonar.ce.task.projectanalysis.component.Component;
28 import org.sonar.ce.task.projectanalysis.component.ReportComponent;
29 import org.sonar.ce.task.projectanalysis.measure.Measure;
30 import org.sonar.ce.task.projectanalysis.measure.MeasureRepositoryRule;
31 import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule;
32 import org.sonar.ce.task.projectanalysis.period.Period;
33 import org.sonar.ce.task.projectanalysis.period.PeriodHolderRule;
34 import org.sonar.core.issue.DefaultIssue;
36 import static org.assertj.core.api.Assertions.assertThat;
37 import static org.assertj.guava.api.Assertions.assertThat;
38 import static org.sonar.api.issue.Issue.RESOLUTION_FIXED;
39 import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT;
40 import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT_KEY;
41 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT;
42 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT_KEY;
43 import static org.sonar.api.measures.CoreMetrics.NEW_TECHNICAL_DEBT;
44 import static org.sonar.api.measures.CoreMetrics.NEW_TECHNICAL_DEBT_KEY;
45 import static org.sonar.api.rules.RuleType.BUG;
46 import static org.sonar.api.rules.RuleType.CODE_SMELL;
47 import static org.sonar.api.rules.RuleType.VULNERABILITY;
48 import static org.sonar.core.config.CorePropertyDefinitions.LEAK_PERIOD_MODE_PREVIOUS_VERSION;
50 public class NewEffortAggregatorTest {
52 private static final Period PERIOD = new Period(LEAK_PERIOD_MODE_PREVIOUS_VERSION, null, 1_500_000_000L, "U1");
53 private static final long[] OLD_ISSUES_DATES = new long[] {
54 PERIOD.getSnapshotDate(),
55 PERIOD.getSnapshotDate() - 1,
56 PERIOD.getSnapshotDate() - 1_200_000L,
59 private static final Component FILE = ReportComponent.builder(Component.Type.FILE, 1).setUuid("FILE").build();
60 private static final Component PROJECT = ReportComponent.builder(Component.Type.PROJECT, 2).addChildren(FILE).build();
63 public PeriodHolderRule periodsHolder = new PeriodHolderRule();
65 public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
66 .add(NEW_TECHNICAL_DEBT)
67 .add(NEW_RELIABILITY_REMEDIATION_EFFORT)
68 .add(NEW_SECURITY_REMEDIATION_EFFORT);
70 public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create();
72 private final Random random = new Random();
73 private NewEffortAggregator underTest = new NewEffortAggregator(periodsHolder, metricRepository, measureRepository);
76 public void sum_new_maintainability_effort_of_issues() {
77 periodsHolder.setPeriod(PERIOD);
78 DefaultIssue unresolved1 = newCodeSmellIssue(10L);
79 DefaultIssue old1 = oldCodeSmellIssue(100L);
80 DefaultIssue unresolved2 = newCodeSmellIssue(30L);
81 DefaultIssue old2 = oldCodeSmellIssue(300L);
82 DefaultIssue unresolvedWithoutDebt = newCodeSmellIssueWithoutEffort();
83 DefaultIssue resolved = newCodeSmellIssue(50L).setResolution(RESOLUTION_FIXED);
85 underTest.beforeComponent(FILE);
86 underTest.onIssue(FILE, unresolved1);
87 underTest.onIssue(FILE, old1);
88 underTest.onIssue(FILE, unresolved2);
89 underTest.onIssue(FILE, old2);
90 underTest.onIssue(FILE, unresolvedWithoutDebt);
91 underTest.onIssue(FILE, resolved);
92 underTest.afterComponent(FILE);
94 assertVariation(FILE, NEW_TECHNICAL_DEBT_KEY, 10 + 30);
98 public void new_maintainability_effort_is_only_computed_using_code_smell_issues() {
99 periodsHolder.setPeriod(PERIOD);
100 DefaultIssue codeSmellIssue = newCodeSmellIssue(10);
101 DefaultIssue oldSmellIssue = oldCodeSmellIssue(100);
102 // Issues of type BUG and VULNERABILITY should be ignored
103 DefaultIssue bugIssue = newBugIssue(15);
104 DefaultIssue oldBugIssue = oldBugIssue(150);
105 DefaultIssue vulnerabilityIssue = newVulnerabilityIssue(12);
106 DefaultIssue oldVulnerabilityIssue = oldVulnerabilityIssue(120);
108 underTest.beforeComponent(FILE);
109 underTest.onIssue(FILE, codeSmellIssue);
110 underTest.onIssue(FILE, oldSmellIssue);
111 underTest.onIssue(FILE, bugIssue);
112 underTest.onIssue(FILE, oldBugIssue);
113 underTest.onIssue(FILE, vulnerabilityIssue);
114 underTest.onIssue(FILE, oldVulnerabilityIssue);
115 underTest.afterComponent(FILE);
117 // Only effort of CODE SMELL issue is used
118 assertVariation(FILE, NEW_TECHNICAL_DEBT_KEY, 10);
122 public void sum_new_reliability_effort_of_issues() {
123 periodsHolder.setPeriod(PERIOD);
124 DefaultIssue unresolved1 = newBugIssue(10L);
125 DefaultIssue old1 = oldBugIssue(100L);
126 DefaultIssue unresolved2 = newBugIssue(30L);
128 DefaultIssue old2 = oldBugIssue(300L);
129 DefaultIssue unresolvedWithoutDebt = newBugIssueWithoutEffort();
130 DefaultIssue resolved = newBugIssue(50L).setResolution(RESOLUTION_FIXED);
132 underTest.beforeComponent(FILE);
133 underTest.onIssue(FILE, unresolved1);
134 underTest.onIssue(FILE, old1);
135 underTest.onIssue(FILE, unresolved2);
136 underTest.onIssue(FILE, old2);
137 underTest.onIssue(FILE, unresolvedWithoutDebt);
138 underTest.onIssue(FILE, resolved);
139 underTest.afterComponent(FILE);
141 assertVariation(FILE, NEW_RELIABILITY_REMEDIATION_EFFORT_KEY, 10 + 30);
145 public void new_reliability_effort_is_only_computed_using_bug_issues() {
146 periodsHolder.setPeriod(PERIOD);
147 DefaultIssue bugIssue = newBugIssue(15);
148 DefaultIssue oldBugIssue = oldBugIssue(150);
149 // Issues of type CODE SMELL and VULNERABILITY should be ignored
150 DefaultIssue codeSmellIssue = newCodeSmellIssue(10);
151 DefaultIssue oldCodeSmellIssue = oldCodeSmellIssue(100);
152 DefaultIssue vulnerabilityIssue = newVulnerabilityIssue(12);
153 DefaultIssue oldVulnerabilityIssue = oldVulnerabilityIssue(120);
155 underTest.beforeComponent(FILE);
156 underTest.onIssue(FILE, bugIssue);
157 underTest.onIssue(FILE, oldBugIssue);
158 underTest.onIssue(FILE, codeSmellIssue);
159 underTest.onIssue(FILE, oldCodeSmellIssue);
160 underTest.onIssue(FILE, vulnerabilityIssue);
161 underTest.onIssue(FILE, oldVulnerabilityIssue);
162 underTest.afterComponent(FILE);
164 // Only effort of BUG issue is used
165 assertVariation(FILE, NEW_RELIABILITY_REMEDIATION_EFFORT_KEY, 15);
169 public void sum_new_vulnerability_effort_of_issues() {
170 periodsHolder.setPeriod(PERIOD);
171 DefaultIssue unresolved1 = newVulnerabilityIssue(10L);
172 DefaultIssue old1 = oldVulnerabilityIssue(100L);
173 DefaultIssue unresolved2 = newVulnerabilityIssue(30L);
174 DefaultIssue old2 = oldVulnerabilityIssue(300L);
175 DefaultIssue unresolvedWithoutDebt = newVulnerabilityIssueWithoutEffort();
176 DefaultIssue resolved = newVulnerabilityIssue(50L).setResolution(RESOLUTION_FIXED);
177 DefaultIssue oldResolved = oldVulnerabilityIssue(500L).setResolution(RESOLUTION_FIXED);
179 underTest.beforeComponent(FILE);
180 underTest.onIssue(FILE, unresolved1);
181 underTest.onIssue(FILE, old1);
182 underTest.onIssue(FILE, unresolved2);
183 underTest.onIssue(FILE, old2);
184 underTest.onIssue(FILE, unresolvedWithoutDebt);
185 underTest.onIssue(FILE, resolved);
186 underTest.onIssue(FILE, oldResolved);
187 underTest.afterComponent(FILE);
189 assertVariation(FILE, NEW_SECURITY_REMEDIATION_EFFORT_KEY, 10 + 30);
193 public void new_security_effort_is_only_computed_using_vulnerability_issues() {
194 periodsHolder.setPeriod(PERIOD);
195 DefaultIssue vulnerabilityIssue = newVulnerabilityIssue(12);
196 DefaultIssue oldVulnerabilityIssue = oldVulnerabilityIssue(120);
197 // Issues of type CODE SMELL and BUG should be ignored
198 DefaultIssue codeSmellIssue = newCodeSmellIssue(10);
199 DefaultIssue oldCodeSmellIssue = oldCodeSmellIssue(100);
200 DefaultIssue bugIssue = newBugIssue(15);
201 DefaultIssue oldBugIssue = oldBugIssue(150);
203 underTest.beforeComponent(FILE);
204 underTest.onIssue(FILE, codeSmellIssue);
205 underTest.onIssue(FILE, oldCodeSmellIssue);
206 underTest.onIssue(FILE, bugIssue);
207 underTest.onIssue(FILE, oldBugIssue);
208 underTest.onIssue(FILE, vulnerabilityIssue);
209 underTest.onIssue(FILE, oldVulnerabilityIssue);
210 underTest.afterComponent(FILE);
212 // Only effort of VULNERABILITY issue is used
213 assertVariation(FILE, NEW_SECURITY_REMEDIATION_EFFORT_KEY, 12);
217 public void aggregate_new_characteristic_measures_of_children() {
218 periodsHolder.setPeriod(PERIOD);
220 DefaultIssue codeSmellIssue = newCodeSmellIssue(10);
221 DefaultIssue oldCodeSmellIssue = oldCodeSmellIssue(100);
222 DefaultIssue bugIssue = newBugIssue(8);
223 DefaultIssue oldBugIssue = oldBugIssue(80);
224 DefaultIssue vulnerabilityIssue = newVulnerabilityIssue(12);
225 DefaultIssue oldVulnerabilityIssue = oldVulnerabilityIssue(120);
227 DefaultIssue codeSmellProjectIssue = newCodeSmellIssue(30);
228 DefaultIssue oldCodeSmellProjectIssue = oldCodeSmellIssue(300);
229 DefaultIssue bugProjectIssue = newBugIssue(28);
230 DefaultIssue oldBugProjectIssue = oldBugIssue(280);
231 DefaultIssue vulnerabilityProjectIssue = newVulnerabilityIssue(32);
232 DefaultIssue oldVulnerabilityProjectIssue = oldVulnerabilityIssue(320);
234 underTest.beforeComponent(FILE);
235 underTest.onIssue(FILE, codeSmellIssue);
236 underTest.onIssue(FILE, oldCodeSmellIssue);
237 underTest.onIssue(FILE, bugIssue);
238 underTest.onIssue(FILE, oldBugIssue);
239 underTest.onIssue(FILE, vulnerabilityIssue);
240 underTest.onIssue(FILE, oldVulnerabilityIssue);
241 underTest.afterComponent(FILE);
242 underTest.beforeComponent(PROJECT);
243 underTest.onIssue(PROJECT, codeSmellProjectIssue);
244 underTest.onIssue(PROJECT, oldCodeSmellProjectIssue);
245 underTest.onIssue(PROJECT, bugProjectIssue);
246 underTest.onIssue(PROJECT, oldBugProjectIssue);
247 underTest.onIssue(PROJECT, vulnerabilityProjectIssue);
248 underTest.onIssue(PROJECT, oldVulnerabilityProjectIssue);
249 underTest.afterComponent(PROJECT);
251 assertVariation(PROJECT, NEW_TECHNICAL_DEBT_KEY, 10 + 30);
252 assertVariation(PROJECT, NEW_RELIABILITY_REMEDIATION_EFFORT_KEY, 8 + 28);
253 assertVariation(PROJECT, NEW_SECURITY_REMEDIATION_EFFORT_KEY, 12 + 32);
257 public void no_measures_if_no_periods() {
258 periodsHolder.setPeriod(null);
259 DefaultIssue unresolved = newCodeSmellIssue(10);
261 underTest.beforeComponent(FILE);
262 underTest.onIssue(FILE, unresolved);
263 underTest.afterComponent(FILE);
265 assertThat(measureRepository.getRawMeasures(FILE)).isEmpty();
269 public void should_have_empty_measures_if_no_issues() {
270 periodsHolder.setPeriod(PERIOD);
272 underTest.beforeComponent(FILE);
273 underTest.afterComponent(FILE);
275 assertVariation(FILE, NEW_TECHNICAL_DEBT_KEY, 0);
276 assertVariation(FILE, NEW_RELIABILITY_REMEDIATION_EFFORT_KEY, 0);
277 assertVariation(FILE, NEW_SECURITY_REMEDIATION_EFFORT_KEY, 0);
280 private void assertVariation(Component component, String metricKey, int variation) {
281 Measure newMeasure = measureRepository.getRawMeasure(component, metricRepository.getByKey(metricKey)).get();
282 assertThat(newMeasure.getVariation()).isEqualTo(variation);
283 assertThat(newMeasure.getValueType()).isEqualTo(Measure.ValueType.NO_VALUE);
286 private static DefaultIssue newCodeSmellIssue(long effort) {
287 return newCodeSmellIssueWithoutEffort()
288 .setEffort(Duration.create(effort))
289 .setType(RuleType.CODE_SMELL)
290 .setCreationDate(new Date(PERIOD.getSnapshotDate() + 10_000L));
293 private DefaultIssue oldCodeSmellIssue(long effort) {
294 return newCodeSmellIssueWithoutEffort()
295 .setEffort(Duration.create(effort))
296 .setType(RuleType.CODE_SMELL)
297 .setCreationDate(new Date(OLD_ISSUES_DATES[random.nextInt(OLD_ISSUES_DATES.length)]));
300 private static DefaultIssue newBugIssue(long effort) {
301 return newCodeSmellIssueWithoutEffort()
302 .setEffort(Duration.create(effort))
303 .setType(RuleType.BUG)
304 .setCreationDate(new Date(PERIOD.getSnapshotDate() + 10_000L));
307 private DefaultIssue oldBugIssue(long effort) {
308 return newCodeSmellIssueWithoutEffort()
309 .setEffort(Duration.create(effort))
310 .setType(RuleType.BUG)
311 .setCreationDate(new Date(OLD_ISSUES_DATES[random.nextInt(OLD_ISSUES_DATES.length)]));
314 private static DefaultIssue newVulnerabilityIssue(long effort) {
315 return newCodeSmellIssueWithoutEffort()
316 .setEffort(Duration.create(effort))
317 .setType(RuleType.VULNERABILITY)
318 .setCreationDate(new Date(PERIOD.getSnapshotDate() + 10_000L));
321 private DefaultIssue oldVulnerabilityIssue(long effort) {
322 return newCodeSmellIssueWithoutEffort()
323 .setEffort(Duration.create(effort))
324 .setType(RuleType.VULNERABILITY)
325 .setCreationDate(new Date(OLD_ISSUES_DATES[random.nextInt(OLD_ISSUES_DATES.length)]));
328 private static DefaultIssue newCodeSmellIssueWithoutEffort() {
329 return new DefaultIssue()
331 .setCreationDate(new Date(PERIOD.getSnapshotDate() + 10_000L));
334 private static DefaultIssue newBugIssueWithoutEffort() {
335 return new DefaultIssue().setType(BUG);
338 private static DefaultIssue newVulnerabilityIssueWithoutEffort() {
339 return new DefaultIssue().setType(VULNERABILITY);