]> source.dussan.org Git - sonarqube.git/blob
3068fad340bab8706f441b3ced46b55c280b40a4
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2016 SonarSource SA
4  * mailto:contact 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.server.computation.qualitymodel;
21
22 import java.util.Arrays;
23 import org.junit.Before;
24 import org.junit.Rule;
25 import org.junit.Test;
26 import org.sonar.api.rules.RuleType;
27 import org.sonar.api.utils.Duration;
28 import org.sonar.core.issue.DefaultIssue;
29 import org.sonar.core.util.Uuids;
30 import org.sonar.server.computation.batch.TreeRootHolderRule;
31 import org.sonar.server.computation.component.Component;
32 import org.sonar.server.computation.component.FileAttributes;
33 import org.sonar.server.computation.component.ReportComponent;
34 import org.sonar.server.computation.component.VisitorsCrawler;
35 import org.sonar.server.computation.issue.ComponentIssuesRepositoryRule;
36 import org.sonar.server.computation.issue.FillComponentIssuesVisitorRule;
37 import org.sonar.server.computation.measure.Measure;
38 import org.sonar.server.computation.measure.MeasureRepositoryRule;
39 import org.sonar.server.computation.metric.MetricRepositoryRule;
40 import org.sonar.server.computation.qualitymodel.RatingGrid.Rating;
41
42 import static org.assertj.core.api.Assertions.assertThat;
43 import static org.mockito.Mockito.mock;
44 import static org.mockito.Mockito.when;
45 import static org.sonar.api.issue.Issue.RESOLUTION_FIXED;
46 import static org.sonar.api.measures.CoreMetrics.DEVELOPMENT_COST;
47 import static org.sonar.api.measures.CoreMetrics.DEVELOPMENT_COST_KEY;
48 import static org.sonar.api.measures.CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A;
49 import static org.sonar.api.measures.CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY;
50 import static org.sonar.api.measures.CoreMetrics.EFFORT_TO_REACH_RELIABILITY_RATING_A;
51 import static org.sonar.api.measures.CoreMetrics.EFFORT_TO_REACH_RELIABILITY_RATING_A_KEY;
52 import static org.sonar.api.measures.CoreMetrics.EFFORT_TO_REACH_SECURITY_RATING_A;
53 import static org.sonar.api.measures.CoreMetrics.EFFORT_TO_REACH_SECURITY_RATING_A_KEY;
54 import static org.sonar.api.measures.CoreMetrics.NCLOC;
55 import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
56 import static org.sonar.api.measures.CoreMetrics.RELIABILITY_RATING;
57 import static org.sonar.api.measures.CoreMetrics.RELIABILITY_RATING_KEY;
58 import static org.sonar.api.measures.CoreMetrics.SECURITY_RATING;
59 import static org.sonar.api.measures.CoreMetrics.SECURITY_RATING_KEY;
60 import static org.sonar.api.measures.CoreMetrics.SQALE_DEBT_RATIO;
61 import static org.sonar.api.measures.CoreMetrics.SQALE_DEBT_RATIO_KEY;
62 import static org.sonar.api.measures.CoreMetrics.SQALE_RATING;
63 import static org.sonar.api.measures.CoreMetrics.SQALE_RATING_KEY;
64 import static org.sonar.api.measures.CoreMetrics.TECHNICAL_DEBT;
65 import static org.sonar.api.measures.CoreMetrics.TECHNICAL_DEBT_KEY;
66 import static org.sonar.api.rule.Severity.BLOCKER;
67 import static org.sonar.api.rule.Severity.CRITICAL;
68 import static org.sonar.api.rule.Severity.INFO;
69 import static org.sonar.api.rule.Severity.MAJOR;
70 import static org.sonar.api.rule.Severity.MINOR;
71 import static org.sonar.api.rules.RuleType.BUG;
72 import static org.sonar.api.rules.RuleType.CODE_SMELL;
73 import static org.sonar.api.rules.RuleType.VULNERABILITY;
74 import static org.sonar.server.computation.component.Component.Type.DIRECTORY;
75 import static org.sonar.server.computation.component.Component.Type.FILE;
76 import static org.sonar.server.computation.component.Component.Type.MODULE;
77 import static org.sonar.server.computation.component.Component.Type.PROJECT;
78 import static org.sonar.server.computation.component.ReportComponent.builder;
79 import static org.sonar.server.computation.measure.Measure.newMeasureBuilder;
80 import static org.sonar.server.computation.measure.MeasureRepoEntry.entryOf;
81 import static org.sonar.server.computation.measure.MeasureRepoEntry.toEntries;
82 import static org.sonar.server.computation.qualitymodel.RatingGrid.Rating.A;
83 import static org.sonar.server.computation.qualitymodel.RatingGrid.Rating.B;
84 import static org.sonar.server.computation.qualitymodel.RatingGrid.Rating.C;
85 import static org.sonar.server.computation.qualitymodel.RatingGrid.Rating.D;
86 import static org.sonar.server.computation.qualitymodel.RatingGrid.Rating.E;
87
88 public class QualityModelMeasuresVisitorForReportTest {
89
90   static final String LANGUAGE_KEY_1 = "lKey1";
91   static final String LANGUAGE_KEY_2 = "lKey2";
92
93   static final double[] RATING_GRID = new double[] {0.1, 0.2, 0.5, 1};
94
95   static final long DEV_COST_LANGUAGE_1 = 30;
96   static final long DEV_COST_LANGUAGE_2 = 42;
97
98   static final int PROJECT_REF = 1;
99   static final int MODULE_REF = 12;
100   static final int DIRECTORY_REF = 123;
101   static final int FILE_1_REF = 1231;
102   static final int FILE_2_REF = 1232;
103
104   static final Component ROOT_PROJECT = builder(Component.Type.PROJECT, PROJECT_REF).setKey("project")
105     .addChildren(
106       builder(MODULE, MODULE_REF).setKey("module")
107         .addChildren(
108           builder(DIRECTORY, DIRECTORY_REF).setKey("directory")
109             .addChildren(
110               builder(FILE, FILE_1_REF).setFileAttributes(new FileAttributes(false, LANGUAGE_KEY_1)).setKey("file1").build(),
111               builder(FILE, FILE_2_REF).setFileAttributes(new FileAttributes(false, LANGUAGE_KEY_1)).setKey("file2").build()
112             ).build()
113         ).build()
114     ).build();
115
116   @Rule
117   public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
118
119   @Rule
120   public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
121     .add(NCLOC)
122     .add(DEVELOPMENT_COST)
123     .add(TECHNICAL_DEBT)
124     .add(SQALE_DEBT_RATIO)
125     .add(SQALE_RATING)
126     .add(EFFORT_TO_REACH_MAINTAINABILITY_RATING_A)
127     .add(RELIABILITY_RATING)
128     .add(EFFORT_TO_REACH_RELIABILITY_RATING_A)
129     .add(SECURITY_RATING)
130     .add(EFFORT_TO_REACH_SECURITY_RATING_A);
131
132   @Rule
133   public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
134
135   @Rule
136   public ComponentIssuesRepositoryRule componentIssuesRepositoryRule = new ComponentIssuesRepositoryRule(treeRootHolder);
137
138   @Rule
139   public FillComponentIssuesVisitorRule fillComponentIssuesVisitorRule = new FillComponentIssuesVisitorRule(componentIssuesRepositoryRule, treeRootHolder);
140
141   private RatingSettings ratingSettings = mock(RatingSettings.class);
142
143   private VisitorsCrawler underTest;
144
145   @Before
146   public void setUp() {
147     // assumes rating configuration is consistent
148     when(ratingSettings.getRatingGrid()).thenReturn(new RatingGrid(RATING_GRID));
149     when(ratingSettings.getDevCost(LANGUAGE_KEY_1)).thenReturn(DEV_COST_LANGUAGE_1);
150     when(ratingSettings.getDevCost(LANGUAGE_KEY_2)).thenReturn(DEV_COST_LANGUAGE_2);
151
152     underTest = new VisitorsCrawler(Arrays.asList(
153       fillComponentIssuesVisitorRule,
154       new QualityModelMeasuresVisitor(metricRepository, measureRepository, ratingSettings, componentIssuesRepositoryRule)));
155   }
156
157   @Test
158   public void measures_created_for_project_are_all_zero_when_they_have_no_FILE_child() {
159     ReportComponent root = builder(PROJECT, 1).build();
160     treeRootHolder.setRoot(root);
161
162     underTest.visit(root);
163
164     assertThat(toEntries(measureRepository.getRawMeasures(root)))
165       .containsOnly(
166         entryOf(DEVELOPMENT_COST_KEY, newMeasureBuilder().create("0")),
167         entryOf(SQALE_DEBT_RATIO_KEY, newMeasureBuilder().create(0d, 1)),
168         entryOf(SQALE_RATING_KEY, createMaintainabilityRatingMeasure(A)),
169         entryOf(EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY, newMeasureBuilder().create(0L)),
170         entryOf(RELIABILITY_RATING_KEY, createMaintainabilityRatingMeasure(A)),
171         entryOf(EFFORT_TO_REACH_RELIABILITY_RATING_A_KEY, newMeasureBuilder().create(0L)),
172         entryOf(SECURITY_RATING_KEY, createMaintainabilityRatingMeasure(A)),
173         entryOf(EFFORT_TO_REACH_SECURITY_RATING_A_KEY, newMeasureBuilder().create(0L))
174       );
175   }
176
177   @Test
178   public void compute_development_cost() {
179     ReportComponent root = builder(PROJECT, 1)
180       .addChildren(
181         builder(MODULE, 11)
182           .addChildren(
183             builder(DIRECTORY, 111)
184               .addChildren(
185                 createFileComponent(LANGUAGE_KEY_1, 1111),
186                 createFileComponent(LANGUAGE_KEY_2, 1112),
187                 builder(FILE, 1113).setFileAttributes(new FileAttributes(true, LANGUAGE_KEY_1)).build())
188               .build(),
189             builder(DIRECTORY, 112)
190               .addChildren(
191                 createFileComponent(LANGUAGE_KEY_2, 1121))
192               .build())
193           .build(),
194         builder(MODULE, 12)
195           .addChildren(
196             builder(DIRECTORY, 121)
197               .addChildren(
198                 createFileComponent(LANGUAGE_KEY_1, 1211))
199               .build(),
200             builder(DIRECTORY, 122).build())
201           .build(),
202         builder(MODULE, 13).build())
203       .build();
204
205     treeRootHolder.setRoot(root);
206
207     int ncloc1111 = 10;
208     addRawMeasure(NCLOC_KEY, 1111, ncloc1111);
209
210     int ncloc1112 = 10;
211     addRawMeasure(NCLOC_KEY, 1112, ncloc1112);
212
213     int nclocValue1121 = 30;
214     addRawMeasure(NCLOC_KEY, 1121, nclocValue1121);
215
216     int ncloc1211 = 20;
217     addRawMeasure(NCLOC_KEY, 1211, ncloc1211);
218
219     underTest.visit(root);
220
221     // verify measures on files
222     verifyAddedRawMeasure(1111, DEVELOPMENT_COST_KEY, Long.toString(ncloc1111 * DEV_COST_LANGUAGE_1));
223     verifyAddedRawMeasure(1112, DEVELOPMENT_COST_KEY, Long.toString(ncloc1111 * DEV_COST_LANGUAGE_2));
224     verifyNoAddedRawMeasure(1113);
225     verifyAddedRawMeasure(1121, DEVELOPMENT_COST_KEY, Long.toString(nclocValue1121 * DEV_COST_LANGUAGE_2));
226     verifyAddedRawMeasure(1211, DEVELOPMENT_COST_KEY, Long.toString(ncloc1211 * DEV_COST_LANGUAGE_1));
227
228     // directory has no children => no file => 0 everywhere and A rating
229     verifyAddedRawMeasure(122, DEVELOPMENT_COST_KEY, "0");
230
231     // directory has children => dev cost is aggregated
232     verifyAddedRawMeasure(111, DEVELOPMENT_COST_KEY, Long.toString(
233       ncloc1111 * DEV_COST_LANGUAGE_1 +
234         ncloc1112 * DEV_COST_LANGUAGE_2
235       ));
236     verifyAddedRawMeasure(112, DEVELOPMENT_COST_KEY, Long.toString(nclocValue1121 * DEV_COST_LANGUAGE_2));
237     verifyAddedRawMeasure(121, DEVELOPMENT_COST_KEY, Long.toString(ncloc1211 * DEV_COST_LANGUAGE_1));
238
239     // just for fun, we didn't define any debt on module => they must all have rating A
240     verifyAddedRawMeasure(11, DEVELOPMENT_COST_KEY, Long.toString(
241       ncloc1111 * DEV_COST_LANGUAGE_1 +
242         ncloc1112 * DEV_COST_LANGUAGE_2 +
243         nclocValue1121 * DEV_COST_LANGUAGE_2
244       ));
245     verifyAddedRawMeasure(12, DEVELOPMENT_COST_KEY, Long.toString(ncloc1211 * DEV_COST_LANGUAGE_1));
246     verifyAddedRawMeasure(13, DEVELOPMENT_COST_KEY, "0");
247     verifyAddedRawMeasure(1, DEVELOPMENT_COST_KEY, Long.toString(
248       ncloc1111 * DEV_COST_LANGUAGE_1 +
249         ncloc1112 * DEV_COST_LANGUAGE_2 +
250         nclocValue1121 * DEV_COST_LANGUAGE_2 +
251         ncloc1211 * DEV_COST_LANGUAGE_1
252       ));
253   }
254
255   @Test
256   public void compute_maintainability_debt_ratio_measure() throws Exception {
257     treeRootHolder.setRoot(ROOT_PROJECT);
258
259     int file1Ncloc = 10;
260     addRawMeasure(NCLOC_KEY, FILE_1_REF, file1Ncloc);
261     long file1MaintainabilityCost = 100L;
262     addRawMeasure(TECHNICAL_DEBT_KEY, FILE_1_REF, file1MaintainabilityCost);
263
264     int file2Ncloc = 5;
265     addRawMeasure(NCLOC_KEY, FILE_2_REF, file2Ncloc);
266     long file2MaintainabilityCost = 1L;
267     addRawMeasure(TECHNICAL_DEBT_KEY, FILE_2_REF, file2MaintainabilityCost);
268
269     long directoryMaintainabilityCost = 100L;
270     addRawMeasure(TECHNICAL_DEBT_KEY, DIRECTORY_REF, directoryMaintainabilityCost);
271
272     long moduleMaintainabilityCost = 100L;
273     addRawMeasure(TECHNICAL_DEBT_KEY, MODULE_REF, moduleMaintainabilityCost);
274
275     long projectMaintainabilityCost = 1000L;
276     addRawMeasure(TECHNICAL_DEBT_KEY, PROJECT_REF, projectMaintainabilityCost);
277
278     underTest.visit(ROOT_PROJECT);
279
280     verifyAddedRawMeasure(FILE_1_REF, SQALE_DEBT_RATIO_KEY, file1MaintainabilityCost * 1d / (file1Ncloc * DEV_COST_LANGUAGE_1) * 100);
281     verifyAddedRawMeasure(FILE_2_REF, SQALE_DEBT_RATIO_KEY, file2MaintainabilityCost * 1d / (file2Ncloc * DEV_COST_LANGUAGE_1) * 100);
282     verifyAddedRawMeasure(DIRECTORY_REF, SQALE_DEBT_RATIO_KEY, directoryMaintainabilityCost * 1d / ((file1Ncloc + file2Ncloc) * DEV_COST_LANGUAGE_1) * 100);
283     verifyAddedRawMeasure(MODULE_REF, SQALE_DEBT_RATIO_KEY, moduleMaintainabilityCost * 1d / ((file1Ncloc + file2Ncloc) * DEV_COST_LANGUAGE_1) * 100);
284     verifyAddedRawMeasure(PROJECT_REF, SQALE_DEBT_RATIO_KEY, projectMaintainabilityCost * 1d / ((file1Ncloc + file2Ncloc) * DEV_COST_LANGUAGE_1) * 100);
285   }
286
287   @Test
288   public void compute_maintainability_rating_measure() throws Exception {
289     treeRootHolder.setRoot(ROOT_PROJECT);
290
291     addRawMeasure(NCLOC_KEY, FILE_1_REF, 10);
292     addRawMeasure(TECHNICAL_DEBT_KEY, FILE_1_REF, 100L);
293
294     addRawMeasure(NCLOC_KEY, FILE_2_REF, 5);
295     addRawMeasure(TECHNICAL_DEBT_KEY, FILE_2_REF, 1L);
296
297     addRawMeasure(TECHNICAL_DEBT_KEY, DIRECTORY_REF, 100L);
298     addRawMeasure(TECHNICAL_DEBT_KEY, MODULE_REF, 100L);
299     addRawMeasure(TECHNICAL_DEBT_KEY, PROJECT_REF, 1000L);
300
301     underTest.visit(ROOT_PROJECT);
302
303     verifyAddedRawMeasure(FILE_1_REF, SQALE_RATING_KEY, C);
304     verifyAddedRawMeasure(FILE_2_REF, SQALE_RATING_KEY, A);
305     verifyAddedRawMeasure(DIRECTORY_REF, SQALE_RATING_KEY, C);
306     verifyAddedRawMeasure(MODULE_REF, SQALE_RATING_KEY, C);
307     verifyAddedRawMeasure(PROJECT_REF, SQALE_RATING_KEY, E);
308   }
309
310   @Test
311   public void compute_effort_to_maintainability_rating_A_measure() throws Exception {
312     treeRootHolder.setRoot(ROOT_PROJECT);
313
314     int file1Ncloc = 10;
315     long file1Effort = 100L;
316     addRawMeasure(NCLOC_KEY, FILE_1_REF, file1Ncloc);
317     addRawMeasure(TECHNICAL_DEBT_KEY, FILE_1_REF, file1Effort);
318
319     int file2Ncloc = 5;
320     long file2Effort = 20L;
321     addRawMeasure(NCLOC_KEY, FILE_2_REF, file2Ncloc);
322     addRawMeasure(TECHNICAL_DEBT_KEY, FILE_2_REF, file2Effort);
323
324     long dirEffort = 120L;
325     addRawMeasure(TECHNICAL_DEBT_KEY, DIRECTORY_REF, dirEffort);
326
327     long moduleEffort = 120L;
328     addRawMeasure(TECHNICAL_DEBT_KEY, MODULE_REF, moduleEffort);
329
330     long projectEffort = 150L;
331     addRawMeasure(TECHNICAL_DEBT_KEY, PROJECT_REF, projectEffort);
332
333     underTest.visit(ROOT_PROJECT);
334
335     verifyAddedRawMeasure(FILE_1_REF, EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY,
336       (long) (file1Effort - RATING_GRID[0] * file1Ncloc * DEV_COST_LANGUAGE_1));
337     verifyAddedRawMeasure(FILE_2_REF, EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY,
338       (long) (file2Effort - RATING_GRID[0] * file2Ncloc * DEV_COST_LANGUAGE_1));
339     verifyAddedRawMeasure(DIRECTORY_REF, EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY,
340       (long) (dirEffort - RATING_GRID[0] * (file1Ncloc + file2Ncloc) * DEV_COST_LANGUAGE_1));
341     verifyAddedRawMeasure(MODULE_REF, EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY,
342       (long) (moduleEffort - RATING_GRID[0] * (file1Ncloc + file2Ncloc) * DEV_COST_LANGUAGE_1));
343     verifyAddedRawMeasure(PROJECT_REF, EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY,
344       (long) (projectEffort - RATING_GRID[0] * (file1Ncloc + file2Ncloc) * DEV_COST_LANGUAGE_1));
345   }
346
347   @Test
348   public void compute_0_effort_to_maintainability_rating_A_when_effort_is_lower_than_dev_cost() throws Exception {
349     treeRootHolder.setRoot(ROOT_PROJECT);
350
351     addRawMeasure(NCLOC_KEY, FILE_1_REF, 10);
352     addRawMeasure(TECHNICAL_DEBT_KEY, FILE_1_REF, 2L);
353
354     underTest.visit(ROOT_PROJECT);
355
356     verifyAddedRawMeasure(FILE_1_REF, EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY, 0L);
357   }
358
359   @Test
360   public void effort_to_maintainability_rating_A_is_same_as_effort_when_no_dev_cost() throws Exception {
361     treeRootHolder.setRoot(ROOT_PROJECT);
362
363     addRawMeasure(TECHNICAL_DEBT_KEY, FILE_1_REF, 100L);
364
365     underTest.visit(ROOT_PROJECT);
366
367     verifyAddedRawMeasure(FILE_1_REF, EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY, 100);
368   }
369
370   @Test
371   public void compute_reliability_rating() throws Exception {
372     treeRootHolder.setRoot(ROOT_PROJECT);
373     fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, BLOCKER), newBugIssue(1L, MAJOR),
374       // Should not be taken into account
375       newVulnerabilityIssue(5L, MINOR)
376       );
377     fillComponentIssuesVisitorRule.setIssues(FILE_2_REF, newBugIssue(2L, CRITICAL), newBugIssue(3L, MINOR),
378       // Should not be taken into account
379       newBugIssue(10L, BLOCKER).setResolution(RESOLUTION_FIXED)
380       );
381
382     underTest.visit(ROOT_PROJECT);
383
384     verifyAddedRawMeasure(FILE_1_REF, RELIABILITY_RATING_KEY, E);
385     verifyAddedRawMeasure(FILE_2_REF, RELIABILITY_RATING_KEY, D);
386     verifyAddedRawMeasure(DIRECTORY_REF, RELIABILITY_RATING_KEY, E);
387     verifyAddedRawMeasure(MODULE_REF, RELIABILITY_RATING_KEY, E);
388     verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, E);
389   }
390
391   @Test
392   public void compute_security_rating() throws Exception {
393     treeRootHolder.setRoot(ROOT_PROJECT);
394     fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newVulnerabilityIssue(10L, BLOCKER), newVulnerabilityIssue(1L, MAJOR),
395       // Should not be taken into account
396       newBugIssue(1L, MAJOR));
397     fillComponentIssuesVisitorRule.setIssues(FILE_2_REF, newVulnerabilityIssue(2L, CRITICAL), newVulnerabilityIssue(3L, MINOR),
398       // Should not be taken into account
399       newVulnerabilityIssue(10L, BLOCKER).setResolution(RESOLUTION_FIXED)
400       );
401
402     underTest.visit(ROOT_PROJECT);
403
404     verifyAddedRawMeasure(FILE_1_REF, SECURITY_RATING_KEY, E);
405     verifyAddedRawMeasure(FILE_2_REF, SECURITY_RATING_KEY, D);
406     verifyAddedRawMeasure(DIRECTORY_REF, SECURITY_RATING_KEY, E);
407     verifyAddedRawMeasure(MODULE_REF, SECURITY_RATING_KEY, E);
408     verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, E);
409   }
410
411   @Test
412   public void compute_E_reliability_and_security_rating_on_blocker_issue() throws Exception {
413     treeRootHolder.setRoot(ROOT_PROJECT);
414     fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, BLOCKER), newVulnerabilityIssue(1L, BLOCKER),
415       // Should not be taken into account
416       newBugIssue(1L, MAJOR));
417
418     underTest.visit(ROOT_PROJECT);
419
420     verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, E);
421     verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, E);
422   }
423
424   @Test
425   public void compute_D_reliability_and_security_rating_on_critical_issue() throws Exception {
426     treeRootHolder.setRoot(ROOT_PROJECT);
427     fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, CRITICAL), newVulnerabilityIssue(15L, CRITICAL),
428       // Should not be taken into account
429       newCodeSmellIssue(1L, MAJOR));
430
431     underTest.visit(ROOT_PROJECT);
432
433     verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, D);
434     verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, D);
435   }
436
437   @Test
438   public void compute_C_reliability_and_security_rating_on_major_issue() throws Exception {
439     treeRootHolder.setRoot(ROOT_PROJECT);
440     fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, MAJOR), newVulnerabilityIssue(15L, MAJOR),
441       // Should not be taken into account
442       newCodeSmellIssue(1L, MAJOR));
443
444     underTest.visit(ROOT_PROJECT);
445
446     verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, C);
447     verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, C);
448   }
449
450   @Test
451   public void compute_B_reliability_and_security_rating_on_minor_issue() throws Exception {
452     treeRootHolder.setRoot(ROOT_PROJECT);
453     fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, MINOR), newVulnerabilityIssue(15L, MINOR),
454       // Should not be taken into account
455       newCodeSmellIssue(1L, MAJOR));
456
457     underTest.visit(ROOT_PROJECT);
458
459     verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, B);
460     verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, B);
461   }
462
463   @Test
464   public void compute_A_reliability_and_security_rating_on_info_issue() throws Exception {
465     treeRootHolder.setRoot(ROOT_PROJECT);
466     fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, INFO), newVulnerabilityIssue(15L, INFO),
467       // Should not be taken into account
468       newCodeSmellIssue(1L, MAJOR));
469
470     underTest.visit(ROOT_PROJECT);
471
472     verifyAddedRawMeasure(PROJECT_REF, RELIABILITY_RATING_KEY, A);
473     verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, A);
474   }
475
476   @Test
477   public void compute_effort_to_reliability_rating_A_measure() throws Exception {
478     treeRootHolder.setRoot(ROOT_PROJECT);
479
480     fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, BLOCKER), newBugIssue(1L, MAJOR),
481       // CODE SMELL should not be taken into account
482       newCodeSmellIssue(4L, MAJOR),
483       // Resolved issue should be ignored
484       newBugIssue(10L, BLOCKER).setResolution(RESOLUTION_FIXED)
485       );
486     fillComponentIssuesVisitorRule.setIssues(FILE_2_REF, newBugIssue(2L, CRITICAL), newBugIssue(3L, MINOR),
487       // INFO issue should not be taken into account
488       newBugIssue(5L, INFO),
489       // Issue without debt
490       newIssue(MAJOR, BUG));
491
492     underTest.visit(ROOT_PROJECT);
493
494     verifyAddedRawMeasure(FILE_1_REF, EFFORT_TO_REACH_RELIABILITY_RATING_A_KEY, 10L + 1L);
495     verifyAddedRawMeasure(FILE_2_REF, EFFORT_TO_REACH_RELIABILITY_RATING_A_KEY, 2L + 3L);
496     verifyAddedRawMeasure(DIRECTORY_REF, EFFORT_TO_REACH_RELIABILITY_RATING_A_KEY, 16L);
497     verifyAddedRawMeasure(MODULE_REF, EFFORT_TO_REACH_RELIABILITY_RATING_A_KEY, 16L);
498     verifyAddedRawMeasure(PROJECT_REF, EFFORT_TO_REACH_RELIABILITY_RATING_A_KEY, 16L);
499   }
500
501   @Test
502   public void compute_effort_to_security_rating_A_measure() throws Exception {
503     treeRootHolder.setRoot(ROOT_PROJECT);
504
505     fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newVulnerabilityIssue(8L, BLOCKER), newVulnerabilityIssue(6L, MAJOR),
506       // CODE SMELL should not be taken into account
507       newCodeSmellIssue(4L, MAJOR),
508       // Resolved issue should be ignored
509       newVulnerabilityIssue(10L, BLOCKER).setResolution(RESOLUTION_FIXED)
510       );
511     fillComponentIssuesVisitorRule.setIssues(FILE_2_REF, newVulnerabilityIssue(2L, CRITICAL), newVulnerabilityIssue(1L, MINOR),
512       // INFO issue should not be taken into account
513       newVulnerabilityIssue(5L, INFO),
514       // Issue without debt
515       newIssue(MAJOR, VULNERABILITY));
516
517     underTest.visit(ROOT_PROJECT);
518
519     verifyAddedRawMeasure(FILE_1_REF, EFFORT_TO_REACH_SECURITY_RATING_A_KEY, 8L + 6L);
520     verifyAddedRawMeasure(FILE_2_REF, EFFORT_TO_REACH_SECURITY_RATING_A_KEY, 2L + 1L);
521     verifyAddedRawMeasure(DIRECTORY_REF, EFFORT_TO_REACH_SECURITY_RATING_A_KEY, 17L);
522     verifyAddedRawMeasure(MODULE_REF, EFFORT_TO_REACH_SECURITY_RATING_A_KEY, 17L);
523     verifyAddedRawMeasure(PROJECT_REF, EFFORT_TO_REACH_SECURITY_RATING_A_KEY, 17L);
524   }
525
526   private void addRawMeasure(String metricKey, int componentRef, long value) {
527     measureRepository.addRawMeasure(componentRef, metricKey, newMeasureBuilder().create(value));
528   }
529
530   private void addRawMeasure(String metricKey, int componentRef, int value) {
531     measureRepository.addRawMeasure(componentRef, metricKey, newMeasureBuilder().create(value));
532   }
533
534   private void verifyAddedRawMeasure(int componentRef, String metricKey, long value) {
535     assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).contains(entryOf(metricKey, newMeasureBuilder().create(value)));
536   }
537
538   private void verifyAddedRawMeasure(int componentRef, String metricKey, double value) {
539     assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).contains(entryOf(metricKey, newMeasureBuilder().create(value, 1)));
540   }
541
542   private void verifyAddedRawMeasure(int componentRef, String metricKey, Rating rating) {
543     assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).contains(entryOf(metricKey, newMeasureBuilder().create(rating.getIndex(), rating.name())));
544   }
545
546   private void verifyAddedRawMeasure(int componentRef, String metricKey, String value) {
547     assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).contains(entryOf(metricKey, newMeasureBuilder().create(value)));
548   }
549
550   private void verifyNoAddedRawMeasure(int componentRef) {
551     assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).isEmpty();
552   }
553
554   private static ReportComponent createFileComponent(String languageKey1, int fileRef) {
555     return builder(FILE, fileRef).setFileAttributes(new FileAttributes(false, languageKey1)).build();
556   }
557
558   private static Measure createMaintainabilityRatingMeasure(Rating rating) {
559     return newMeasureBuilder().create(rating.getIndex(), rating.name());
560   }
561
562   private static DefaultIssue newBugIssue(long effort, String severity) {
563     return newIssue(effort, severity, BUG);
564   }
565
566   private static DefaultIssue newVulnerabilityIssue(long effort, String severity) {
567     return newIssue(effort, severity, VULNERABILITY);
568   }
569
570   private static DefaultIssue newCodeSmellIssue(long effort, String severity) {
571     return newIssue(effort, severity, CODE_SMELL);
572   }
573
574   private static DefaultIssue newIssue(long effort, String severity, RuleType type) {
575     return newIssue(severity, type)
576       .setEffort(Duration.create(effort));
577   }
578
579   private static DefaultIssue newIssue(String severity, RuleType type) {
580     return new DefaultIssue()
581       .setKey(Uuids.create())
582       .setSeverity(severity)
583       .setType(type);
584   }
585
586 }