3 * Copyright (C) 2009-2022 SonarSource SA
4 * mailto:info AT sonarsource DOT com
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.
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.
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.
20 package org.sonar.server.measure.live;
22 import java.util.Date;
23 import java.util.List;
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.db.DbTester;
32 import org.sonar.db.component.BranchDto;
33 import org.sonar.db.component.BranchType;
34 import org.sonar.db.component.ComponentDto;
35 import org.sonar.db.component.ComponentTesting;
36 import org.sonar.db.component.SnapshotDto;
37 import org.sonar.db.issue.IssueDto;
38 import org.sonar.db.measure.LiveMeasureDto;
39 import org.sonar.db.metric.MetricDto;
40 import org.sonar.db.newcodeperiod.NewCodePeriodType;
41 import org.sonar.db.rule.RuleDto;
43 import static org.assertj.core.api.Assertions.assertThat;
44 import static org.mockito.ArgumentMatchers.any;
45 import static org.mockito.ArgumentMatchers.eq;
46 import static org.mockito.Mockito.mock;
47 import static org.mockito.Mockito.verify;
48 import static org.sonar.api.CoreProperties.RATING_GRID;
50 public class LiveMeasureTreeUpdaterImplTest {
52 public DbTester db = DbTester.create();
54 private final Configuration config = new MapSettings().setProperty(RATING_GRID, "0.05,0.1,0.2,0.5").asConfig();
55 private final HotspotMeasureUpdater hotspotMeasureUpdater = mock(HotspotMeasureUpdater.class);
56 private LiveMeasureTreeUpdaterImpl treeUpdater;
57 private ComponentIndexImpl componentIndex;
58 private MeasureMatrix matrix;
59 private MetricDto metricDto;
60 private Metric metric;
61 private ComponentDto project;
62 private BranchDto branch;
63 private ComponentDto dir;
64 private ComponentDto file1;
65 private ComponentDto file2;
66 private SnapshotDto snapshot;
70 // insert project and file structure
71 project = db.components().insertPrivateProject();
72 branch = db.getDbClient().branchDao().selectByUuid(db.getSession(), project.uuid()).get();
73 dir = db.components().insertComponent(ComponentTesting.newDirectory(project, "src/main/java"));
74 file1 = db.components().insertComponent(ComponentTesting.newFileDto(project, dir));
75 file2 = db.components().insertComponent(ComponentTesting.newFileDto(project, dir));
78 metricDto = db.measures().insertMetric(m -> m.setValueType(Metric.ValueType.INT.name()));
79 metric = new Metric.Builder(metricDto.getKey(), metricDto.getShortName(), Metric.ValueType.valueOf(metricDto.getValueType())).create();
80 matrix = new MeasureMatrix(List.of(project, dir, file1, file2), List.of(metricDto), List.of());
81 componentIndex = new ComponentIndexImpl(db.getDbClient());
85 public void should_aggregate_values_up_the_hierarchy() {
86 snapshot = db.components().insertSnapshot(project);
87 treeUpdater = new LiveMeasureTreeUpdaterImpl(db.getDbClient(), new AggregateValuesFormula(), hotspotMeasureUpdater);
89 componentIndex.load(db.getSession(), List.of(file1));
90 List<LiveMeasureDto> initialValues = List.of(
91 new LiveMeasureDto().setComponentUuid(file1.uuid()).setValue(1d).setMetricUuid(metricDto.getUuid()),
92 new LiveMeasureDto().setComponentUuid(file2.uuid()).setValue(1d).setMetricUuid(metricDto.getUuid()),
93 new LiveMeasureDto().setComponentUuid(dir.uuid()).setValue(1d).setMetricUuid(metricDto.getUuid()),
94 new LiveMeasureDto().setComponentUuid(project.uuid()).setValue(1d).setMetricUuid(metricDto.getUuid())
96 matrix = new MeasureMatrix(List.of(project, dir, file1, file2), List.of(metricDto), initialValues);
97 treeUpdater.update(db.getSession(), snapshot, config, componentIndex, branch, matrix);
99 assertThat(matrix.getChanged()).extracting(LiveMeasureDto::getComponentUuid).containsOnly(project.uuid(), dir.uuid());
100 assertThat(matrix.getMeasure(project, metric.getKey()).get().getValue()).isEqualTo(4d);
101 assertThat(matrix.getMeasure(dir, metric.getKey()).get().getValue()).isEqualTo(3d);
102 assertThat(matrix.getMeasure(file1, metric.getKey()).get().getValue()).isEqualTo(1d);
103 assertThat(matrix.getMeasure(file2, metric.getKey()).get().getValue()).isEqualTo(1d);
107 public void should_set_values_up_the_hierarchy() {
108 snapshot = db.components().insertSnapshot(project);
109 treeUpdater = new LiveMeasureTreeUpdaterImpl(db.getDbClient(), new SetValuesFormula(), hotspotMeasureUpdater);
111 componentIndex.load(db.getSession(), List.of(file1));
112 treeUpdater.update(db.getSession(), snapshot, config, componentIndex, branch, matrix);
114 assertThat(matrix.getChanged()).extracting(LiveMeasureDto::getComponentUuid).containsOnly(project.uuid(), dir.uuid(), file1.uuid());
115 assertThat(matrix.getMeasure(project, metric.getKey()).get().getValue()).isEqualTo(1d);
116 assertThat(matrix.getMeasure(dir, metric.getKey()).get().getValue()).isEqualTo(1d);
117 assertThat(matrix.getMeasure(file1, metric.getKey()).get().getValue()).isEqualTo(1d);
118 assertThat(matrix.getMeasure(file2, metric.getKey())).isEmpty();
122 public void dont_use_leak_formulas_if_no_period() {
123 snapshot = db.components().insertSnapshot(project, s -> s.setPeriodDate(null));
124 treeUpdater = new LiveMeasureTreeUpdaterImpl(db.getDbClient(), new CountUnresolvedInLeak(), hotspotMeasureUpdater);
126 componentIndex.load(db.getSession(), List.of(file1));
127 treeUpdater.update(db.getSession(), snapshot, config, componentIndex, branch, matrix);
129 assertThat(matrix.getChanged()).extracting(LiveMeasureDto::getComponentUuid).isEmpty();
133 public void use_leak_formulas_if_pr() {
134 snapshot = db.components().insertSnapshot(project, s -> s.setPeriodDate(null));
135 branch.setBranchType(BranchType.PULL_REQUEST);
136 treeUpdater = new LiveMeasureTreeUpdaterImpl(db.getDbClient(), new CountUnresolvedInLeak(), hotspotMeasureUpdater);
138 componentIndex.load(db.getSession(), List.of(file1));
139 treeUpdater.update(db.getSession(), snapshot, config, componentIndex, branch, matrix);
141 assertThat(matrix.getChanged()).extracting(LiveMeasureDto::getComponentUuid).containsOnly(project.uuid(), dir.uuid(), file1.uuid());
145 public void calculate_new_metrics_if_using_new_code_branch_reference() {
146 snapshot = db.components().insertSnapshot(project, s -> s.setPeriodMode(NewCodePeriodType.REFERENCE_BRANCH.name()));
147 treeUpdater = new LiveMeasureTreeUpdaterImpl(db.getDbClient(), new CountUnresolvedInLeak(), hotspotMeasureUpdater);
149 componentIndex.load(db.getSession(), List.of(file1));
150 treeUpdater.update(db.getSession(), snapshot, config, componentIndex, branch, matrix);
152 assertThat(matrix.getChanged()).extracting(LiveMeasureDto::getComponentUuid).containsOnly(project.uuid(), dir.uuid(), file1.uuid());
156 public void issue_counter_based_on_new_code_branch_reference() {
157 snapshot = db.components().insertSnapshot(project, s -> s.setPeriodMode(NewCodePeriodType.REFERENCE_BRANCH.name()));
158 treeUpdater = new LiveMeasureTreeUpdaterImpl(db.getDbClient(), new CountUnresolvedInLeak(), hotspotMeasureUpdater);
160 RuleDto rule = db.rules().insert();
161 IssueDto issue1 = db.issues().insertIssue(rule, project, file1);
162 IssueDto issue2 = db.issues().insertIssue(rule, project, file1);
163 db.issues().insertNewCodeReferenceIssue(issue1);
165 componentIndex.load(db.getSession(), List.of(file1));
166 treeUpdater.update(db.getSession(), snapshot, config, componentIndex, branch, matrix);
167 assertThat(matrix.getMeasure(file1, metric.getKey()).get().getVariation()).isEqualTo(1d);
171 public void issue_counter_uses_begin_of_leak() {
172 snapshot = db.components().insertSnapshot(project, s -> s.setPeriodDate(1000L));
173 treeUpdater = new LiveMeasureTreeUpdaterImpl(db.getDbClient(), new CountUnresolvedInLeak(), hotspotMeasureUpdater);
175 db.issues().insertIssue(i -> i.setIssueCreationDate(new Date(999)).setComponentUuid(file1.uuid()));
176 db.issues().insertIssue(i -> i.setIssueCreationDate(new Date(1001)).setComponentUuid(file1.uuid()));
177 db.issues().insertIssue(i -> i.setIssueCreationDate(new Date(1002)).setComponentUuid(file1.uuid()));
179 componentIndex.load(db.getSession(), List.of(file1));
180 treeUpdater.update(db.getSession(), snapshot, config, componentIndex, branch, matrix);
182 assertThat(matrix.getMeasure(file1, metric.getKey()).get().getVariation()).isEqualTo(2d);
186 public void calls_hotspot_updater() {
187 snapshot = db.components().insertSnapshot(project, s -> s.setPeriodDate(1000L));
189 componentIndex.load(db.getSession(), List.of(file1));
190 treeUpdater = new LiveMeasureTreeUpdaterImpl(db.getDbClient(), new CountUnresolvedInLeak(), hotspotMeasureUpdater);
191 treeUpdater.update(db.getSession(), snapshot, config, componentIndex, branch, matrix);
192 verify(hotspotMeasureUpdater).apply(eq(db.getSession()), any(), eq(componentIndex), eq(true), eq(1000L));
195 private class AggregateValuesFormula implements MeasureUpdateFormulaFactory {
197 public List<MeasureUpdateFormula> getFormulas() {
198 return List.of(new MeasureUpdateFormula(metric, false, new MeasureUpdateFormulaFactoryImpl.AddChildren(), (c, i) -> {
203 public Set<Metric> getFormulaMetrics() {
204 return Set.of(metric);
208 private class SetValuesFormula implements MeasureUpdateFormulaFactory {
210 public List<MeasureUpdateFormula> getFormulas() {
211 return List.of(new MeasureUpdateFormula(metric, false, (c, m) -> {
212 }, (c, i) -> c.setValue(1d)));
216 public Set<Metric> getFormulaMetrics() {
217 return Set.of(metric);
221 private class CountUnresolvedInLeak implements MeasureUpdateFormulaFactory {
223 public List<MeasureUpdateFormula> getFormulas() {
224 return List.of(new MeasureUpdateFormula(metric, true, (c, m) -> {
225 }, (c, i) -> c.setLeakValue(i.countUnresolved(true))));
229 public Set<Metric> getFormulaMetrics() {
230 return Set.of(metric);