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