]> source.dussan.org Git - sonarqube.git/blob
7d6d267f752fd229377be44b7078d1a231952b87
[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 javax.annotation.Nullable;
23 import org.junit.Rule;
24 import org.junit.Test;
25 import org.sonar.api.rules.RuleType;
26 import org.sonar.ce.task.projectanalysis.component.Component;
27 import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
28 import org.sonar.ce.task.projectanalysis.component.VisitorsCrawler;
29 import org.sonar.ce.task.projectanalysis.issue.ComponentIssuesRepositoryRule;
30 import org.sonar.ce.task.projectanalysis.issue.FillComponentIssuesVisitorRule;
31 import org.sonar.ce.task.projectanalysis.measure.Measure;
32 import org.sonar.ce.task.projectanalysis.measure.MeasureRepositoryRule;
33 import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule;
34 import org.sonar.core.issue.DefaultIssue;
35 import org.sonar.core.util.Uuids;
36 import org.sonar.server.measure.Rating;
37
38 import static java.util.Arrays.asList;
39 import static org.assertj.core.api.Assertions.assertThat;
40 import static org.sonar.api.issue.Issue.RESOLUTION_FIXED;
41 import static org.sonar.api.issue.Issue.RESOLUTION_SAFE;
42 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_REVIEWED;
43 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_KEY;
44 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS;
45 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY;
46 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS;
47 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY;
48 import static org.sonar.api.measures.CoreMetrics.SECURITY_REVIEW_RATING;
49 import static org.sonar.api.measures.CoreMetrics.SECURITY_REVIEW_RATING_KEY;
50 import static org.sonar.api.rule.Severity.MAJOR;
51 import static org.sonar.api.rule.Severity.MINOR;
52 import static org.sonar.ce.task.projectanalysis.component.Component.Type.DIRECTORY;
53 import static org.sonar.ce.task.projectanalysis.component.Component.Type.FILE;
54 import static org.sonar.ce.task.projectanalysis.component.ReportComponent.builder;
55 import static org.sonar.core.issue.DefaultIssue.STATUS_REVIEWED;
56 import static org.sonar.core.issue.DefaultIssue.STATUS_TO_REVIEW;
57 import static org.sonar.server.measure.Rating.A;
58 import static org.sonar.server.measure.Rating.B;
59 import static org.sonar.server.measure.Rating.C;
60 import static org.sonar.server.measure.Rating.D;
61 import static org.sonar.server.measure.Rating.E;
62
63 public class SecurityReviewMeasuresVisitorTest {
64
65   private static final int PROJECT_REF = 1;
66   private static final int ROOT_DIR_REF = 12;
67   private static final int DIRECTORY_REF = 123;
68   private static final int FILE_1_REF = 1231;
69   private static final int FILE_2_REF = 1232;
70
71   static final Component ROOT_PROJECT = builder(Component.Type.PROJECT, PROJECT_REF).setKey("project")
72     .addChildren(
73       builder(DIRECTORY, ROOT_DIR_REF).setKey("dir")
74         .addChildren(
75           builder(DIRECTORY, DIRECTORY_REF).setKey("directory")
76             .addChildren(
77               builder(FILE, FILE_1_REF).setKey("file1").build(),
78               builder(FILE, FILE_2_REF).setKey("file2").build())
79             .build())
80         .build())
81     .build();
82
83   @Rule
84   public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
85   @Rule
86   public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
87     .add(SECURITY_REVIEW_RATING)
88     .add(SECURITY_HOTSPOTS_REVIEWED)
89     .add(SECURITY_HOTSPOTS_REVIEWED_STATUS)
90     .add(SECURITY_HOTSPOTS_TO_REVIEW_STATUS);
91   @Rule
92   public ComponentIssuesRepositoryRule componentIssuesRepositoryRule = new ComponentIssuesRepositoryRule(treeRootHolder);
93   @Rule
94   public FillComponentIssuesVisitorRule fillComponentIssuesVisitorRule = new FillComponentIssuesVisitorRule(componentIssuesRepositoryRule, treeRootHolder);
95   @Rule
96   public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
97
98   private VisitorsCrawler underTest = new VisitorsCrawler(asList(fillComponentIssuesVisitorRule,
99     new SecurityReviewMeasuresVisitor(componentIssuesRepositoryRule, measureRepository, metricRepository)));
100
101   @Test
102   public void compute_rating_and_reviewed_measures_when_100_percent_hotspots_reviewed() {
103     treeRootHolder.setRoot(ROOT_PROJECT);
104     fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
105       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
106       // Should not be taken into account
107       newIssue());
108     fillComponentIssuesVisitorRule.setIssues(FILE_2_REF,
109       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
110       newHotspot(STATUS_REVIEWED, RESOLUTION_SAFE),
111       newIssue());
112
113     underTest.visit(ROOT_PROJECT);
114
115     verifyRatingAndReviewedMeasures(FILE_1_REF, A, 100.0);
116     verifyRatingAndReviewedMeasures(FILE_2_REF, A, 100.0);
117     verifyRatingAndReviewedMeasures(DIRECTORY_REF, A, 100.0);
118     verifyRatingAndReviewedMeasures(ROOT_DIR_REF, A, 100.0);
119     verifyRatingAndReviewedMeasures(PROJECT_REF, A, 100.0);
120   }
121
122   @Test
123   public void compute_rating_and_reviewed__measures_when_more_than_80_percent_hotspots_reviewed() {
124     treeRootHolder.setRoot(ROOT_PROJECT);
125     fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
126       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
127       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
128       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
129       // Should not be taken into account
130       newIssue());
131     fillComponentIssuesVisitorRule.setIssues(FILE_2_REF,
132       newHotspot(STATUS_TO_REVIEW, null),
133       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
134       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
135       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
136       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
137       newIssue());
138
139     underTest.visit(ROOT_PROJECT);
140
141     verifyRatingAndReviewedMeasures(FILE_1_REF, A, 100.0);
142     verifyRatingAndReviewedMeasures(FILE_2_REF, A, 80.0);
143     verifyRatingAndReviewedMeasures(DIRECTORY_REF, A, 87.5);
144     verifyRatingAndReviewedMeasures(ROOT_DIR_REF, A, 87.5);
145     verifyRatingAndReviewedMeasures(PROJECT_REF, A, 87.5);
146   }
147
148   @Test
149   public void compute_rating_and_reviewed__measures_when_more_than_70_percent_hotspots_reviewed() {
150     treeRootHolder.setRoot(ROOT_PROJECT);
151     fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
152       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
153       // Should not be taken into account
154       newIssue());
155     fillComponentIssuesVisitorRule.setIssues(FILE_2_REF,
156       newHotspot(STATUS_TO_REVIEW, null),
157       newHotspot(STATUS_TO_REVIEW, null),
158       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
159       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
160       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
161       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
162       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
163       newIssue());
164
165     underTest.visit(ROOT_PROJECT);
166
167     verifyRatingAndReviewedMeasures(FILE_1_REF, A, 100.0);
168     verifyRatingAndReviewedMeasures(FILE_2_REF, B, 71.4);
169     verifyRatingAndReviewedMeasures(DIRECTORY_REF, B, 75.0);
170     verifyRatingAndReviewedMeasures(ROOT_DIR_REF, B, 75.0);
171     verifyRatingAndReviewedMeasures(PROJECT_REF, B, 75.0);
172   }
173
174   @Test
175   public void compute_rating_and_reviewed__measures_when_more_than_50_percent_hotspots_reviewed() {
176     treeRootHolder.setRoot(ROOT_PROJECT);
177     fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
178       newHotspot(STATUS_TO_REVIEW, null),
179       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
180       // Should not be taken into account
181       newIssue());
182     fillComponentIssuesVisitorRule.setIssues(FILE_2_REF,
183       newHotspot(STATUS_TO_REVIEW, null),
184       newHotspot(STATUS_TO_REVIEW, null),
185       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
186       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
187       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
188       newIssue());
189
190     underTest.visit(ROOT_PROJECT);
191
192     verifyRatingAndReviewedMeasures(FILE_1_REF, C, 50.0);
193     verifyRatingAndReviewedMeasures(FILE_2_REF, C, 60.0);
194     verifyRatingAndReviewedMeasures(DIRECTORY_REF, C, 57.1);
195     verifyRatingAndReviewedMeasures(ROOT_DIR_REF, C, 57.1);
196     verifyRatingAndReviewedMeasures(PROJECT_REF, C, 57.1);
197   }
198
199   @Test
200   public void compute_rating_and_reviewed__measures_when_more_30_than_percent_hotspots_reviewed() {
201     treeRootHolder.setRoot(ROOT_PROJECT);
202     fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
203       newHotspot(STATUS_TO_REVIEW, null),
204       newHotspot(STATUS_TO_REVIEW, null),
205       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
206       // Should not be taken into account
207       newIssue());
208     fillComponentIssuesVisitorRule.setIssues(FILE_2_REF,
209       newHotspot(STATUS_TO_REVIEW, null),
210       newHotspot(STATUS_TO_REVIEW, null),
211       newHotspot(STATUS_TO_REVIEW, null),
212       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
213       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
214       newIssue());
215
216     underTest.visit(ROOT_PROJECT);
217
218     verifyRatingAndReviewedMeasures(FILE_1_REF, D, 33.3);
219     verifyRatingAndReviewedMeasures(FILE_2_REF, D, 40.0);
220     verifyRatingAndReviewedMeasures(DIRECTORY_REF, D, 37.5);
221     verifyRatingAndReviewedMeasures(ROOT_DIR_REF, D, 37.5);
222     verifyRatingAndReviewedMeasures(PROJECT_REF, D, 37.5);
223   }
224
225   @Test
226   public void compute_rating_and_reviewed__measures_when_less_than_30_percent_hotspots_reviewed() {
227     treeRootHolder.setRoot(ROOT_PROJECT);
228     fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
229       newHotspot(STATUS_TO_REVIEW, null),
230       newHotspot(STATUS_TO_REVIEW, null),
231       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
232       // Should not be taken into account
233       newIssue());
234     fillComponentIssuesVisitorRule.setIssues(FILE_2_REF,
235       newHotspot(STATUS_TO_REVIEW, null),
236       newHotspot(STATUS_TO_REVIEW, null),
237       newHotspot(STATUS_TO_REVIEW, null),
238       newIssue());
239
240     underTest.visit(ROOT_PROJECT);
241
242     verifyRatingAndReviewedMeasures(FILE_1_REF, D, 33.3);
243     verifyRatingAndReviewedMeasures(FILE_2_REF, E, 0.0);
244     verifyRatingAndReviewedMeasures(DIRECTORY_REF, E, 16.7);
245     verifyRatingAndReviewedMeasures(ROOT_DIR_REF, E, 16.7);
246     verifyRatingAndReviewedMeasures(PROJECT_REF, E, 16.7);
247   }
248
249   @Test
250   public void compute_A_rating_and_no_reviewed_when_no_hotspot() {
251     treeRootHolder.setRoot(ROOT_PROJECT);
252
253     underTest.visit(ROOT_PROJECT);
254
255     verifyRatingAndReviewedMeasures(PROJECT_REF, A, null);
256   }
257
258   @Test
259   public void compute_status_related_measures() {
260     treeRootHolder.setRoot(ROOT_PROJECT);
261     fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
262       newHotspot(STATUS_TO_REVIEW, null),
263       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
264       // Should not be taken into account
265       newIssue());
266     fillComponentIssuesVisitorRule.setIssues(FILE_2_REF,
267       newHotspot(STATUS_TO_REVIEW, null),
268       newHotspot(STATUS_TO_REVIEW, null),
269       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
270       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
271       newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
272       newIssue());
273
274     underTest.visit(ROOT_PROJECT);
275
276     verifyHotspotStatusMeasures(FILE_1_REF, 1, 1);
277     verifyHotspotStatusMeasures(FILE_2_REF, 3, 2);
278     verifyHotspotStatusMeasures(DIRECTORY_REF, 4, 3);
279     verifyHotspotStatusMeasures(ROOT_DIR_REF, 4, 3);
280     verifyHotspotStatusMeasures(PROJECT_REF, 4, 3);
281   }
282
283   @Test
284   public void compute_0_status_related_measures_when_no_hotspot() {
285     treeRootHolder.setRoot(ROOT_PROJECT);
286
287     underTest.visit(ROOT_PROJECT);
288
289     verifyHotspotStatusMeasures(PROJECT_REF, 0, 0);
290   }
291
292   private void verifyRatingAndReviewedMeasures(int componentRef, Rating expectedReviewRating, @Nullable Double expectedHotspotsReviewed) {
293     verifySecurityReviewRating(componentRef, expectedReviewRating);
294     if (expectedHotspotsReviewed != null) {
295       verifySecurityHotspotsReviewed(componentRef, expectedHotspotsReviewed);
296     } else {
297       assertThat(measureRepository.getAddedRawMeasure(componentRef, SECURITY_HOTSPOTS_REVIEWED_KEY)).isEmpty();
298     }
299   }
300
301   private void verifySecurityReviewRating(int componentRef, Rating rating) {
302     Measure measure = measureRepository.getAddedRawMeasure(componentRef, SECURITY_REVIEW_RATING_KEY).get();
303     assertThat(measure.getIntValue()).isEqualTo(rating.getIndex());
304     assertThat(measure.getData()).isEqualTo(rating.name());
305   }
306
307   private void verifySecurityHotspotsReviewed(int componentRef, double percent) {
308     assertThat(measureRepository.getAddedRawMeasure(componentRef, SECURITY_HOTSPOTS_REVIEWED_KEY).get().getDoubleValue()).isEqualTo(percent);
309   }
310
311   private void verifyHotspotStatusMeasures(int componentRef, @Nullable Integer hotspotsReviewed, @Nullable Integer hotspotsToReview) {
312     if (hotspotsReviewed == null){
313       assertThat(measureRepository.getAddedRawMeasure(componentRef, SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY)).isEmpty();
314     } else {
315       assertThat(measureRepository.getAddedRawMeasure(componentRef, SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY).get().getIntValue()).isEqualTo(hotspotsReviewed);
316     }
317     if (hotspotsReviewed == null){
318       assertThat(measureRepository.getAddedRawMeasure(componentRef, SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY)).isEmpty();
319     } else {
320       assertThat(measureRepository.getAddedRawMeasure(componentRef, SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY).get().getIntValue()).isEqualTo(hotspotsToReview);
321     }
322   }
323
324   private static DefaultIssue newHotspot(String status, @Nullable String resolution) {
325     return new DefaultIssue()
326       .setKey(Uuids.create())
327       .setSeverity(MINOR)
328       .setStatus(status)
329       .setResolution(resolution)
330       .setType(RuleType.SECURITY_HOTSPOT);
331   }
332
333   private static DefaultIssue newIssue() {
334     return new DefaultIssue()
335       .setKey(Uuids.create())
336       .setSeverity(MAJOR)
337       .setType(RuleType.BUG);
338   }
339
340 }