3 * Copyright (C) 2009-2024 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.ce.task.projectanalysis.step;
22 import java.util.Optional;
23 import org.junit.Before;
24 import org.junit.Rule;
25 import org.junit.Test;
26 import org.sonar.api.measures.Metric;
27 import org.sonar.api.utils.System2;
28 import org.sonar.ce.task.projectanalysis.analysis.MutableAnalysisMetadataHolderRule;
29 import org.sonar.ce.task.projectanalysis.component.Component;
30 import org.sonar.ce.task.projectanalysis.component.ReportComponent;
31 import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
32 import org.sonar.ce.task.projectanalysis.component.ViewsComponent;
33 import org.sonar.ce.task.projectanalysis.measure.MeasureRepositoryRule;
34 import org.sonar.ce.task.projectanalysis.measure.MeasureToMeasureDto;
35 import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule;
36 import org.sonar.ce.task.step.ComputationStep;
37 import org.sonar.ce.task.step.TestComputationStepContext;
38 import org.sonar.db.DbClient;
39 import org.sonar.db.DbTester;
40 import org.sonar.db.component.ComponentDto;
41 import org.sonar.db.measure.MeasureDto;
42 import org.sonar.db.metric.MetricDto;
44 import static org.assertj.core.api.Assertions.assertThat;
45 import static org.sonar.ce.task.projectanalysis.component.Component.Type.DIRECTORY;
46 import static org.sonar.ce.task.projectanalysis.component.Component.Type.FILE;
47 import static org.sonar.ce.task.projectanalysis.component.Component.Type.PROJECT;
48 import static org.sonar.ce.task.projectanalysis.component.Component.Type.PROJECT_VIEW;
49 import static org.sonar.ce.task.projectanalysis.component.Component.Type.SUBVIEW;
50 import static org.sonar.ce.task.projectanalysis.component.Component.Type.VIEW;
51 import static org.sonar.ce.task.projectanalysis.measure.Measure.newMeasureBuilder;
53 public class PersistMeasuresStepIT extends BaseStepTest {
55 private static final Metric STRING_METRIC = new Metric.Builder("string-metric", "String metric", Metric.ValueType.STRING).create();
56 private static final Metric INT_METRIC = new Metric.Builder("int-metric", "int metric", Metric.ValueType.INT).create();
57 private static final Metric NON_HISTORICAL_METRIC = new Metric.Builder("nh-metric", "nh metric", Metric.ValueType.INT).setDeleteHistoricalData(true).create();
59 private static final String ANALYSIS_UUID = "a1";
61 private static final int REF_1 = 1;
62 private static final int REF_2 = 2;
63 private static final int REF_3 = 3;
64 private static final int REF_4 = 4;
67 public DbTester db = DbTester.create(System2.INSTANCE);
69 public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
71 public MetricRepositoryRule metricRepository = new MetricRepositoryRule();
73 public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
75 public MutableAnalysisMetadataHolderRule analysisMetadataHolder = new MutableAnalysisMetadataHolderRule();
77 private DbClient dbClient = db.getDbClient();
81 analysisMetadataHolder.setUuid(ANALYSIS_UUID);
82 MetricDto stringMetricDto = db.measures().insertMetric(m -> m.setKey(STRING_METRIC.getKey()).setValueType(Metric.ValueType.STRING.name()));
83 MetricDto intMetricDto = db.measures().insertMetric(m -> m.setKey(INT_METRIC.getKey()).setValueType(Metric.ValueType.INT.name()));
84 MetricDto nhMetricDto = db.measures().insertMetric(m -> m.setKey(NON_HISTORICAL_METRIC.getKey()).setValueType(Metric.ValueType.INT.name()));
85 metricRepository.add(stringMetricDto.getUuid(), STRING_METRIC);
86 metricRepository.add(intMetricDto.getUuid(), INT_METRIC);
87 metricRepository.add(nhMetricDto.getUuid(), NON_HISTORICAL_METRIC);
91 public void measures_on_non_historical_metrics_are_not_persisted() {
93 measureRepository.addRawMeasure(REF_1, NON_HISTORICAL_METRIC.getKey(), newMeasureBuilder().create(1));
94 measureRepository.addRawMeasure(REF_1, INT_METRIC.getKey(), newMeasureBuilder().create(2));
96 TestComputationStepContext context = execute();
98 assertThatMeasureIsNotPersisted("project-uuid", NON_HISTORICAL_METRIC);
99 MeasureDto persistedMeasure = selectMeasure("project-uuid", INT_METRIC).get();
100 assertThat(persistedMeasure.getValue()).isEqualTo(2);
101 assertNbOfInserts(context, 1);
105 public void persist_measures_of_project_analysis_excluding_directories() {
108 // the computed measures
109 measureRepository.addRawMeasure(REF_1, STRING_METRIC.getKey(), newMeasureBuilder().create("project-value"));
110 measureRepository.addRawMeasure(REF_3, STRING_METRIC.getKey(), newMeasureBuilder().create("dir-value"));
111 measureRepository.addRawMeasure(REF_4, STRING_METRIC.getKey(), newMeasureBuilder().create("file-value"));
113 TestComputationStepContext context = execute();
115 // project and dir measures are persisted, but not file measures
116 assertThat(db.countRowsOfTable("project_measures")).isOne();
117 assertThat(selectMeasure("project-uuid", STRING_METRIC).get().getData()).isEqualTo("project-value");
118 assertThatMeasuresAreNotPersisted("dir-uuid");
119 assertThatMeasuresAreNotPersisted("file-uuid");
120 assertNbOfInserts(context, 1);
124 public void measures_without_value_are_not_persisted() {
126 measureRepository.addRawMeasure(REF_1, STRING_METRIC.getKey(), newMeasureBuilder().createNoValue());
127 measureRepository.addRawMeasure(REF_1, INT_METRIC.getKey(), newMeasureBuilder().createNoValue());
129 TestComputationStepContext context = execute();
131 assertThatMeasureIsNotPersisted("project-uuid", STRING_METRIC);
132 assertThatMeasureIsNotPersisted("project-uuid", INT_METRIC);
133 assertNbOfInserts(context, 0);
137 public void measures_on_new_code_period_are_persisted() {
139 measureRepository.addRawMeasure(REF_1, INT_METRIC.getKey(), newMeasureBuilder().create(42.0));
141 TestComputationStepContext context = execute();
143 MeasureDto persistedMeasure = selectMeasure("project-uuid", INT_METRIC).get();
144 assertThat(persistedMeasure.getValue()).isEqualTo(42.0);
145 assertNbOfInserts(context, 1);
149 public void persist_all_measures_of_portfolio_analysis() {
152 // the computed measures
153 measureRepository.addRawMeasure(REF_1, STRING_METRIC.getKey(), newMeasureBuilder().create("view-value"));
154 measureRepository.addRawMeasure(REF_2, STRING_METRIC.getKey(), newMeasureBuilder().create("subview-value"));
155 measureRepository.addRawMeasure(REF_3, STRING_METRIC.getKey(), newMeasureBuilder().create("project-value"));
157 TestComputationStepContext context = execute();
159 assertThat(db.countRowsOfTable("project_measures")).isEqualTo(2);
160 assertThat(selectMeasure("view-uuid", STRING_METRIC).get().getData()).isEqualTo("view-value");
161 assertThat(selectMeasure("subview-uuid", STRING_METRIC).get().getData()).isEqualTo("subview-value");
162 assertNbOfInserts(context, 2);
165 private void prepareProject() {
166 // tree of components as defined by scanner report
167 Component project = ReportComponent.builder(PROJECT, REF_1).setUuid("project-uuid")
169 ReportComponent.builder(DIRECTORY, REF_3).setUuid("dir-uuid")
171 ReportComponent.builder(FILE, REF_4).setUuid("file-uuid")
175 treeRootHolder.setRoot(project);
177 // components as persisted in db
178 ComponentDto projectDto = insertComponent("project-key", "project-uuid");
179 ComponentDto dirDto = insertComponent("dir-key", "dir-uuid");
180 ComponentDto fileDto = insertComponent("file-key", "file-uuid");
181 db.components().insertSnapshot(projectDto, s -> s.setUuid(ANALYSIS_UUID));
184 private void preparePortfolio() {
185 // tree of components
186 Component portfolio = ViewsComponent.builder(VIEW, REF_1).setUuid("view-uuid")
188 ViewsComponent.builder(SUBVIEW, REF_2).setUuid("subview-uuid")
190 ViewsComponent.builder(PROJECT_VIEW, REF_3).setUuid("project-uuid")
194 treeRootHolder.setRoot(portfolio);
196 // components as persisted in db
197 ComponentDto viewDto = insertComponent("view-key", "view-uuid");
198 ComponentDto subViewDto = insertComponent("subview-key", "subview-uuid");
199 ComponentDto projectDto = insertComponent("project-key", "project-uuid");
200 db.components().insertSnapshot(viewDto, s -> s.setUuid(ANALYSIS_UUID));
203 private void assertThatMeasureIsNotPersisted(String componentUuid, Metric metric) {
204 assertThat(selectMeasure(componentUuid, metric)).isEmpty();
207 private void assertThatMeasuresAreNotPersisted(String componentUuid) {
208 assertThatMeasureIsNotPersisted(componentUuid, STRING_METRIC);
209 assertThatMeasureIsNotPersisted(componentUuid, INT_METRIC);
212 private TestComputationStepContext execute() {
213 TestComputationStepContext context = new TestComputationStepContext();
214 new PersistMeasuresStep(dbClient, metricRepository, new MeasureToMeasureDto(analysisMetadataHolder, treeRootHolder), treeRootHolder, measureRepository)
219 private Optional<MeasureDto> selectMeasure(String componentUuid, Metric metric) {
220 return dbClient.measureDao().selectMeasure(db.getSession(), ANALYSIS_UUID, componentUuid, metric.getKey());
223 private ComponentDto insertComponent(String key, String uuid) {
224 ComponentDto componentDto = new ComponentDto()
227 .setUuidPath(uuid + ".")
228 .setBranchUuid(uuid);
229 db.components().insertComponent(componentDto);
233 private static void assertNbOfInserts(TestComputationStepContext context, int expected) {
234 context.getStatistics().assertValue("inserts", expected);
238 protected ComputationStep step() {
239 return new PersistMeasuresStep(dbClient, metricRepository, new MeasureToMeasureDto(analysisMetadataHolder, treeRootHolder), treeRootHolder, measureRepository);