]> source.dussan.org Git - sonarqube.git/blob
df5064c040240e6615bdced94c71131203ec602e
[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.server.measure.live;
21
22 import java.util.Date;
23 import java.util.List;
24 import java.util.Set;
25 import org.junit.Before;
26 import org.junit.Rule;
27 import org.junit.Test;
28 import org.sonar.api.config.Configuration;
29 import org.sonar.api.config.internal.MapSettings;
30 import org.sonar.api.measures.Metric;
31 import org.sonar.api.rules.RuleType;
32 import org.sonar.db.DbTester;
33 import org.sonar.db.component.BranchDto;
34 import org.sonar.db.component.BranchType;
35 import org.sonar.db.component.ComponentDto;
36 import org.sonar.db.component.ComponentTesting;
37 import org.sonar.db.component.SnapshotDto;
38 import org.sonar.db.issue.IssueDto;
39 import org.sonar.db.measure.LiveMeasureDto;
40 import org.sonar.db.metric.MetricDto;
41 import org.sonar.db.newcodeperiod.NewCodePeriodType;
42 import org.sonar.db.rule.RuleDto;
43
44 import static org.assertj.core.api.Assertions.assertThat;
45 import static org.sonar.api.CoreProperties.RATING_GRID;
46 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_KEY;
47 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_KEY;
48 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY;
49 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY;
50 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_KEY;
51 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_KEY;
52 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY;
53 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY;
54
55 public class LiveMeasureTreeUpdaterImplIT {
56   @Rule
57   public DbTester db = DbTester.create();
58
59   private final Configuration config = new MapSettings().setProperty(RATING_GRID, "0.05,0.1,0.2,0.5").asConfig();
60   private LiveMeasureTreeUpdaterImpl treeUpdater;
61   private ComponentIndexImpl componentIndex;
62   private MeasureMatrix matrix;
63   private MetricDto metricDto;
64   private Metric metric;
65   private ComponentDto project;
66   private BranchDto branch;
67   private ComponentDto dir;
68   private ComponentDto file1;
69   private ComponentDto file2;
70   private SnapshotDto snapshot;
71
72   @Before
73   public void setUp() {
74     // insert project and file structure
75     project = db.components().insertPrivateProject().getMainBranchComponent();
76     branch = db.getDbClient().branchDao().selectByUuid(db.getSession(), project.uuid()).get();
77     dir = db.components().insertComponent(ComponentTesting.newDirectory(project, "src/main/java"));
78     file1 = db.components().insertComponent(ComponentTesting.newFileDto(project, dir));
79     file2 = db.components().insertComponent(ComponentTesting.newFileDto(project, dir));
80
81     // other needed data
82     metricDto = db.measures().insertMetric(m -> m.setValueType(Metric.ValueType.INT.name()));
83     metric = new Metric.Builder(metricDto.getKey(), metricDto.getShortName(), Metric.ValueType.valueOf(metricDto.getValueType())).create();
84     matrix = new MeasureMatrix(List.of(project, dir, file1, file2), List.of(metricDto), List.of());
85     componentIndex = new ComponentIndexImpl(db.getDbClient());
86   }
87
88   @Test
89   public void should_aggregate_values_up_the_hierarchy() {
90     snapshot = db.components().insertSnapshot(project);
91     treeUpdater = new LiveMeasureTreeUpdaterImpl(db.getDbClient(), new AggregateValuesFormula());
92
93     componentIndex.load(db.getSession(), List.of(file1));
94     List<LiveMeasureDto> initialValues = List.of(
95       new LiveMeasureDto().setComponentUuid(file1.uuid()).setValue(1d).setMetricUuid(metricDto.getUuid()),
96       new LiveMeasureDto().setComponentUuid(file2.uuid()).setValue(1d).setMetricUuid(metricDto.getUuid()),
97       new LiveMeasureDto().setComponentUuid(dir.uuid()).setValue(1d).setMetricUuid(metricDto.getUuid()),
98       new LiveMeasureDto().setComponentUuid(project.uuid()).setValue(1d).setMetricUuid(metricDto.getUuid())
99     );
100     matrix = new MeasureMatrix(List.of(project, dir, file1, file2), List.of(metricDto), initialValues);
101     treeUpdater.update(db.getSession(), snapshot, config, componentIndex, branch, matrix);
102
103     assertThat(matrix.getChanged()).extracting(LiveMeasureDto::getComponentUuid).containsOnly(project.uuid(), dir.uuid());
104     assertThat(matrix.getMeasure(project, metric.getKey()).get().getValue()).isEqualTo(4d);
105     assertThat(matrix.getMeasure(dir, metric.getKey()).get().getValue()).isEqualTo(3d);
106     assertThat(matrix.getMeasure(file1, metric.getKey()).get().getValue()).isEqualTo(1d);
107     assertThat(matrix.getMeasure(file2, metric.getKey()).get().getValue()).isEqualTo(1d);
108   }
109
110   @Test
111   public void should_set_values_up_the_hierarchy() {
112     snapshot = db.components().insertSnapshot(project);
113     treeUpdater = new LiveMeasureTreeUpdaterImpl(db.getDbClient(), new SetValuesFormula());
114
115     componentIndex.load(db.getSession(), List.of(file1));
116     treeUpdater.update(db.getSession(), snapshot, config, componentIndex, branch, matrix);
117
118     assertThat(matrix.getChanged()).extracting(LiveMeasureDto::getComponentUuid).containsOnly(project.uuid(), dir.uuid(), file1.uuid());
119     assertThat(matrix.getMeasure(project, metric.getKey()).get().getValue()).isEqualTo(1d);
120     assertThat(matrix.getMeasure(dir, metric.getKey()).get().getValue()).isEqualTo(1d);
121     assertThat(matrix.getMeasure(file1, metric.getKey()).get().getValue()).isEqualTo(1d);
122     assertThat(matrix.getMeasure(file2, metric.getKey())).isEmpty();
123   }
124
125   @Test
126   public void dont_use_leak_formulas_if_no_period() {
127     snapshot = db.components().insertSnapshot(project, s -> s.setPeriodDate(null));
128     treeUpdater = new LiveMeasureTreeUpdaterImpl(db.getDbClient(), new CountUnresolvedInLeak());
129
130     componentIndex.load(db.getSession(), List.of(file1));
131     treeUpdater.update(db.getSession(), snapshot, config, componentIndex, branch, matrix);
132
133     assertThat(matrix.getChanged()).extracting(LiveMeasureDto::getComponentUuid).isEmpty();
134   }
135
136   @Test
137   public void use_leak_formulas_if_pr() {
138     snapshot = db.components().insertSnapshot(project, s -> s.setPeriodDate(null));
139     branch.setBranchType(BranchType.PULL_REQUEST);
140     treeUpdater = new LiveMeasureTreeUpdaterImpl(db.getDbClient(), new CountUnresolvedInLeak());
141
142     componentIndex.load(db.getSession(), List.of(file1));
143     treeUpdater.update(db.getSession(), snapshot, config, componentIndex, branch, matrix);
144
145     assertThat(matrix.getChanged()).extracting(LiveMeasureDto::getComponentUuid).containsOnly(project.uuid(), dir.uuid(), file1.uuid());
146   }
147
148   @Test
149   public void calculate_new_metrics_if_using_new_code_branch_reference() {
150     snapshot = db.components().insertSnapshot(project, s -> s.setPeriodMode(NewCodePeriodType.REFERENCE_BRANCH.name()));
151     treeUpdater = new LiveMeasureTreeUpdaterImpl(db.getDbClient(), new CountUnresolvedInLeak());
152
153     componentIndex.load(db.getSession(), List.of(file1));
154     treeUpdater.update(db.getSession(), snapshot, config, componentIndex, branch, matrix);
155
156     assertThat(matrix.getChanged()).extracting(LiveMeasureDto::getComponentUuid).containsOnly(project.uuid(), dir.uuid(), file1.uuid());
157   }
158
159   @Test
160   public void issue_counter_based_on_new_code_branch_reference() {
161     snapshot = db.components().insertSnapshot(project, s -> s.setPeriodMode(NewCodePeriodType.REFERENCE_BRANCH.name()));
162     treeUpdater = new LiveMeasureTreeUpdaterImpl(db.getDbClient(), new CountUnresolvedInLeak());
163
164     RuleDto rule = db.rules().insert(r -> r.setType(RuleType.BUG));
165     IssueDto issue1 = db.issues().insertIssue(rule, project, file1);
166     IssueDto issue2 = db.issues().insertIssue(rule, project, file1);
167     db.issues().insertNewCodeReferenceIssue(issue1);
168
169     componentIndex.load(db.getSession(), List.of(file1));
170     treeUpdater.update(db.getSession(), snapshot, config, componentIndex, branch, matrix);
171     assertThat(matrix.getMeasure(file1, metric.getKey()).get().getValue()).isEqualTo(1d);
172   }
173
174   @Test
175   public void issue_counter_uses_begin_of_leak() {
176     snapshot = db.components().insertSnapshot(project, s -> s.setPeriodDate(1000L));
177     treeUpdater = new LiveMeasureTreeUpdaterImpl(db.getDbClient(), new CountUnresolvedInLeak());
178
179     db.issues().insertIssue(i -> i.setIssueCreationDate(new Date(999)).setComponentUuid(file1.uuid()));
180     db.issues().insertIssue(i -> i.setIssueCreationDate(new Date(1001)).setComponentUuid(file1.uuid()));
181     db.issues().insertIssue(i -> i.setIssueCreationDate(new Date(1002)).setComponentUuid(file1.uuid()));
182
183     componentIndex.load(db.getSession(), List.of(file1));
184     treeUpdater.update(db.getSession(), snapshot, config, componentIndex, branch, matrix);
185
186     assertThat(matrix.getMeasure(file1, metric.getKey()).get().getValue()).isEqualTo(2d);
187   }
188
189   @Test
190   public void context_calculates_hotspot_counts_from_percentage() {
191     List<MetricDto> metrics = List.of(new MetricDto().setKey(SECURITY_HOTSPOTS_KEY), new MetricDto().setKey(SECURITY_HOTSPOTS_REVIEWED_KEY),
192       new MetricDto().setKey(SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY), new MetricDto().setKey(SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY));
193     componentIndex.load(db.getSession(), List.of(file1));
194     matrix = new MeasureMatrix(List.of(project, dir, file1, file2), metrics, List.of());
195
196     LiveMeasureTreeUpdaterImpl.FormulaContextImpl context = new LiveMeasureTreeUpdaterImpl.FormulaContextImpl(matrix, componentIndex, null);
197     matrix.setValue(file1, SECURITY_HOTSPOTS_KEY, 4d);
198     matrix.setValue(file1, SECURITY_HOTSPOTS_REVIEWED_KEY, 33d);
199
200     matrix.setValue(file2, SECURITY_HOTSPOTS_KEY, 2d);
201     matrix.setValue(file2, SECURITY_HOTSPOTS_REVIEWED_KEY, 50d);
202
203     context.change(dir, null);
204     assertThat(context.getChildrenHotspotsToReview()).isEqualTo(6);
205     assertThat(context.getChildrenHotspotsReviewed()).isEqualTo(4);
206   }
207
208   @Test
209   public void context_calculates_new_hotspot_counts_from_percentage() {
210     List<MetricDto> metrics = List.of(new MetricDto().setKey(NEW_SECURITY_HOTSPOTS_KEY), new MetricDto().setKey(NEW_SECURITY_HOTSPOTS_REVIEWED_KEY),
211       new MetricDto().setKey(NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY), new MetricDto().setKey(NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY));
212     componentIndex.load(db.getSession(), List.of(file1));
213     matrix = new MeasureMatrix(List.of(project, dir, file1, file2), metrics, List.of());
214
215     LiveMeasureTreeUpdaterImpl.FormulaContextImpl context = new LiveMeasureTreeUpdaterImpl.FormulaContextImpl(matrix, componentIndex, null);
216     matrix.setValue(file1, NEW_SECURITY_HOTSPOTS_KEY, 4d);
217     matrix.setValue(file1, NEW_SECURITY_HOTSPOTS_REVIEWED_KEY, 33d);
218
219     matrix.setValue(file2, NEW_SECURITY_HOTSPOTS_KEY, 2d);
220     matrix.setValue(file2, NEW_SECURITY_HOTSPOTS_REVIEWED_KEY, 50d);
221
222     context.change(dir, null);
223     assertThat(context.getChildrenNewHotspotsToReview()).isEqualTo(6);
224     assertThat(context.getChildrenNewHotspotsReviewed()).isEqualTo(4);
225   }
226
227   @Test
228   public void context_returns_hotspots_counts_from_measures() {
229     List<MetricDto> metrics = List.of(new MetricDto().setKey(SECURITY_HOTSPOTS_KEY), new MetricDto().setKey(SECURITY_HOTSPOTS_REVIEWED_KEY),
230       new MetricDto().setKey(SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY), new MetricDto().setKey(SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY));
231     componentIndex.load(db.getSession(), List.of(file1));
232     matrix = new MeasureMatrix(List.of(project, dir, file1, file2), metrics, List.of());
233
234     LiveMeasureTreeUpdaterImpl.FormulaContextImpl context = new LiveMeasureTreeUpdaterImpl.FormulaContextImpl(matrix, componentIndex, null);
235     matrix.setValue(file1, SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY, 5D);
236     matrix.setValue(file1, SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY, 5D);
237     matrix.setValue(file1, SECURITY_HOTSPOTS_KEY, 6d);
238     matrix.setValue(file1, SECURITY_HOTSPOTS_REVIEWED_KEY, 33d);
239
240     matrix.setValue(file2, SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY, 5D);
241     matrix.setValue(file2, SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY, 5D);
242     matrix.setValue(file2, SECURITY_HOTSPOTS_KEY, 4d);
243     matrix.setValue(file2, SECURITY_HOTSPOTS_REVIEWED_KEY, 50d);
244
245     context.change(dir, null);
246     assertThat(context.getChildrenHotspotsToReview()).isEqualTo(10);
247     assertThat(context.getChildrenHotspotsReviewed()).isEqualTo(10);
248   }
249
250   private class AggregateValuesFormula implements MeasureUpdateFormulaFactory {
251     @Override
252     public List<MeasureUpdateFormula> getFormulas() {
253       return List.of(new MeasureUpdateFormula(metric, false, new MeasureUpdateFormulaFactoryImpl.AddChildren(), (c, i) -> {
254       }));
255     }
256
257     @Override
258     public Set<Metric> getFormulaMetrics() {
259       return Set.of(metric);
260     }
261   }
262
263   private class SetValuesFormula implements MeasureUpdateFormulaFactory {
264     @Override
265     public List<MeasureUpdateFormula> getFormulas() {
266       return List.of(new MeasureUpdateFormula(metric, false, (c, m) -> {
267       }, (c, i) -> c.setValue(1d)));
268     }
269
270     @Override
271     public Set<Metric> getFormulaMetrics() {
272       return Set.of(metric);
273     }
274   }
275
276   private class CountUnresolvedInLeak implements MeasureUpdateFormulaFactory {
277     @Override
278     public List<MeasureUpdateFormula> getFormulas() {
279       return List.of(new MeasureUpdateFormula(metric, true, (c, m) -> {
280       }, (c, i) -> c.setValue(i.countUnresolved(true))));
281     }
282
283     @Override
284     public Set<Metric> getFormulaMetrics() {
285       return Set.of(metric);
286     }
287   }
288 }