3 * Copyright (C) 2009-2017 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.server.computation.task.projectanalysis.issue;
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;
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;
56 public class NewEffortAggregatorTest {
58 private static final Period PERIOD = new Period(LEAK_PERIOD_MODE_PREVIOUS_ANALYSIS, null, 1_500_000_000L, "U1");
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();
63 private NewEffortCalculator calculator = mock(NewEffortCalculator.class);
66 public PeriodHolderRule periodsHolder = new PeriodHolderRule();
69 public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
70 .add(NEW_TECHNICAL_DEBT)
71 .add(NEW_RELIABILITY_REMEDIATION_EFFORT)
72 .add(NEW_SECURITY_REMEDIATION_EFFORT);
75 public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create();
77 private DbClient dbClient = mock(DbClient.class, Mockito.RETURNS_DEEP_STUBS);
79 private NewEffortAggregator underTest = new NewEffortAggregator(calculator, periodsHolder, dbClient, metricRepository, measureRepository);
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);
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);
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);
100 assertVariation(FILE, NEW_TECHNICAL_DEBT_KEY, 3 + 4);
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);
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);
115 underTest.beforeComponent(FILE);
116 underTest.onIssue(FILE, codeSmellIssue);
117 underTest.onIssue(FILE, bugIssue);
118 underTest.onIssue(FILE, vulnerabilityIssue);
119 underTest.afterComponent(FILE);
121 // Only effort of CODE SMELL issue is used
122 assertVariation(FILE, NEW_TECHNICAL_DEBT_KEY, 4);
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);
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);
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);
144 assertVariation(FILE, NEW_RELIABILITY_REMEDIATION_EFFORT_KEY, 3 + 4);
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);
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);
159 underTest.beforeComponent(FILE);
160 underTest.onIssue(FILE, bugIssue);
161 underTest.onIssue(FILE, codeSmellIssue);
162 underTest.onIssue(FILE, vulnerabilityIssue);
163 underTest.afterComponent(FILE);
165 // Only effort of BUG issue is used
166 assertVariation(FILE, NEW_RELIABILITY_REMEDIATION_EFFORT_KEY, 3);
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);
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);
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);
188 assertVariation(FILE, NEW_SECURITY_REMEDIATION_EFFORT_KEY, 3 + 4);
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);
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);
203 underTest.beforeComponent(FILE);
204 underTest.onIssue(FILE, codeSmellIssue);
205 underTest.onIssue(FILE, bugIssue);
206 underTest.onIssue(FILE, vulnerabilityIssue);
207 underTest.afterComponent(FILE);
209 // Only effort of VULNERABILITY issue is used
210 assertVariation(FILE, NEW_SECURITY_REMEDIATION_EFFORT_KEY, 5);
214 public void aggregate_new_characteristic_measures_of_children() {
215 periodsHolder.setPeriod(PERIOD);
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);
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);
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);
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);
248 public void no_measures_if_no_periods() {
249 periodsHolder.setPeriod(null);
250 DefaultIssue unresolved = new DefaultIssue().setEffort(Duration.create(10));
251 verifyZeroInteractions(calculator);
253 underTest.beforeComponent(FILE);
254 underTest.onIssue(FILE, unresolved);
255 underTest.afterComponent(FILE);
257 assertThat(measureRepository.getRawMeasures(FILE)).isEmpty();
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);
265 private static DefaultIssue newCodeSmellIssue(long effort) {
266 return newCodeSmellIssueWithoutEffort().setEffort(Duration.create(effort)).setType(RuleType.CODE_SMELL);
269 private static DefaultIssue newBugIssue(long effort) {
270 return newCodeSmellIssueWithoutEffort().setEffort(Duration.create(effort)).setType(RuleType.BUG);
273 private static DefaultIssue newVulnerabilityIssue(long effort) {
274 return newCodeSmellIssueWithoutEffort().setEffort(Duration.create(effort)).setType(RuleType.VULNERABILITY);
277 private static DefaultIssue newCodeSmellIssueWithoutEffort() {
278 return new DefaultIssue().setType(CODE_SMELL);
281 private static DefaultIssue newBugIssueWithoutEffort() {
282 return new DefaultIssue().setType(BUG);
285 private static DefaultIssue newVulnerabilityIssueWithoutEffort() {
286 return new DefaultIssue().setType(VULNERABILITY);