3 * Copyright (C) 2009-2024 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.qualitymodel;
22 import java.util.Arrays;
23 import java.util.Date;
24 import org.junit.Before;
25 import org.junit.Rule;
26 import org.junit.Test;
27 import org.sonar.api.rules.RuleType;
28 import org.sonar.api.utils.Duration;
29 import org.sonar.ce.task.projectanalysis.component.Component;
30 import org.sonar.ce.task.projectanalysis.component.FileAttributes;
31 import org.sonar.ce.task.projectanalysis.component.ReportComponent;
32 import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
33 import org.sonar.ce.task.projectanalysis.component.VisitorsCrawler;
34 import org.sonar.ce.task.projectanalysis.issue.ComponentIssuesRepositoryRule;
35 import org.sonar.ce.task.projectanalysis.issue.FillComponentIssuesVisitorRule;
36 import org.sonar.ce.task.projectanalysis.issue.NewIssueClassifier;
37 import org.sonar.ce.task.projectanalysis.measure.MeasureAssert;
38 import org.sonar.ce.task.projectanalysis.measure.MeasureRepositoryRule;
39 import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule;
40 import org.sonar.core.issue.DefaultIssue;
41 import org.sonar.core.util.UuidFactoryFast;
42 import org.sonar.server.measure.Rating;
44 import static org.assertj.core.api.Assertions.assertThat;
45 import static org.mockito.ArgumentMatchers.any;
46 import static org.mockito.ArgumentMatchers.eq;
47 import static org.mockito.Mockito.mock;
48 import static org.mockito.Mockito.when;
49 import static org.sonar.api.issue.Issue.RESOLUTION_FIXED;
50 import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_RATING;
51 import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_RATING_KEY;
52 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_RATING;
53 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_RATING_KEY;
54 import static org.sonar.api.rule.Severity.BLOCKER;
55 import static org.sonar.api.rule.Severity.CRITICAL;
56 import static org.sonar.api.rule.Severity.INFO;
57 import static org.sonar.api.rule.Severity.MAJOR;
58 import static org.sonar.api.rule.Severity.MINOR;
59 import static org.sonar.api.rules.RuleType.BUG;
60 import static org.sonar.api.rules.RuleType.CODE_SMELL;
61 import static org.sonar.api.rules.RuleType.VULNERABILITY;
62 import static org.sonar.ce.task.projectanalysis.component.Component.Type.DIRECTORY;
63 import static org.sonar.ce.task.projectanalysis.component.Component.Type.FILE;
64 import static org.sonar.ce.task.projectanalysis.component.Component.Type.PROJECT;
65 import static org.sonar.ce.task.projectanalysis.component.ReportComponent.builder;
66 import static org.sonar.server.measure.Rating.A;
67 import static org.sonar.server.measure.Rating.B;
68 import static org.sonar.server.measure.Rating.C;
69 import static org.sonar.server.measure.Rating.D;
70 import static org.sonar.server.measure.Rating.E;
72 public class NewReliabilityAndSecurityRatingMeasuresVisitorTest {
74 private static final long LEAK_PERIOD_SNAPSHOT_IN_MILLISEC = 12323L;
75 private static final Date DEFAULT_ISSUE_CREATION_DATE = new Date(1000L);
76 private static final Date AFTER_LEAK_PERIOD_DATE = new Date(LEAK_PERIOD_SNAPSHOT_IN_MILLISEC + 5000L);
78 static final String LANGUAGE_KEY_1 = "lKey1";
80 static final int PROJECT_REF = 1;
81 static final int ROOT_DIR_REF = 12;
82 static final int DIRECTORY_REF = 123;
83 static final int FILE_1_REF = 1231;
84 static final int FILE_2_REF = 1232;
86 static final Component ROOT_PROJECT = builder(Component.Type.PROJECT, PROJECT_REF).setKey("project")
88 builder(DIRECTORY, ROOT_DIR_REF).setKey("dir")
90 builder(DIRECTORY, DIRECTORY_REF).setKey("directory")
92 builder(FILE, FILE_1_REF).setFileAttributes(new FileAttributes(false, LANGUAGE_KEY_1, 1)).setKey("file1").build(),
93 builder(FILE, FILE_2_REF).setFileAttributes(new FileAttributes(false, LANGUAGE_KEY_1, 1)).setKey("file2").build())
99 public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
102 public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
103 .add(NEW_SECURITY_RATING)
104 .add(NEW_RELIABILITY_RATING);
107 public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
110 public ComponentIssuesRepositoryRule componentIssuesRepositoryRule = new ComponentIssuesRepositoryRule(treeRootHolder);
112 public FillComponentIssuesVisitorRule fillComponentIssuesVisitorRule = new FillComponentIssuesVisitorRule(componentIssuesRepositoryRule, treeRootHolder);
114 private final NewIssueClassifier newIssueClassifier = mock(NewIssueClassifier.class);
115 private final VisitorsCrawler underTest = new VisitorsCrawler(Arrays.asList(fillComponentIssuesVisitorRule,
116 new NewReliabilityAndSecurityRatingMeasuresVisitor(metricRepository, measureRepository, componentIssuesRepositoryRule, newIssueClassifier)));
119 public void before() {
120 when(newIssueClassifier.isEnabled()).thenReturn(true);
124 public void measures_created_for_project_are_all_A_when_they_have_no_FILE_child() {
125 ReportComponent root = builder(PROJECT, 1).build();
126 treeRootHolder.setRoot(root);
128 underTest.visit(root);
130 verifyAddedRawMeasureOnLeakPeriod(1, NEW_SECURITY_RATING_KEY, A);
131 verifyAddedRawMeasureOnLeakPeriod(1, NEW_RELIABILITY_RATING_KEY, A);
135 public void no_measure_if_there_is_no_period() {
136 when(newIssueClassifier.isEnabled()).thenReturn(false);
137 treeRootHolder.setRoot(builder(PROJECT, 1).build());
139 underTest.visit(treeRootHolder.getRoot());
141 assertThat(measureRepository.getAddedRawMeasures(1).values()).isEmpty();
145 public void compute_new_security_rating() {
146 treeRootHolder.setRoot(ROOT_PROJECT);
147 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
148 newVulnerabilityIssue(10L, MAJOR),
149 // Should not be taken into account
150 oldVulnerabilityIssue(1L, MAJOR),
151 newBugIssue(1L, MAJOR));
152 fillComponentIssuesVisitorRule.setIssues(FILE_2_REF,
153 newVulnerabilityIssue(2L, CRITICAL),
154 newVulnerabilityIssue(3L, MINOR),
155 // Should not be taken into account
156 newVulnerabilityIssue(10L, BLOCKER).setResolution(RESOLUTION_FIXED));
157 fillComponentIssuesVisitorRule.setIssues(ROOT_DIR_REF, newVulnerabilityIssue(7L, BLOCKER));
159 underTest.visit(ROOT_PROJECT);
161 verifyAddedRawMeasureOnLeakPeriod(FILE_1_REF, NEW_SECURITY_RATING_KEY, C);
162 verifyAddedRawMeasureOnLeakPeriod(FILE_2_REF, NEW_SECURITY_RATING_KEY, D);
163 verifyAddedRawMeasureOnLeakPeriod(DIRECTORY_REF, NEW_SECURITY_RATING_KEY, D);
164 verifyAddedRawMeasureOnLeakPeriod(ROOT_DIR_REF, NEW_SECURITY_RATING_KEY, E);
165 verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, E);
169 public void compute_new_security_rating_to_A_when_no_issue() {
170 treeRootHolder.setRoot(ROOT_PROJECT);
171 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF);
173 underTest.visit(ROOT_PROJECT);
175 verifyAddedRawMeasureOnLeakPeriod(FILE_1_REF, NEW_SECURITY_RATING_KEY, A);
176 verifyAddedRawMeasureOnLeakPeriod(FILE_2_REF, NEW_SECURITY_RATING_KEY, A);
177 verifyAddedRawMeasureOnLeakPeriod(DIRECTORY_REF, NEW_SECURITY_RATING_KEY, A);
178 verifyAddedRawMeasureOnLeakPeriod(ROOT_DIR_REF, NEW_SECURITY_RATING_KEY, A);
179 verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, A);
183 public void compute_new_security_rating_to_A_when_no_new_issue() {
184 treeRootHolder.setRoot(ROOT_PROJECT);
185 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, oldVulnerabilityIssue(1L, MAJOR));
187 underTest.visit(ROOT_PROJECT);
189 verifyAddedRawMeasureOnLeakPeriod(FILE_1_REF, NEW_SECURITY_RATING_KEY, A);
190 verifyAddedRawMeasureOnLeakPeriod(FILE_2_REF, NEW_SECURITY_RATING_KEY, A);
191 verifyAddedRawMeasureOnLeakPeriod(DIRECTORY_REF, NEW_SECURITY_RATING_KEY, A);
192 verifyAddedRawMeasureOnLeakPeriod(ROOT_DIR_REF, NEW_SECURITY_RATING_KEY, A);
193 verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, A);
197 public void compute_new_reliability_rating() {
198 treeRootHolder.setRoot(ROOT_PROJECT);
199 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
200 newBugIssue(10L, MAJOR),
201 // Should not be taken into account
202 oldBugIssue(1L, MAJOR),
203 newVulnerabilityIssue(1L, MAJOR));
204 fillComponentIssuesVisitorRule.setIssues(FILE_2_REF,
205 newBugIssue(2L, CRITICAL),
206 newBugIssue(3L, MINOR),
207 // Should not be taken into account
208 newBugIssue(10L, BLOCKER).setResolution(RESOLUTION_FIXED));
209 fillComponentIssuesVisitorRule.setIssues(ROOT_DIR_REF,
210 newBugIssue(7L, BLOCKER));
212 underTest.visit(ROOT_PROJECT);
214 verifyAddedRawMeasureOnLeakPeriod(FILE_1_REF, NEW_RELIABILITY_RATING_KEY, C);
215 verifyAddedRawMeasureOnLeakPeriod(FILE_2_REF, NEW_RELIABILITY_RATING_KEY, D);
216 verifyAddedRawMeasureOnLeakPeriod(DIRECTORY_REF, NEW_RELIABILITY_RATING_KEY, D);
217 verifyAddedRawMeasureOnLeakPeriod(ROOT_DIR_REF, NEW_RELIABILITY_RATING_KEY, E);
218 verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_RELIABILITY_RATING_KEY, E);
222 public void compute_new_reliability_rating_to_A_when_no_issue() {
223 treeRootHolder.setRoot(ROOT_PROJECT);
224 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF);
226 underTest.visit(ROOT_PROJECT);
228 verifyAddedRawMeasureOnLeakPeriod(FILE_1_REF, NEW_RELIABILITY_RATING_KEY, A);
229 verifyAddedRawMeasureOnLeakPeriod(FILE_2_REF, NEW_RELIABILITY_RATING_KEY, A);
230 verifyAddedRawMeasureOnLeakPeriod(DIRECTORY_REF, NEW_RELIABILITY_RATING_KEY, A);
231 verifyAddedRawMeasureOnLeakPeriod(ROOT_DIR_REF, NEW_RELIABILITY_RATING_KEY, A);
232 verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_RELIABILITY_RATING_KEY, A);
236 public void compute_new_reliability_rating_to_A_when_no_new_issue() {
237 treeRootHolder.setRoot(ROOT_PROJECT);
238 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, oldBugIssue(1L, MAJOR));
240 underTest.visit(ROOT_PROJECT);
242 verifyAddedRawMeasureOnLeakPeriod(FILE_1_REF, NEW_RELIABILITY_RATING_KEY, A);
243 verifyAddedRawMeasureOnLeakPeriod(FILE_2_REF, NEW_RELIABILITY_RATING_KEY, A);
244 verifyAddedRawMeasureOnLeakPeriod(DIRECTORY_REF, NEW_RELIABILITY_RATING_KEY, A);
245 verifyAddedRawMeasureOnLeakPeriod(ROOT_DIR_REF, NEW_RELIABILITY_RATING_KEY, A);
246 verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_RELIABILITY_RATING_KEY, A);
250 public void compute_E_reliability_and_security_rating_on_blocker_issue() {
251 treeRootHolder.setRoot(ROOT_PROJECT);
252 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
253 newBugIssue(10L, BLOCKER),
254 newVulnerabilityIssue(1L, BLOCKER),
255 // Should not be taken into account
256 newBugIssue(1L, MAJOR));
258 underTest.visit(ROOT_PROJECT);
260 verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_RELIABILITY_RATING_KEY, E);
261 verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, E);
265 public void compute_D_reliability_and_security_rating_on_critical_issue() {
266 treeRootHolder.setRoot(ROOT_PROJECT);
267 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
268 newBugIssue(10L, CRITICAL),
269 newVulnerabilityIssue(15L, CRITICAL),
270 // Should not be taken into account
271 newCodeSmellIssue(1L, MAJOR));
273 underTest.visit(ROOT_PROJECT);
275 verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_RELIABILITY_RATING_KEY, D);
276 verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, D);
280 public void compute_C_reliability_and_security_rating_on_major_issue() {
281 treeRootHolder.setRoot(ROOT_PROJECT);
282 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
283 newBugIssue(10L, MAJOR),
284 newVulnerabilityIssue(15L, MAJOR),
285 // Should not be taken into account
286 newCodeSmellIssue(1L, MAJOR));
288 underTest.visit(ROOT_PROJECT);
290 verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_RELIABILITY_RATING_KEY, C);
291 verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, C);
295 public void compute_B_reliability_and_security_rating_on_minor_issue() {
296 treeRootHolder.setRoot(ROOT_PROJECT);
297 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
298 newBugIssue(10L, MINOR),
299 newVulnerabilityIssue(15L, MINOR),
300 // Should not be taken into account
301 newCodeSmellIssue(1L, MAJOR));
303 underTest.visit(ROOT_PROJECT);
305 verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_RELIABILITY_RATING_KEY, B);
306 verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, B);
310 public void compute_A_reliability_and_security_rating_on_info_issue() {
311 treeRootHolder.setRoot(ROOT_PROJECT);
312 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
313 newBugIssue(10L, INFO).setCreationDate(AFTER_LEAK_PERIOD_DATE),
314 newVulnerabilityIssue(15L, INFO).setCreationDate(AFTER_LEAK_PERIOD_DATE),
315 // Should not be taken into account
316 newCodeSmellIssue(1L, MAJOR).setCreationDate(AFTER_LEAK_PERIOD_DATE));
318 underTest.visit(ROOT_PROJECT);
320 verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_RELIABILITY_RATING_KEY, A);
321 verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, A);
324 private void verifyAddedRawMeasureOnLeakPeriod(int componentRef, String metricKey, Rating rating) {
325 MeasureAssert.assertThat(measureRepository.getAddedRawMeasure(componentRef, metricKey)).hasValue(rating.getIndex());
328 private DefaultIssue newBugIssue(long effort, String severity) {
329 return createIssue(effort, severity, BUG, true);
332 private DefaultIssue oldBugIssue(long effort, String severity) {
333 return createIssue(effort, severity, BUG, false);
336 private DefaultIssue newVulnerabilityIssue(long effort, String severity) {
337 return createIssue(effort, severity, VULNERABILITY, true);
340 private DefaultIssue oldVulnerabilityIssue(long effort, String severity) {
341 return createIssue(effort, severity, VULNERABILITY, false);
344 private DefaultIssue newCodeSmellIssue(long effort, String severity) {
345 return createIssue(effort, severity, CODE_SMELL, true);
348 private DefaultIssue createIssue(long effort, String severity, RuleType type, boolean isNew) {
349 DefaultIssue issue = createIssue(severity, type)
350 .setEffort(Duration.create(effort));
351 when(newIssueClassifier.isNew(any(), eq(issue))).thenReturn(isNew);
355 private static DefaultIssue createIssue(String severity, RuleType type) {
356 return new DefaultIssue()
357 .setKey(UuidFactoryFast.getInstance().create())
358 .setSeverity(severity)
360 .setCreationDate(DEFAULT_ISSUE_CREATION_DATE);