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.jupiter.api.Test;
25 import org.junit.jupiter.api.extension.RegisterExtension;
26 import org.sonar.api.issue.impact.Severity;
27 import org.sonar.api.issue.impact.SoftwareQuality;
28 import org.sonar.api.rules.RuleType;
29 import org.sonar.api.utils.Duration;
30 import org.sonar.ce.task.projectanalysis.component.Component;
31 import org.sonar.ce.task.projectanalysis.component.FileAttributes;
32 import org.sonar.ce.task.projectanalysis.component.ReportComponent;
33 import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
34 import org.sonar.ce.task.projectanalysis.component.VisitorsCrawler;
35 import org.sonar.ce.task.projectanalysis.issue.ComponentIssuesRepositoryRule;
36 import org.sonar.ce.task.projectanalysis.issue.FillComponentIssuesVisitorRule;
37 import org.sonar.ce.task.projectanalysis.measure.Measure;
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.Uuids;
42 import org.sonar.server.measure.Rating;
44 import static org.assertj.core.api.Assertions.assertThat;
45 import static org.sonar.api.issue.Issue.RESOLUTION_FIXED;
46 import static org.sonar.api.measures.CoreMetrics.RELIABILITY_RATING;
47 import static org.sonar.api.measures.CoreMetrics.RELIABILITY_RATING_KEY;
48 import static org.sonar.api.measures.CoreMetrics.SECURITY_RATING;
49 import static org.sonar.api.measures.CoreMetrics.SECURITY_RATING_KEY;
50 import static org.sonar.api.rule.Severity.BLOCKER;
51 import static org.sonar.api.rule.Severity.CRITICAL;
52 import static org.sonar.api.rule.Severity.INFO;
53 import static org.sonar.api.rule.Severity.MAJOR;
54 import static org.sonar.api.rule.Severity.MINOR;
55 import static org.sonar.api.rules.RuleType.BUG;
56 import static org.sonar.api.rules.RuleType.CODE_SMELL;
57 import static org.sonar.api.rules.RuleType.VULNERABILITY;
58 import static org.sonar.ce.task.projectanalysis.component.Component.Type.DIRECTORY;
59 import static org.sonar.ce.task.projectanalysis.component.Component.Type.FILE;
60 import static org.sonar.ce.task.projectanalysis.component.Component.Type.PROJECT;
61 import static org.sonar.ce.task.projectanalysis.component.ReportComponent.builder;
62 import static org.sonar.ce.task.projectanalysis.measure.Measure.newMeasureBuilder;
63 import static org.sonar.ce.task.projectanalysis.measure.MeasureRepoEntry.entryOf;
64 import static org.sonar.ce.task.projectanalysis.measure.MeasureRepoEntry.toEntries;
65 import static org.sonar.server.measure.Rating.A;
66 import static org.sonar.server.measure.Rating.B;
67 import static org.sonar.server.measure.Rating.C;
68 import static org.sonar.server.measure.Rating.D;
69 import static org.sonar.server.measure.Rating.E;
70 import static org.sonar.server.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY;
71 import static org.sonar.server.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING;
72 import static org.sonar.server.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING_KEY;
73 import static org.sonar.server.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING;
74 import static org.sonar.server.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING_KEY;
76 class ReliabilityAndSecurityRatingMeasuresVisitorTest {
78 static final String LANGUAGE_KEY_1 = "lKey1";
80 static final int PROJECT_REF = 1;
81 static final int DIRECTORY_REF = 123;
82 static final int FILE_1_REF = 1231;
83 static final int FILE_2_REF = 1232;
84 static final int FILE_3_REF = 1233;
86 static final Component ROOT_PROJECT = builder(Component.Type.PROJECT, PROJECT_REF).setKey("project")
88 builder(DIRECTORY, DIRECTORY_REF).setKey("directory")
90 builder(FILE, FILE_1_REF).setFileAttributes(new FileAttributes(false, LANGUAGE_KEY_1, 1)).setKey("file1").build(),
91 builder(FILE, FILE_2_REF).setFileAttributes(new FileAttributes(false, LANGUAGE_KEY_1, 1)).setKey("file2").build(),
92 builder(FILE, FILE_3_REF).setFileAttributes(new FileAttributes(false, LANGUAGE_KEY_1, 1)).setKey("file3").build())
97 TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
100 MetricRepositoryRule metricRepository = new MetricRepositoryRule()
101 .add(RELIABILITY_RATING)
102 .add(SECURITY_RATING)
103 .add(SOFTWARE_QUALITY_RELIABILITY_RATING)
104 .add(SOFTWARE_QUALITY_SECURITY_RATING);
107 MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
109 private final ComponentIssuesRepositoryRule componentIssuesRepositoryRule = new ComponentIssuesRepositoryRule(treeRootHolder);
112 public FillComponentIssuesVisitorRule fillComponentIssuesVisitorRule = new FillComponentIssuesVisitorRule(componentIssuesRepositoryRule, treeRootHolder);
114 VisitorsCrawler underTest = new VisitorsCrawler(
115 Arrays.asList(fillComponentIssuesVisitorRule, new ReliabilityAndSecurityRatingMeasuresVisitor(metricRepository, measureRepository, componentIssuesRepositoryRule)));
118 void measures_created_for_project_are_all_A_when_they_have_no_FILE_child() {
119 ReportComponent root = builder(PROJECT, 1).build();
120 treeRootHolder.setRoot(root);
122 underTest.visit(root);
124 assertThat(measureRepository.getRawMeasures(root)
125 .entrySet().stream().map(e -> entryOf(e.getKey(), e.getValue())))
127 entryOf(RELIABILITY_RATING_KEY, createRatingMeasure(A)),
128 entryOf(SECURITY_RATING_KEY, createRatingMeasure(A)),
129 entryOf(SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, createRatingMeasure(A)),
130 entryOf(SOFTWARE_QUALITY_SECURITY_RATING_KEY, createRatingMeasure(A)));
134 void compute_reliability_rating() {
135 treeRootHolder.setRoot(ROOT_PROJECT);
136 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, MAJOR), newBugIssue(1L, MAJOR),
137 // Should not be taken into account
138 newVulnerabilityIssue(5L, MINOR));
139 fillComponentIssuesVisitorRule.setIssues(FILE_2_REF, newBugIssue(2L, CRITICAL), newBugIssue(3L, MINOR),
140 // Should not be taken into account
141 newBugIssue(10L, BLOCKER).setResolution(RESOLUTION_FIXED));
142 fillComponentIssuesVisitorRule.setIssues(PROJECT_REF, newBugIssue(7L, BLOCKER));
144 underTest.visit(ROOT_PROJECT);
146 verifyAddedRawMeasure(FILE_1_REF, RELIABILITY_RATING_KEY, C);
147 verifyAddedRawMeasure(FILE_2_REF, RELIABILITY_RATING_KEY, D);
148 verifyAddedRawMeasure(DIRECTORY_REF, RELIABILITY_RATING_KEY, D);
149 verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, E);
153 void compute_software_quality_reliability_rating() {
154 treeRootHolder.setRoot(ROOT_PROJECT);
155 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
156 newImpactIssue(SoftwareQuality.RELIABILITY, Severity.LOW),
157 // Should not be taken into account
158 newImpactIssue(SoftwareQuality.SECURITY, Severity.HIGH));
159 fillComponentIssuesVisitorRule.setIssues(FILE_2_REF,
160 newImpactIssue(SoftwareQuality.RELIABILITY, Severity.MEDIUM),
161 // Should not be taken into account
162 newImpactIssue(SoftwareQuality.SECURITY, Severity.HIGH));
163 fillComponentIssuesVisitorRule.setIssues(FILE_3_REF,
164 // Should not be taken into account
165 newImpactIssue(SoftwareQuality.SECURITY, Severity.HIGH));
167 fillComponentIssuesVisitorRule.setIssues(PROJECT_REF, newImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH));
169 underTest.visit(ROOT_PROJECT);
171 verifyAddedRawMeasure(FILE_1_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, B);
172 verifyAddedRawMeasure(FILE_2_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, C);
173 verifyAddedRawMeasure(FILE_3_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, A);
174 verifyAddedRawMeasure(DIRECTORY_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, C);
175 verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, D);
179 void compute_security_rating() {
180 treeRootHolder.setRoot(ROOT_PROJECT);
181 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newVulnerabilityIssue(10L, MAJOR), newVulnerabilityIssue(1L, MAJOR),
182 // Should not be taken into account
183 newBugIssue(1L, MAJOR));
184 fillComponentIssuesVisitorRule.setIssues(FILE_2_REF, newVulnerabilityIssue(2L, CRITICAL), newVulnerabilityIssue(3L, MINOR),
185 // Should not be taken into account
186 newVulnerabilityIssue(10L, BLOCKER).setResolution(RESOLUTION_FIXED));
187 fillComponentIssuesVisitorRule.setIssues(PROJECT_REF, newVulnerabilityIssue(7L, BLOCKER));
189 underTest.visit(ROOT_PROJECT);
191 verifyAddedRawMeasure(FILE_1_REF, SECURITY_RATING_KEY, C);
192 verifyAddedRawMeasure(FILE_2_REF, SECURITY_RATING_KEY, D);
193 verifyAddedRawMeasure(DIRECTORY_REF, SECURITY_RATING_KEY, D);
194 verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, E);
198 void compute_software_quality_security_rating() {
199 treeRootHolder.setRoot(ROOT_PROJECT);
200 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
201 newImpactIssue(SoftwareQuality.SECURITY, Severity.LOW),
202 // Should not be taken into account
203 newImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH));
204 fillComponentIssuesVisitorRule.setIssues(FILE_2_REF,
205 newImpactIssue(SoftwareQuality.SECURITY, Severity.MEDIUM),
206 // Should not be taken into account
207 newImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH));
208 fillComponentIssuesVisitorRule.setIssues(FILE_3_REF,
209 // Should not be taken into account
210 newImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH));
212 fillComponentIssuesVisitorRule.setIssues(PROJECT_REF, newImpactIssue(SoftwareQuality.SECURITY, Severity.HIGH));
214 underTest.visit(ROOT_PROJECT);
216 verifyAddedRawMeasure(FILE_1_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, B);
217 verifyAddedRawMeasure(FILE_2_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, C);
218 verifyAddedRawMeasure(FILE_3_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, A);
219 verifyAddedRawMeasure(DIRECTORY_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, C);
220 verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, D);
224 void compute_E_reliability_and_security_rating_on_blocker_issue() {
225 treeRootHolder.setRoot(ROOT_PROJECT);
226 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, BLOCKER), newVulnerabilityIssue(1L, BLOCKER),
227 // Should not be taken into account
228 newBugIssue(1L, MAJOR));
230 underTest.visit(ROOT_PROJECT);
232 verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, E);
233 verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, E);
237 void compute_D_reliability_and_security_rating_on_critical_issue() {
238 treeRootHolder.setRoot(ROOT_PROJECT);
239 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, CRITICAL), newVulnerabilityIssue(15L, CRITICAL),
240 // Should not be taken into account
241 newCodeSmellIssue(1L, MAJOR));
243 underTest.visit(ROOT_PROJECT);
245 verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, D);
246 verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, D);
250 void compute_D_software_quality_reliability_and_security_rating_on_high_issue() {
251 treeRootHolder.setRoot(ROOT_PROJECT);
252 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH), newImpactIssue(SoftwareQuality.SECURITY, Severity.HIGH),
253 // Should not be taken into account
254 newImpactIssue(SoftwareQuality.MAINTAINABILITY, Severity.HIGH));
256 underTest.visit(ROOT_PROJECT);
258 verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, D);
259 verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, D);
263 void compute_C_reliability_and_security_rating_on_major_issue() {
264 treeRootHolder.setRoot(ROOT_PROJECT);
265 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, MAJOR), newVulnerabilityIssue(15L, MAJOR),
266 // Should not be taken into account
267 newCodeSmellIssue(1L, MAJOR));
269 underTest.visit(ROOT_PROJECT);
271 verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, C);
272 verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, C);
276 void compute_C_software_quality_reliability_and_security_rating_on_medium_issue() {
277 treeRootHolder.setRoot(ROOT_PROJECT);
278 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newImpactIssue(SoftwareQuality.RELIABILITY, Severity.MEDIUM), newImpactIssue(SoftwareQuality.SECURITY, Severity.MEDIUM),
279 // Should not be taken into account
280 newImpactIssue(SoftwareQuality.MAINTAINABILITY, Severity.HIGH));
282 underTest.visit(ROOT_PROJECT);
284 verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, C);
285 verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, C);
289 void compute_B_reliability_and_security_rating_on_minor_issue() {
290 treeRootHolder.setRoot(ROOT_PROJECT);
291 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, MINOR), newVulnerabilityIssue(15L, MINOR),
292 // Should not be taken into account
293 newCodeSmellIssue(1L, MAJOR));
295 underTest.visit(ROOT_PROJECT);
297 verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, B);
298 verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, B);
302 void compute_B_software_quality_reliability_and_security_rating_on_low_issue() {
303 treeRootHolder.setRoot(ROOT_PROJECT);
304 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newImpactIssue(SoftwareQuality.RELIABILITY, Severity.LOW), newImpactIssue(SoftwareQuality.SECURITY, Severity.LOW),
305 // Should not be taken into account
306 newImpactIssue(SoftwareQuality.MAINTAINABILITY, Severity.HIGH));
308 underTest.visit(ROOT_PROJECT);
310 verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, B);
311 verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, B);
315 void compute_A_reliability_and_security_rating_on_info_issue() {
316 treeRootHolder.setRoot(ROOT_PROJECT);
317 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, INFO), newVulnerabilityIssue(15L, INFO),
318 // Should not be taken into account
319 newCodeSmellIssue(1L, MAJOR));
321 underTest.visit(ROOT_PROJECT);
323 verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, A);
324 verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, A);
328 void compute_A_software_quality_reliability_and_security_rating_when_no_issue() {
329 treeRootHolder.setRoot(ROOT_PROJECT);
330 fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
331 // Should not be taken into account
332 newImpactIssue(SoftwareQuality.MAINTAINABILITY, Severity.HIGH));
334 underTest.visit(ROOT_PROJECT);
336 verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, A);
337 verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, A);
340 private void verifyAddedRawMeasure(int componentRef, String metricKey, Rating rating) {
341 assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).contains(entryOf(metricKey, newMeasureBuilder().create(rating.getIndex(), rating.name())));
344 private static Measure createRatingMeasure(Rating rating) {
345 return newMeasureBuilder().create(rating.getIndex(), rating.name());
348 private static DefaultIssue newBugIssue(long effort, String severity) {
349 return newIssue(effort, severity, BUG);
352 private static DefaultIssue newVulnerabilityIssue(long effort, String severity) {
353 return newIssue(effort, severity, VULNERABILITY);
356 private static DefaultIssue newCodeSmellIssue(long effort, String severity) {
357 return newIssue(effort, severity, CODE_SMELL);
360 private static DefaultIssue newIssue(long effort, String severity, RuleType type) {
361 return newIssue(severity, type)
362 .setEffort(Duration.create(effort));
365 private static DefaultIssue newIssue(String severity, RuleType type) {
366 return new DefaultIssue()
367 .setKey(Uuids.create())
368 .setSeverity(severity)
370 .setCreationDate(new Date(1000L));
373 private static DefaultIssue newImpactIssue(SoftwareQuality softwareQuality, Severity severity) {
374 return new DefaultIssue()
375 .setKey(Uuids.create())
376 .addImpact(softwareQuality, severity)
378 .setSeverity("BLOCKER")
379 .setCreationDate(new Date(1000L));