]> source.dussan.org Git - sonarqube.git/blob
d89c7fbae1e221c0e39b8556dcf825eabf1087fe
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2024 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.ce.task.projectanalysis.qualitymodel;
21
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;
43
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;
75
76 class ReliabilityAndSecurityRatingMeasuresVisitorTest {
77
78   static final String LANGUAGE_KEY_1 = "lKey1";
79
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;
85
86   static final Component ROOT_PROJECT = builder(Component.Type.PROJECT, PROJECT_REF).setKey("project")
87     .addChildren(
88       builder(DIRECTORY, DIRECTORY_REF).setKey("directory")
89         .addChildren(
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())
93         .build())
94     .build();
95
96   @RegisterExtension
97   TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
98
99   @RegisterExtension
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);
105
106   @RegisterExtension
107   MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
108
109   private final ComponentIssuesRepositoryRule componentIssuesRepositoryRule = new ComponentIssuesRepositoryRule(treeRootHolder);
110
111   @RegisterExtension
112   public FillComponentIssuesVisitorRule fillComponentIssuesVisitorRule = new FillComponentIssuesVisitorRule(componentIssuesRepositoryRule, treeRootHolder);
113
114   VisitorsCrawler underTest = new VisitorsCrawler(
115     Arrays.asList(fillComponentIssuesVisitorRule, new ReliabilityAndSecurityRatingMeasuresVisitor(metricRepository, measureRepository, componentIssuesRepositoryRule)));
116
117   @Test
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);
121
122     underTest.visit(root);
123
124     assertThat(measureRepository.getRawMeasures(root)
125       .entrySet().stream().map(e -> entryOf(e.getKey(), e.getValue())))
126       .containsOnly(
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)));
131   }
132
133   @Test
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));
143
144     underTest.visit(ROOT_PROJECT);
145
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);
150   }
151
152   @Test
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));
166
167     fillComponentIssuesVisitorRule.setIssues(PROJECT_REF, newImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH));
168
169     underTest.visit(ROOT_PROJECT);
170
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);
176   }
177
178   @Test
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));
188
189     underTest.visit(ROOT_PROJECT);
190
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);
195   }
196
197   @Test
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));
211
212     fillComponentIssuesVisitorRule.setIssues(PROJECT_REF, newImpactIssue(SoftwareQuality.SECURITY, Severity.HIGH));
213
214     underTest.visit(ROOT_PROJECT);
215
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);
221   }
222
223   @Test
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));
229
230     underTest.visit(ROOT_PROJECT);
231
232     verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, E);
233     verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, E);
234   }
235
236   @Test
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));
242
243     underTest.visit(ROOT_PROJECT);
244
245     verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, D);
246     verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, D);
247   }
248
249   @Test
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));
255
256     underTest.visit(ROOT_PROJECT);
257
258     verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, D);
259     verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, D);
260   }
261
262   @Test
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));
268
269     underTest.visit(ROOT_PROJECT);
270
271     verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, C);
272     verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, C);
273   }
274
275   @Test
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));
281
282     underTest.visit(ROOT_PROJECT);
283
284     verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, C);
285     verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, C);
286   }
287
288   @Test
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));
294
295     underTest.visit(ROOT_PROJECT);
296
297     verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, B);
298     verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, B);
299   }
300
301   @Test
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));
307
308     underTest.visit(ROOT_PROJECT);
309
310     verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, B);
311     verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, B);
312   }
313
314   @Test
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));
320
321     underTest.visit(ROOT_PROJECT);
322
323     verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, A);
324     verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, A);
325   }
326
327   @Test
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));
333
334     underTest.visit(ROOT_PROJECT);
335
336     verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, A);
337     verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, A);
338   }
339
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())));
342   }
343
344   private static Measure createRatingMeasure(Rating rating) {
345     return newMeasureBuilder().create(rating.getIndex(), rating.name());
346   }
347
348   private static DefaultIssue newBugIssue(long effort, String severity) {
349     return newIssue(effort, severity, BUG);
350   }
351
352   private static DefaultIssue newVulnerabilityIssue(long effort, String severity) {
353     return newIssue(effort, severity, VULNERABILITY);
354   }
355
356   private static DefaultIssue newCodeSmellIssue(long effort, String severity) {
357     return newIssue(effort, severity, CODE_SMELL);
358   }
359
360   private static DefaultIssue newIssue(long effort, String severity, RuleType type) {
361     return newIssue(severity, type)
362       .setEffort(Duration.create(effort));
363   }
364
365   private static DefaultIssue newIssue(String severity, RuleType type) {
366     return new DefaultIssue()
367       .setKey(Uuids.create())
368       .setSeverity(severity)
369       .setType(type)
370       .setCreationDate(new Date(1000L));
371   }
372
373   private static DefaultIssue newImpactIssue(SoftwareQuality softwareQuality, Severity severity) {
374     return new DefaultIssue()
375       .setKey(Uuids.create())
376       .addImpact(softwareQuality, severity)
377       .setType(BUG)
378       .setSeverity("BLOCKER")
379       .setCreationDate(new Date(1000L));
380   }
381
382 }