]> source.dussan.org Git - sonarqube.git/blob
b030f2474b11d4d5fb00d6e2cd8f04b3d84bf728
[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.measure;
21
22 import com.google.common.base.Function;
23 import com.google.common.collect.ImmutableList;
24 import com.tngtech.java.junit.dataprovider.DataProvider;
25 import com.tngtech.java.junit.dataprovider.DataProviderRunner;
26 import com.tngtech.java.junit.dataprovider.UseDataProvider;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Optional;
30 import javax.annotation.Nullable;
31 import org.junit.Before;
32 import org.junit.Rule;
33 import org.junit.Test;
34 import org.junit.runner.RunWith;
35 import org.sonar.api.utils.System2;
36 import org.sonar.ce.task.projectanalysis.batch.BatchReportReader;
37 import org.sonar.ce.task.projectanalysis.batch.BatchReportReaderRule;
38 import org.sonar.ce.task.projectanalysis.component.Component;
39 import org.sonar.ce.task.projectanalysis.component.ReportComponent;
40 import org.sonar.ce.task.projectanalysis.metric.Metric;
41 import org.sonar.ce.task.projectanalysis.metric.MetricImpl;
42 import org.sonar.ce.task.projectanalysis.metric.MetricRepository;
43 import org.sonar.ce.task.projectanalysis.metric.ReportMetricValidator;
44 import org.sonar.db.DbClient;
45 import org.sonar.db.DbSession;
46 import org.sonar.db.DbTester;
47 import org.sonar.db.component.ComponentDto;
48 import org.sonar.db.component.SnapshotDto;
49 import org.sonar.db.measure.MeasureDto;
50 import org.sonar.db.metric.MetricDto;
51 import org.sonar.scanner.protocol.output.ScannerReport;
52 import org.sonar.scanner.protocol.output.ScannerReport.Measure.StringValue;
53
54 import static com.google.common.collect.FluentIterable.from;
55 import static java.lang.String.format;
56 import static org.assertj.core.api.Assertions.assertThat;
57 import static org.assertj.core.api.Assertions.assertThatThrownBy;
58 import static org.junit.Assert.fail;
59 import static org.mockito.Mockito.mock;
60 import static org.mockito.Mockito.verifyNoInteractions;
61 import static org.mockito.Mockito.verifyNoMoreInteractions;
62 import static org.mockito.Mockito.when;
63 import static org.sonar.db.component.ComponentTesting.newFileDto;
64
65 @RunWith(DataProviderRunner.class)
66 public class MeasureRepositoryImplIT {
67
68
69   @Rule
70   public DbTester dbTester = DbTester.create(System2.INSTANCE);
71   @Rule
72   public BatchReportReaderRule reportReader = new BatchReportReaderRule();
73
74   private static final String FILE_COMPONENT_KEY = "file cpt key";
75   private static final ReportComponent FILE_COMPONENT = ReportComponent.builder(Component.Type.FILE, 1).setKey(FILE_COMPONENT_KEY).build();
76   private static final ReportComponent OTHER_COMPONENT = ReportComponent.builder(Component.Type.FILE, 2).setKey("some other key").build();
77   private static final String METRIC_KEY_1 = "metric 1";
78   private static final int METRIC_ID_1 = 1;
79   private static final String METRIC_KEY_2 = "metric 2";
80   private static final int METRIC_ID_2 = 2;
81   private final Metric metric1 = mock(Metric.class);
82   private final Metric metric2 = mock(Metric.class);
83   private static final String LAST_ANALYSIS_UUID = "u123";
84   private static final String OTHER_ANALYSIS_UUID = "u369";
85   private static final Measure SOME_MEASURE = Measure.newMeasureBuilder().create("some value");
86   private static final String SOME_DATA = "some data";
87
88   private ReportMetricValidator reportMetricValidator = mock(ReportMetricValidator.class);
89
90   private DbClient dbClient = dbTester.getDbClient();
91   private MetricRepository metricRepository = mock(MetricRepository.class);
92   private MeasureRepositoryImpl underTest = new MeasureRepositoryImpl(dbClient, reportReader, metricRepository, reportMetricValidator);
93
94   private DbClient mockedDbClient = mock(DbClient.class);
95   private BatchReportReader mockBatchReportReader = mock(BatchReportReader.class);
96   private MeasureRepositoryImpl underTestWithMock = new MeasureRepositoryImpl(mockedDbClient, mockBatchReportReader, metricRepository, reportMetricValidator);
97
98   private DbSession dbSession = dbTester.getSession();
99
100   @Before
101   public void setUp() {
102     when(metric1.getKey()).thenReturn(METRIC_KEY_1);
103     when(metric1.getType()).thenReturn(Metric.MetricType.STRING);
104     when(metric2.getKey()).thenReturn(METRIC_KEY_2);
105     when(metric2.getType()).thenReturn(Metric.MetricType.STRING);
106
107     // references to metrics are consistent with DB by design
108     when(metricRepository.getByKey(METRIC_KEY_1)).thenReturn(metric1);
109     when(metricRepository.getByKey(METRIC_KEY_2)).thenReturn(metric2);
110   }
111
112   @Test
113   public void getBaseMeasure_throws_NPE_and_does_not_open_session_if_component_is_null() {
114     try {
115       underTestWithMock.getBaseMeasure(null, metric1);
116       fail("an NPE should have been raised");
117     } catch (NullPointerException e) {
118       verifyNoInteractions(mockedDbClient);
119     }
120   }
121
122   @Test
123   public void getBaseMeasure_throws_NPE_and_does_not_open_session_if_metric_is_null() {
124     try {
125       underTestWithMock.getBaseMeasure(FILE_COMPONENT, null);
126       fail("an NPE should have been raised");
127     } catch (NullPointerException e) {
128       verifyNoInteractions(mockedDbClient);
129     }
130   }
131
132   @Test
133   public void getBaseMeasure_returns_absent_if_measure_does_not_exist_in_DB() {
134     Optional<Measure> res = underTest.getBaseMeasure(FILE_COMPONENT, metric1);
135
136     assertThat(res).isNotPresent();
137   }
138
139   @Test
140   public void getBaseMeasure_returns_Measure_if_measure_of_last_snapshot_only_in_DB() {
141     ComponentDto project = dbTester.components().insertPrivateProject().getMainBranchComponent();
142     dbTester.components().insertComponent(newFileDto(project).setUuid(FILE_COMPONENT.getUuid()));
143     SnapshotDto lastAnalysis = dbTester.components().insertSnapshot(project, t -> t.setLast(true));
144     SnapshotDto oldAnalysis = dbTester.components().insertSnapshot(project, t -> t.setLast(false));
145     MetricDto metric1 = dbTester.measures().insertMetric(t -> t.setValueType(org.sonar.api.measures.Metric.ValueType.STRING.name()));
146     MetricDto metric2 = dbTester.measures().insertMetric(t -> t.setValueType(org.sonar.api.measures.Metric.ValueType.STRING.name()));
147     dbClient.measureDao().insert(dbSession, createMeasureDto(metric1.getUuid(), FILE_COMPONENT.getUuid(), lastAnalysis.getUuid()));
148     dbClient.measureDao().insert(dbSession, createMeasureDto(metric1.getUuid(), FILE_COMPONENT.getUuid(), oldAnalysis.getUuid()));
149     dbSession.commit();
150
151     // metric 1 is associated to snapshot with "last=true"
152     assertThat(underTest.getBaseMeasure(FILE_COMPONENT, metricOf(metric1)).get().getStringValue())
153       .isEqualTo(SOME_DATA);
154     // metric 2 is associated to snapshot with "last=false" => not retrieved
155     assertThat(underTest.getBaseMeasure(FILE_COMPONENT, metricOf(metric2))).isNotPresent();
156   }
157
158   private Metric metricOf(MetricDto metricDto) {
159     Metric res = mock(Metric.class);
160     when(res.getKey()).thenReturn(metricDto.getKey());
161     when(res.getUuid()).thenReturn(metricDto.getUuid());
162     when(res.getType()).thenReturn(Metric.MetricType.valueOf(metricDto.getValueType()));
163     return res;
164   }
165
166   @Test
167   public void add_throws_NPE_if_Component_argument_is_null() {
168     assertThatThrownBy(() -> underTest.add(null, metric1, SOME_MEASURE))
169       .isInstanceOf(NullPointerException.class);
170   }
171
172   @Test
173   public void add_throws_NPE_if_Component_metric_is_null() {
174     assertThatThrownBy(() -> underTest.add(FILE_COMPONENT, null, SOME_MEASURE))
175       .isInstanceOf(NullPointerException.class);
176   }
177
178   @Test
179   public void add_throws_NPE_if_Component_measure_is_null() {
180     assertThatThrownBy(() -> underTest.add(FILE_COMPONENT, metric1, null))
181       .isInstanceOf(NullPointerException.class);
182   }
183
184   @Test
185   public void add_throws_UOE_if_measure_already_exists() {
186     assertThatThrownBy(() -> {
187       underTest.add(FILE_COMPONENT, metric1, SOME_MEASURE);
188       underTest.add(FILE_COMPONENT, metric1, SOME_MEASURE);
189     })
190       .isInstanceOf(UnsupportedOperationException.class);
191   }
192
193   @Test
194   public void update_throws_NPE_if_Component_metric_is_null() {
195     assertThatThrownBy(() -> underTest.update(FILE_COMPONENT, null, SOME_MEASURE))
196       .isInstanceOf(NullPointerException.class);
197   }
198
199   @Test
200   public void update_throws_NPE_if_Component_measure_is_null() {
201     assertThatThrownBy(() -> underTest.update(FILE_COMPONENT, metric1, null))
202       .isInstanceOf(NullPointerException.class);
203   }
204
205   @Test
206   public void update_throws_UOE_if_measure_does_not_exists() {
207     assertThatThrownBy(() -> underTest.update(FILE_COMPONENT, metric1, SOME_MEASURE))
208       .isInstanceOf(UnsupportedOperationException.class);
209   }
210
211   private static final List<Measure> MEASURES = ImmutableList.of(
212     Measure.newMeasureBuilder().create(1),
213     Measure.newMeasureBuilder().create(1L),
214     Measure.newMeasureBuilder().create(1d, 1),
215     Measure.newMeasureBuilder().create(true),
216     Measure.newMeasureBuilder().create(false),
217     Measure.newMeasureBuilder().create("sds"),
218     Measure.newMeasureBuilder().create(Measure.Level.OK),
219     Measure.newMeasureBuilder().createNoValue());
220
221   @DataProvider
222   public static Object[][] measures() {
223     return from(MEASURES).transform(new Function<Measure, Object[]>() {
224       @Nullable
225       @Override
226       public Object[] apply(Measure input) {
227         return new Measure[] {input};
228       }
229     }).toArray(Object[].class);
230   }
231
232   @Test
233   public void add_accepts_NO_VALUE_as_measure_arg() {
234     for (Metric.MetricType metricType : Metric.MetricType.values()) {
235       underTest.add(FILE_COMPONENT, new MetricImpl("1", "key" + metricType, "name" + metricType, metricType), Measure.newMeasureBuilder().createNoValue());
236     }
237   }
238
239   @Test
240   @UseDataProvider("measures")
241   public void update_throws_IAE_if_valueType_of_Measure_is_not_the_same_as_the_Metric_valueType_unless_NO_VALUE(Measure measure) {
242     for (Metric.MetricType metricType : Metric.MetricType.values()) {
243       if (metricType.getValueType() == measure.getValueType() || measure.getValueType() == Measure.ValueType.NO_VALUE) {
244         continue;
245       }
246
247       try {
248         final MetricImpl metric = new MetricImpl("1", "key" + metricType, "name" + metricType, metricType);
249         underTest.add(FILE_COMPONENT, metric, getSomeMeasureByValueType(metricType));
250         underTest.update(FILE_COMPONENT, metric, measure);
251         fail("An IllegalArgumentException should have been raised");
252       } catch (IllegalArgumentException e) {
253         assertThat(e).hasMessage(format(
254           "Measure's ValueType (%s) is not consistent with the Metric's ValueType (%s)",
255           measure.getValueType(), metricType.getValueType()));
256       }
257     }
258   }
259
260   @Test
261   public void update_accepts_NO_VALUE_as_measure_arg() {
262     for (Metric.MetricType metricType : Metric.MetricType.values()) {
263       MetricImpl metric = new MetricImpl("1", "key" + metricType, "name" + metricType, metricType);
264       underTest.add(FILE_COMPONENT, metric, getSomeMeasureByValueType(metricType));
265       underTest.update(FILE_COMPONENT, metric, Measure.newMeasureBuilder().createNoValue());
266     }
267   }
268
269   private Measure getSomeMeasureByValueType(final Metric.MetricType metricType) {
270     return MEASURES.stream().filter(input -> input.getValueType() == metricType.getValueType()).findFirst().get();
271   }
272
273   @Test
274   public void update_supports_updating_to_the_same_value() {
275     underTest.add(FILE_COMPONENT, metric1, SOME_MEASURE);
276     underTest.update(FILE_COMPONENT, metric1, SOME_MEASURE);
277   }
278
279   @Test
280   public void update_updates_the_stored_value() {
281     Measure newMeasure = Measure.updatedMeasureBuilder(SOME_MEASURE).create();
282
283     underTest.add(FILE_COMPONENT, metric1, SOME_MEASURE);
284     underTest.update(FILE_COMPONENT, metric1, newMeasure);
285
286     assertThat(underTest.getRawMeasure(FILE_COMPONENT, metric1)).containsSame(newMeasure);
287   }
288
289   @Test
290   public void getRawMeasure_throws_NPE_without_reading_batch_report_if_component_arg_is_null() {
291     try {
292       underTestWithMock.getRawMeasure(null, metric1);
293       fail("an NPE should have been raised");
294     } catch (NullPointerException e) {
295       verifyNoMoreInteractions(mockBatchReportReader);
296     }
297   }
298
299   @Test
300   public void getRawMeasure_throws_NPE_without_reading_batch_report_if_metric_arg_is_null() {
301     try {
302       underTestWithMock.getRawMeasure(FILE_COMPONENT, null);
303       fail("an NPE should have been raised");
304     } catch (NullPointerException e) {
305       verifyNoMoreInteractions(mockBatchReportReader);
306     }
307   }
308
309   @Test
310   public void getRawMeasure_returns_measure_added_through_add_method() {
311     underTest.add(FILE_COMPONENT, metric1, SOME_MEASURE);
312
313     Optional<Measure> res = underTest.getRawMeasure(FILE_COMPONENT, metric1);
314
315     assertThat(res)
316       .isPresent()
317       .containsSame(SOME_MEASURE);
318
319     // make sure we really match on the specified component and metric
320     assertThat(underTest.getRawMeasure(OTHER_COMPONENT, metric1)).isNotPresent();
321     assertThat(underTest.getRawMeasure(FILE_COMPONENT, metric2)).isNotPresent();
322   }
323
324   @Test
325   public void getRawMeasure_returns_measure_from_batch_if_not_added_through_add_method() {
326     String value = "trololo";
327
328     when(reportMetricValidator.validate(METRIC_KEY_1)).thenReturn(true);
329
330     reportReader.putMeasures(FILE_COMPONENT.getReportAttributes().getRef(), ImmutableList.of(
331       ScannerReport.Measure.newBuilder().setMetricKey(METRIC_KEY_1).setStringValue(StringValue.newBuilder().setValue(value)).build()));
332
333     Optional<Measure> res = underTest.getRawMeasure(FILE_COMPONENT, metric1);
334
335     assertThat(res).isPresent();
336     assertThat(res.get().getStringValue()).isEqualTo(value);
337
338     // make sure we really match on the specified component and metric
339     assertThat(underTest.getRawMeasure(FILE_COMPONENT, metric2)).isNotPresent();
340     assertThat(underTest.getRawMeasure(OTHER_COMPONENT, metric1)).isNotPresent();
341   }
342
343   @Test
344   public void getRawMeasure_returns_only_validate_measure_from_batch_if_not_added_through_add_method() {
345     when(reportMetricValidator.validate(METRIC_KEY_1)).thenReturn(true);
346     when(reportMetricValidator.validate(METRIC_KEY_2)).thenReturn(false);
347
348     reportReader.putMeasures(FILE_COMPONENT.getReportAttributes().getRef(), ImmutableList.of(
349       ScannerReport.Measure.newBuilder().setMetricKey(METRIC_KEY_1).setStringValue(StringValue.newBuilder().setValue("value1")).build(),
350       ScannerReport.Measure.newBuilder().setMetricKey(METRIC_KEY_2).setStringValue(StringValue.newBuilder().setValue("value2")).build()));
351
352     assertThat(underTest.getRawMeasure(FILE_COMPONENT, metric1)).isPresent();
353     assertThat(underTest.getRawMeasure(FILE_COMPONENT, metric2)).isNotPresent();
354   }
355
356   @Test
357   public void getRawMeasure_retrieves_added_measure_over_batch_measure() {
358     when(reportMetricValidator.validate(METRIC_KEY_1)).thenReturn(true);
359     reportReader.putMeasures(FILE_COMPONENT.getReportAttributes().getRef(), ImmutableList.of(
360       ScannerReport.Measure.newBuilder().setMetricKey(METRIC_KEY_1).setStringValue(StringValue.newBuilder().setValue("some value")).build()));
361
362     Measure addedMeasure = SOME_MEASURE;
363     underTest.add(FILE_COMPONENT, metric1, addedMeasure);
364
365     Optional<Measure> res = underTest.getRawMeasure(FILE_COMPONENT, metric1);
366
367     assertThat(res)
368       .isPresent()
369       .containsSame(addedMeasure);
370   }
371
372   @Test
373   public void getRawMeasure_retrieves_measure_from_batch_and_caches_it_locally_so_that_it_can_be_updated() {
374     when(reportMetricValidator.validate(METRIC_KEY_1)).thenReturn(true);
375     reportReader.putMeasures(FILE_COMPONENT.getReportAttributes().getRef(), ImmutableList.of(
376       ScannerReport.Measure.newBuilder().setMetricKey(METRIC_KEY_1).setStringValue(StringValue.newBuilder().setValue("some value")).build()));
377
378     Optional<Measure> measure = underTest.getRawMeasure(FILE_COMPONENT, metric1);
379
380     underTest.update(FILE_COMPONENT, metric1, Measure.updatedMeasureBuilder(measure.get()).create());
381   }
382
383   @Test
384   public void getRawMeasures_returns_added_measures_over_batch_measures() {
385     when(reportMetricValidator.validate(METRIC_KEY_1)).thenReturn(true);
386     when(reportMetricValidator.validate(METRIC_KEY_2)).thenReturn(true);
387     ScannerReport.Measure batchMeasure1 = ScannerReport.Measure.newBuilder().setMetricKey(METRIC_KEY_1).setStringValue(StringValue.newBuilder().setValue("some value")).build();
388     ScannerReport.Measure batchMeasure2 = ScannerReport.Measure.newBuilder().setMetricKey(METRIC_KEY_2).setStringValue(StringValue.newBuilder().setValue("some value")).build();
389     reportReader.putMeasures(FILE_COMPONENT.getReportAttributes().getRef(), ImmutableList.of(batchMeasure1, batchMeasure2));
390
391     Measure addedMeasure = SOME_MEASURE;
392     underTest.add(FILE_COMPONENT, metric1, addedMeasure);
393
394     Map<String, Measure> rawMeasures = underTest.getRawMeasures(FILE_COMPONENT);
395
396     assertThat(rawMeasures.keySet()).hasSize(2);
397     assertThat(rawMeasures).containsEntry(METRIC_KEY_1, addedMeasure);
398     assertThat(rawMeasures.get(METRIC_KEY_2)).extracting(Measure::getStringValue).isEqualTo("some value");
399   }
400
401   private static MeasureDto createMeasureDto(String metricUuid, String componentUuid, String analysisUuid) {
402     return new MeasureDto()
403       .setComponentUuid(componentUuid)
404       .setAnalysisUuid(analysisUuid)
405       .setData(SOME_DATA)
406       .setMetricUuid(metricUuid);
407   }
408 }