]> source.dussan.org Git - sonarqube.git/blob
1c67608f3deeb059b5f188d48e013ea3313a671c
[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.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;
43
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;
71
72 public class NewReliabilityAndSecurityRatingMeasuresVisitorTest {
73
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);
77
78   static final String LANGUAGE_KEY_1 = "lKey1";
79
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;
85
86   static final Component ROOT_PROJECT = builder(Component.Type.PROJECT, PROJECT_REF).setKey("project")
87     .addChildren(
88       builder(DIRECTORY, ROOT_DIR_REF).setKey("dir")
89         .addChildren(
90           builder(DIRECTORY, DIRECTORY_REF).setKey("directory")
91             .addChildren(
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())
94             .build())
95         .build())
96     .build();
97
98   @Rule
99   public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
100
101   @Rule
102   public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
103     .add(NEW_SECURITY_RATING)
104     .add(NEW_RELIABILITY_RATING);
105
106   @Rule
107   public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
108
109   @Rule
110   public ComponentIssuesRepositoryRule componentIssuesRepositoryRule = new ComponentIssuesRepositoryRule(treeRootHolder);
111   @Rule
112   public FillComponentIssuesVisitorRule fillComponentIssuesVisitorRule = new FillComponentIssuesVisitorRule(componentIssuesRepositoryRule, treeRootHolder);
113
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)));
117
118   @Before
119   public void before() {
120     when(newIssueClassifier.isEnabled()).thenReturn(true);
121   }
122
123   @Test
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);
127
128     underTest.visit(root);
129
130     verifyAddedRawMeasureOnLeakPeriod(1, NEW_SECURITY_RATING_KEY, A);
131     verifyAddedRawMeasureOnLeakPeriod(1, NEW_RELIABILITY_RATING_KEY, A);
132   }
133
134   @Test
135   public void no_measure_if_there_is_no_period() {
136     when(newIssueClassifier.isEnabled()).thenReturn(false);
137     treeRootHolder.setRoot(builder(PROJECT, 1).build());
138
139     underTest.visit(treeRootHolder.getRoot());
140
141     assertThat(measureRepository.getAddedRawMeasures(1).values()).isEmpty();
142   }
143
144   @Test
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));
158
159     underTest.visit(ROOT_PROJECT);
160
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);
166   }
167
168   @Test
169   public void compute_new_security_rating_to_A_when_no_issue() {
170     treeRootHolder.setRoot(ROOT_PROJECT);
171     fillComponentIssuesVisitorRule.setIssues(FILE_1_REF);
172
173     underTest.visit(ROOT_PROJECT);
174
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);
180   }
181
182   @Test
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));
186
187     underTest.visit(ROOT_PROJECT);
188
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);
194   }
195
196   @Test
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));
211
212     underTest.visit(ROOT_PROJECT);
213
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);
219   }
220
221   @Test
222   public void compute_new_reliability_rating_to_A_when_no_issue() {
223     treeRootHolder.setRoot(ROOT_PROJECT);
224     fillComponentIssuesVisitorRule.setIssues(FILE_1_REF);
225
226     underTest.visit(ROOT_PROJECT);
227
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);
233   }
234
235   @Test
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));
239
240     underTest.visit(ROOT_PROJECT);
241
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);
247   }
248
249   @Test
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));
257
258     underTest.visit(ROOT_PROJECT);
259
260     verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_RELIABILITY_RATING_KEY, E);
261     verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, E);
262   }
263
264   @Test
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));
272
273     underTest.visit(ROOT_PROJECT);
274
275     verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_RELIABILITY_RATING_KEY, D);
276     verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, D);
277   }
278
279   @Test
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));
287
288     underTest.visit(ROOT_PROJECT);
289
290     verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_RELIABILITY_RATING_KEY, C);
291     verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, C);
292   }
293
294   @Test
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));
302
303     underTest.visit(ROOT_PROJECT);
304
305     verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_RELIABILITY_RATING_KEY, B);
306     verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, B);
307   }
308
309   @Test
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));
317
318     underTest.visit(ROOT_PROJECT);
319
320     verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_RELIABILITY_RATING_KEY, A);
321     verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, A);
322   }
323
324   private void verifyAddedRawMeasureOnLeakPeriod(int componentRef, String metricKey, Rating rating) {
325     MeasureAssert.assertThat(measureRepository.getAddedRawMeasure(componentRef, metricKey)).hasValue(rating.getIndex());
326   }
327
328   private DefaultIssue newBugIssue(long effort, String severity) {
329     return createIssue(effort, severity, BUG, true);
330   }
331
332   private DefaultIssue oldBugIssue(long effort, String severity) {
333     return createIssue(effort, severity, BUG, false);
334   }
335
336   private DefaultIssue newVulnerabilityIssue(long effort, String severity) {
337     return createIssue(effort, severity, VULNERABILITY, true);
338   }
339
340   private DefaultIssue oldVulnerabilityIssue(long effort, String severity) {
341     return createIssue(effort, severity, VULNERABILITY, false);
342   }
343
344   private DefaultIssue newCodeSmellIssue(long effort, String severity) {
345     return createIssue(effort, severity, CODE_SMELL, true);
346   }
347
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);
352     return issue;
353   }
354
355   private static DefaultIssue createIssue(String severity, RuleType type) {
356     return new DefaultIssue()
357       .setKey(UuidFactoryFast.getInstance().create())
358       .setSeverity(severity)
359       .setType(type)
360       .setCreationDate(DEFAULT_ISSUE_CREATION_DATE);
361   }
362
363 }