diff options
author | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2015-08-14 10:42:05 +0200 |
---|---|---|
committer | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2015-08-24 14:00:31 +0200 |
commit | 1d4769cd6fa1e0efad4b83d57581c535a1fab7a2 (patch) | |
tree | c32f423915b3be6edfd0483aee99a943d9632825 | |
parent | bd01fdc61798dcacd76d0963888a91f20b437507 (diff) | |
download | sonarqube-1d4769cd6fa1e0efad4b83d57581c535a1fab7a2.tar.gz sonarqube-1d4769cd6fa1e0efad4b83d57581c535a1fab7a2.zip |
create delegate for Map based impl of MeasureRepository
allows to share the code with Views plugin
3 files changed, 556 insertions, 114 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MapBasedRawMeasureRepository.java b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MapBasedRawMeasureRepository.java new file mode 100644 index 00000000000..c1a82cd5dfb --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MapBasedRawMeasureRepository.java @@ -0,0 +1,194 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.computation.measure; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableSetMultimap; +import com.google.common.collect.SetMultimap; +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Nullable; +import org.sonar.db.rule.RuleDto; +import org.sonar.server.computation.component.Component; +import org.sonar.server.computation.debt.Characteristic; +import org.sonar.server.computation.metric.Metric; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.lang.String.format; +import static java.util.Objects.requireNonNull; + +/** + * Map based implementation of MeasureRepository which supports only raw measures. + * + * Intended to be used as a delegate of other MeasureRepository implementations (hence the final keyword). + */ +public final class MapBasedRawMeasureRepository<T> implements MeasureRepository { + private final Function<Component, T> componentToKey; + private final Map<T, Map<MeasureKey, Measure>> measures = new HashMap<>(); + + public MapBasedRawMeasureRepository(Function<Component, T> componentToKey) { + this.componentToKey = requireNonNull(componentToKey); + } + + /** + * @throws UnsupportedOperationException all the time, not supported + */ + @Override + public Optional<Measure> getBaseMeasure(Component component, Metric metric) { + throw new UnsupportedOperationException("This implementation of MeasureRepository supports only raw measures"); + } + + @Override + public Optional<Measure> getRawMeasure(final Component component, final Metric metric) { + // fail fast + requireNonNull(component); + requireNonNull(metric); + + return find(component, metric, null, null); + } + + @Override + public Optional<Measure> getRawMeasure(Component component, Metric metric, RuleDto rule) { + // fail fast + requireNonNull(component); + requireNonNull(metric); + requireNonNull(rule); + + return find(component, metric, rule, null); + } + + @Override + public Optional<Measure> getRawMeasure(Component component, Metric metric, Characteristic characteristic) { + // fail fast + requireNonNull(component); + requireNonNull(metric); + requireNonNull(characteristic); + + return find(component, metric, null, characteristic); + } + + @Override + public void add(Component component, Metric metric, Measure measure) { + requireNonNull(component); + checkValueTypeConsistency(metric, measure); + + Optional<Measure> existingMeasure = find(component, metric, measure); + if (existingMeasure.isPresent()) { + throw new UnsupportedOperationException( + format( + "a measure can be set only once for a specific Component (key=%s), Metric (key=%s)%s. Use update method", + component.getKey(), + metric.getKey(), + buildRuleOrCharacteristicMsgPart(measure))); + } + add(component, metric, measure, OverridePolicy.OVERRIDE); + } + + @Override + public void update(Component component, Metric metric, Measure measure) { + requireNonNull(component); + checkValueTypeConsistency(metric, measure); + + Optional<Measure> existingMeasure = find(component, metric, measure); + if (!existingMeasure.isPresent()) { + throw new UnsupportedOperationException( + format( + "a measure can be updated only if one already exists for a specific Component (key=%s), Metric (key=%s)%s. Use add method", + component.getKey(), + metric.getKey(), + buildRuleOrCharacteristicMsgPart(measure))); + } + add(component, metric, measure, OverridePolicy.OVERRIDE); + } + + private static void checkValueTypeConsistency(Metric metric, Measure measure) { + checkArgument( + measure.getValueType() == Measure.ValueType.NO_VALUE || measure.getValueType() == metric.getType().getValueType(), + format( + "Measure's ValueType (%s) is not consistent with the Metric's ValueType (%s)", + measure.getValueType(), metric.getType().getValueType())); + } + + private static String buildRuleOrCharacteristicMsgPart(Measure measure) { + if (measure.getRuleId() != null) { + return " and rule (id=" + measure.getRuleId() + ")"; + } + if (measure.getCharacteristicId() != null) { + return " and Characteristic (id=" + measure.getCharacteristicId() + ")"; + } + return ""; + } + + @Override + public SetMultimap<String, Measure> getRawMeasures(Component component) { + T componentKey = componentToKey.apply(component); + Map<MeasureKey, Measure> rawMeasures = measures.get(componentKey); + if (rawMeasures == null) { + return ImmutableSetMultimap.of(); + } + + ImmutableSetMultimap.Builder<String, Measure> builder = ImmutableSetMultimap.builder(); + for (Map.Entry<MeasureKey, Measure> entry : rawMeasures.entrySet()) { + builder.put(entry.getKey().getMetricKey(), entry.getValue()); + } + return builder.build(); + } + + private Optional<Measure> find(Component component, Metric metric, @Nullable RuleDto rule, @Nullable Characteristic characteristic) { + T componentKey = componentToKey.apply(component); + Map<MeasureKey, Measure> measuresPerMetric = measures.get(componentKey); + if (measuresPerMetric == null) { + return Optional.absent(); + } + return Optional.fromNullable(measuresPerMetric.get(new MeasureKey(metric.getKey(), rule, characteristic))); + } + + private Optional<Measure> find(Component component, Metric metric, Measure measure) { + T componentKey = componentToKey.apply(component); + Map<MeasureKey, Measure> measuresPerMetric = measures.get(componentKey); + if (measuresPerMetric == null) { + return Optional.absent(); + } + return Optional.fromNullable(measuresPerMetric.get(new MeasureKey(metric.getKey(), measure.getRuleId(), measure.getCharacteristicId()))); + } + + public void add(Component component, Metric metric, Measure measure, OverridePolicy overridePolicy) { + requireNonNull(component); + requireNonNull(measure); + requireNonNull(measure); + requireNonNull(overridePolicy); + + T componentKey = componentToKey.apply(component); + Map<MeasureKey, Measure> measuresPerMetric = measures.get(componentKey); + if (measuresPerMetric == null) { + measuresPerMetric = new HashMap<>(); + measures.put(componentKey, measuresPerMetric); + } + MeasureKey key = new MeasureKey(metric.getKey(), measure.getRuleId(), measure.getCharacteristicId()); + if (!measuresPerMetric.containsKey(key) || overridePolicy == OverridePolicy.OVERRIDE) { + measuresPerMetric.put(key, measure); + } + } + + public enum OverridePolicy { + OVERRIDE, DO_NOT_OVERRIDE + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureRepositoryImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureRepositoryImpl.java index 4a921fcd32e..417fbbcf43e 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureRepositoryImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureRepositoryImpl.java @@ -19,14 +19,11 @@ */ package org.sonar.server.computation.measure; +import com.google.common.base.Function; import com.google.common.base.Optional; -import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.SetMultimap; -import java.util.HashMap; import java.util.HashSet; -import java.util.Map; import java.util.Set; -import javax.annotation.Nullable; import org.sonar.batch.protocol.output.BatchReport; import org.sonar.core.util.CloseableIterator; import org.sonar.db.DbClient; @@ -36,15 +33,20 @@ import org.sonar.db.rule.RuleDto; import org.sonar.server.computation.batch.BatchReportReader; import org.sonar.server.computation.component.Component; import org.sonar.server.computation.debt.Characteristic; +import org.sonar.server.computation.measure.MapBasedRawMeasureRepository.OverridePolicy; import org.sonar.server.computation.metric.Metric; import org.sonar.server.computation.metric.MetricRepository; import org.sonar.server.computation.metric.ReportMetricValidator; -import static com.google.common.base.Preconditions.checkArgument; -import static java.lang.String.format; import static java.util.Objects.requireNonNull; public class MeasureRepositoryImpl implements MeasureRepository { + private final MapBasedRawMeasureRepository<Integer> delegate = new MapBasedRawMeasureRepository<>(new Function<Component, Integer>() { + @Override + public Integer apply(Component o) { + return o.getReportAttributes().getRef(); + } + }); private final DbClient dbClient; private final BatchReportReader reportReader; private final BatchMeasureToMeasure batchMeasureToMeasure; @@ -53,7 +55,6 @@ public class MeasureRepositoryImpl implements MeasureRepository { private final MeasureDtoToMeasure measureDtoToMeasure = new MeasureDtoToMeasure(); private final Set<Integer> loadedComponents = new HashSet<>(); - private final Map<Integer, Map<MeasureKey, Measure>> measures = new HashMap<>(); public MeasureRepositoryImpl(DbClient dbClient, BatchReportReader reportReader, MetricRepository metricRepository, ReportMetricValidator reportMetricValidator) { this.dbClient = dbClient; @@ -77,107 +78,40 @@ public class MeasureRepositoryImpl implements MeasureRepository { @Override public Optional<Measure> getRawMeasure(final Component component, final Metric metric) { - // fail fast - requireNonNull(component); - requireNonNull(metric); - - Optional<Measure> local = findLocal(component, metric, null, null); + Optional<Measure> local = delegate.getRawMeasure(component, metric); if (local.isPresent()) { return local; } // look up in batch after loading (if not yet loaded) measures from batch loadBatchMeasuresForComponent(component); - return findLocal(component, metric, null, null); + return delegate.getRawMeasure(component, metric); } @Override public Optional<Measure> getRawMeasure(Component component, Metric metric, RuleDto rule) { - // fail fast - requireNonNull(component); - requireNonNull(metric); - requireNonNull(rule); - - return findLocal(component, metric, rule, null); + return delegate.getRawMeasure(component, metric, rule); } @Override public Optional<Measure> getRawMeasure(Component component, Metric metric, Characteristic characteristic) { - // fail fast - requireNonNull(component); - requireNonNull(metric); - requireNonNull(characteristic); - - return findLocal(component, metric, null, characteristic); + return delegate.getRawMeasure(component, metric, characteristic); } @Override public void add(Component component, Metric metric, Measure measure) { - requireNonNull(component); - checkValueTypeConsistency(metric, measure); - - Optional<Measure> existingMeasure = findLocal(component, metric, measure); - if (existingMeasure.isPresent()) { - throw new UnsupportedOperationException( - format( - "a measure can be set only once for a specific Component (key=%s), Metric (key=%s)%s. Use update method", - component.getKey(), - metric.getKey(), - buildRuleOrCharacteristicMsgPart(measure) - )); - } - addLocal(component, metric, measure, OverridePolicy.OVERRIDE); + delegate.add(component, metric, measure); } @Override public void update(Component component, Metric metric, Measure measure) { - requireNonNull(component); - checkValueTypeConsistency(metric, measure); - - Optional<Measure> existingMeasure = findLocal(component, metric, measure); - if (!existingMeasure.isPresent()) { - throw new UnsupportedOperationException( - format( - "a measure can be updated only if one already exists for a specific Component (key=%s), Metric (key=%s)%s. Use add method", - component.getKey(), - metric.getKey(), - buildRuleOrCharacteristicMsgPart(measure) - )); - } - addLocal(component, metric, measure, OverridePolicy.OVERRIDE); - } - - private static void checkValueTypeConsistency(Metric metric, Measure measure) { - checkArgument( - measure.getValueType() == Measure.ValueType.NO_VALUE || measure.getValueType() == metric.getType().getValueType(), - format( - "Measure's ValueType (%s) is not consistent with the Metric's ValueType (%s)", - measure.getValueType(), metric.getType().getValueType())); - } - - private static String buildRuleOrCharacteristicMsgPart(Measure measure) { - if (measure.getRuleId() != null) { - return " and rule (id=" + measure.getRuleId() + ")"; - } - if (measure.getCharacteristicId() != null) { - return " and Characteristic (id=" + measure.getCharacteristicId() + ")"; - } - return ""; + delegate.update(component, metric, measure); } @Override public SetMultimap<String, Measure> getRawMeasures(Component component) { loadBatchMeasuresForComponent(component); - Map<MeasureKey, Measure> rawMeasures = measures.get(component.getReportAttributes().getRef()); - if (rawMeasures == null) { - return ImmutableSetMultimap.of(); - } - - ImmutableSetMultimap.Builder<String, Measure> builder = ImmutableSetMultimap.builder(); - for (Map.Entry<MeasureKey, Measure> entry : rawMeasures.entrySet()) { - builder.put(entry.getKey().getMetricKey(), entry.getValue()); - } - return builder.build(); + return delegate.getRawMeasures(component); } private void loadBatchMeasuresForComponent(Component component) { @@ -191,43 +125,11 @@ public class MeasureRepositoryImpl implements MeasureRepository { String metricKey = batchMeasure.getMetricKey(); if (reportMetricValidator.validate(metricKey)) { Metric metric = metricRepository.getByKey(metricKey); - addLocal(component, metric, batchMeasureToMeasure.toMeasure(batchMeasure, metric).get(), OverridePolicy.DO_NOT_OVERRIDE); + delegate.add(component, metric, batchMeasureToMeasure.toMeasure(batchMeasure, metric).get(), OverridePolicy.DO_NOT_OVERRIDE); } } } loadedComponents.add(component.getReportAttributes().getRef()); } - private Optional<Measure> findLocal(Component component, Metric metric, - @Nullable RuleDto rule, @Nullable Characteristic characteristic) { - Map<MeasureKey, Measure> measuresPerMetric = measures.get(component.getReportAttributes().getRef()); - if (measuresPerMetric == null) { - return Optional.absent(); - } - return Optional.fromNullable(measuresPerMetric.get(new MeasureKey(metric.getKey(), rule, characteristic))); - } - - private Optional<Measure> findLocal(Component component, Metric metric, Measure measure) { - Map<MeasureKey, Measure> measuresPerMetric = measures.get(component.getReportAttributes().getRef()); - if (measuresPerMetric == null) { - return Optional.absent(); - } - return Optional.fromNullable(measuresPerMetric.get(new MeasureKey(metric.getKey(), measure.getRuleId(), measure.getCharacteristicId()))); - } - - private void addLocal(Component component, Metric metric, Measure measure, OverridePolicy overridePolicy) { - Map<MeasureKey, Measure> measuresPerMetric = measures.get(component.getReportAttributes().getRef()); - if (measuresPerMetric == null) { - measuresPerMetric = new HashMap<>(); - measures.put(component.getReportAttributes().getRef(), measuresPerMetric); - } - MeasureKey key = new MeasureKey(metric.getKey(), measure.getRuleId(), measure.getCharacteristicId()); - if (!measuresPerMetric.containsKey(key) || overridePolicy == OverridePolicy.OVERRIDE) { - measuresPerMetric.put(key, measure); - } - } - - private enum OverridePolicy { - OVERRIDE, DO_NOT_OVERRIDE - } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MapBasedRawMeasureRepositoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MapBasedRawMeasureRepositoryTest.java new file mode 100644 index 00000000000..3c1ef09111b --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MapBasedRawMeasureRepositoryTest.java @@ -0,0 +1,346 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.computation.measure; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableList; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.sonar.api.rule.RuleKey; +import org.sonar.api.utils.System2; +import org.sonar.db.DbClient; +import org.sonar.db.DbTester; +import org.sonar.db.rule.RuleDto; +import org.sonar.server.computation.batch.BatchReportReader; +import org.sonar.server.computation.component.Component; +import org.sonar.server.computation.component.ReportComponent; +import org.sonar.server.computation.debt.Characteristic; +import org.sonar.server.computation.metric.Metric; +import org.sonar.server.computation.metric.MetricImpl; +import org.sonar.server.computation.metric.MetricRepository; +import org.sonar.server.computation.metric.ReportMetricValidator; + +import static com.google.common.collect.FluentIterable.from; +import static java.lang.String.format; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.guava.api.Assertions.assertThat; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +@RunWith(DataProviderRunner.class) +public class MapBasedRawMeasureRepositoryTest { + @Rule + public DbTester dbTester = DbTester.create(System2.INSTANCE); + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private static final String FILE_COMPONENT_KEY = "file cpt key"; + private static final ReportComponent FILE_COMPONENT = ReportComponent.builder(Component.Type.FILE, 1).setKey(FILE_COMPONENT_KEY).build(); + private static final ReportComponent OTHER_COMPONENT = ReportComponent.builder(Component.Type.FILE, 2).setKey("some other key").build(); + private static final String METRIC_KEY_1 = "metric 1"; + private static final String METRIC_KEY_2 = "metric 2"; + private final Metric metric1 = mock(Metric.class); + private final Metric metric2 = mock(Metric.class); + private static final Measure SOME_MEASURE = Measure.newMeasureBuilder().create("some value"); + private static final RuleDto SOME_RULE = RuleDto.createFor(RuleKey.of("A", "1")).setId(963); + private static final Characteristic SOME_CHARACTERISTIC = new Characteristic(741, "key", null); + + private ReportMetricValidator reportMetricValidator = mock(ReportMetricValidator.class); + + private MetricRepository metricRepository = mock(MetricRepository.class); + private MapBasedRawMeasureRepository<Integer> underTest = new MapBasedRawMeasureRepository<>(new Function<Component, Integer>() { + @Override + public Integer apply(Component component) { + return component.getReportAttributes().getRef(); + } + }); + + private DbClient mockedDbClient = mock(DbClient.class); + private BatchReportReader mockBatchReportReader = mock(BatchReportReader.class); + private MeasureRepositoryImpl underTestWithMock = new MeasureRepositoryImpl(mockedDbClient, mockBatchReportReader, metricRepository, reportMetricValidator); + + @Before + public void setUp() { + when(metric1.getKey()).thenReturn(METRIC_KEY_1); + when(metric1.getType()).thenReturn(Metric.MetricType.STRING); + when(metric2.getKey()).thenReturn(METRIC_KEY_2); + when(metric2.getType()).thenReturn(Metric.MetricType.STRING); + + // references to metrics are consistent with DB by design + when(metricRepository.getByKey(METRIC_KEY_1)).thenReturn(metric1); + when(metricRepository.getByKey(METRIC_KEY_2)).thenReturn(metric2); + } + + @Test(expected = NullPointerException.class) + public void add_throws_NPE_if_Component_argument_is_null() { + underTest.add(null, metric1, SOME_MEASURE); + } + + @Test(expected = NullPointerException.class) + public void add_throws_NPE_if_Component_metric_is_null() { + underTest.add(FILE_COMPONENT, null, SOME_MEASURE); + } + + @Test(expected = NullPointerException.class) + public void add_throws_NPE_if_Component_measure_is_null() { + underTest.add(FILE_COMPONENT, metric1, null); + } + + @Test(expected = UnsupportedOperationException.class) + public void add_throws_UOE_if_measure_already_exists() { + underTest.add(FILE_COMPONENT, metric1, SOME_MEASURE); + underTest.add(FILE_COMPONENT, metric1, SOME_MEASURE); + } + + @Test(expected = NullPointerException.class) + public void update_throws_NPE_if_Component_argument_is_null() { + underTest.update(null, metric1, SOME_MEASURE); + } + + @Test(expected = NullPointerException.class) + public void update_throws_NPE_if_Component_metric_is_null() { + underTest.update(FILE_COMPONENT, null, SOME_MEASURE); + } + + @Test(expected = NullPointerException.class) + public void update_throws_NPE_if_Component_measure_is_null() { + underTest.update(FILE_COMPONENT, metric1, null); + } + + @Test(expected = UnsupportedOperationException.class) + public void update_throws_UOE_if_measure_does_not_exists() { + underTest.update(FILE_COMPONENT, metric1, SOME_MEASURE); + } + + private static final List<Measure> MEASURES = ImmutableList.of( + Measure.newMeasureBuilder().create(1), + Measure.newMeasureBuilder().create(1l), + Measure.newMeasureBuilder().create(1d), + Measure.newMeasureBuilder().create(true), + Measure.newMeasureBuilder().create(false), + Measure.newMeasureBuilder().create("sds"), + Measure.newMeasureBuilder().create(Measure.Level.OK), + Measure.newMeasureBuilder().createNoValue() + ); + + @DataProvider + public static Object[][] measures() { + return from(MEASURES).transform(new Function<Measure, Object[]>() { + @Nullable + @Override + public Object[] apply(Measure input) { + return new Measure[] {input}; + } + }).toArray(Object[].class); + } + + @Test + public void add_accepts_NO_VALUE_as_measure_arg() { + for (Metric.MetricType metricType : Metric.MetricType.values()) { + underTest.add(FILE_COMPONENT, new MetricImpl(1, "key" + metricType, "name" + metricType, metricType), Measure.newMeasureBuilder().createNoValue()); + } + } + + @Test + @UseDataProvider("measures") + public void update_throws_IAE_if_valueType_of_Measure_is_not_the_same_as_the_Metric_valueType_unless_NO_VALUE(Measure measure) { + for (Metric.MetricType metricType : Metric.MetricType.values()) { + if (metricType.getValueType() == measure.getValueType() || measure.getValueType() == Measure.ValueType.NO_VALUE) { + continue; + } + + try { + final MetricImpl metric = new MetricImpl(1, "key" + metricType, "name" + metricType, metricType); + underTest.add(FILE_COMPONENT, metric, getSomeMeasureByValueType(metricType)); + underTest.update(FILE_COMPONENT, metric, measure); + fail("An IllegalArgumentException should have been raised"); + } catch (IllegalArgumentException e) { + assertThat(e).hasMessage(format( + "Measure's ValueType (%s) is not consistent with the Metric's ValueType (%s)", + measure.getValueType(), metricType.getValueType())); + } + } + } + + @Test + public void update_accepts_NO_VALUE_as_measure_arg() { + for (Metric.MetricType metricType : Metric.MetricType.values()) { + MetricImpl metric = new MetricImpl(1, "key" + metricType, "name" + metricType, metricType); + underTest.add(FILE_COMPONENT, metric, getSomeMeasureByValueType(metricType)); + underTest.update(FILE_COMPONENT, metric, Measure.newMeasureBuilder().createNoValue()); + } + } + + private Measure getSomeMeasureByValueType(final Metric.MetricType metricType) { + return from(MEASURES).filter(new Predicate<Measure>() { + @Override + public boolean apply(@Nonnull Measure input) { + return input.getValueType() == metricType.getValueType(); + } + }).first().get(); + } + + @Test + public void update_supports_updating_to_the_same_value() { + underTest.add(FILE_COMPONENT, metric1, SOME_MEASURE); + underTest.update(FILE_COMPONENT, metric1, SOME_MEASURE); + } + + @Test + public void update_updates_the_stored_value() { + Measure newMeasure = Measure.updatedMeasureBuilder(SOME_MEASURE).create(); + + underTest.add(FILE_COMPONENT, metric1, SOME_MEASURE); + underTest.update(FILE_COMPONENT, metric1, newMeasure); + + assertThat(underTest.getRawMeasure(FILE_COMPONENT, metric1).get()).isSameAs(newMeasure); + } + + @Test + public void update_updates_the_stored_value_for_rule() { + Measure initialMeasure = Measure.newMeasureBuilder().forRule(123).createNoValue(); + Measure newMeasure = Measure.updatedMeasureBuilder(initialMeasure).create(); + + underTest.add(FILE_COMPONENT, metric1, initialMeasure); + underTest.update(FILE_COMPONENT, metric1, newMeasure); + + assertThat(underTest.getRawMeasures(FILE_COMPONENT).get(metric1.getKey()).iterator().next()).isSameAs(newMeasure); + } + + @Test + public void update_updates_the_stored_value_for_characteristic() { + Measure initialMeasure = Measure.newMeasureBuilder().forCharacteristic(952).createNoValue(); + Measure newMeasure = Measure.updatedMeasureBuilder(initialMeasure).create(); + + underTest.add(FILE_COMPONENT, metric1, initialMeasure); + underTest.update(FILE_COMPONENT, metric1, newMeasure); + + assertThat(underTest.getRawMeasures(FILE_COMPONENT).get(metric1.getKey()).iterator().next()).isSameAs(newMeasure); + } + + @Test + public void getRawMeasure_throws_NPE_without_reading_batch_report_if_component_arg_is_null() { + try { + underTestWithMock.getRawMeasure(null, metric1); + fail("an NPE should have been raised"); + } catch (NullPointerException e) { + verifyNoMoreInteractions(mockBatchReportReader); + } + } + + @Test + public void getRawMeasure_throws_NPE_without_reading_batch_report_if_metric_arg_is_null() { + try { + underTestWithMock.getRawMeasure(FILE_COMPONENT, null); + fail("an NPE should have been raised"); + } catch (NullPointerException e) { + verifyNoMoreInteractions(mockBatchReportReader); + } + } + + @Test + public void getRawMeasure_returns_measure_added_through_add_method() { + underTest.add(FILE_COMPONENT, metric1, SOME_MEASURE); + + Optional<Measure> res = underTest.getRawMeasure(FILE_COMPONENT, metric1); + + assertThat(res).isPresent(); + assertThat(res.get()).isSameAs(SOME_MEASURE); + + // make sure we really match on the specified component and metric + assertThat(underTest.getRawMeasure(OTHER_COMPONENT, metric1)).isAbsent(); + assertThat(underTest.getRawMeasure(FILE_COMPONENT, metric2)).isAbsent(); + } + + @Test(expected = NullPointerException.class) + public void getRawMeasure_for_rule_throws_NPE_if_Component_arg_is_null() { + underTest.getRawMeasure(null, metric1, SOME_RULE); + } + + @Test(expected = NullPointerException.class) + public void getRawMeasure_for_rule_throws_NPE_if_Metric_arg_is_null() { + underTest.getRawMeasure(FILE_COMPONENT, null, SOME_RULE); + } + + @Test(expected = NullPointerException.class) + public void getRawMeasure_for_rule_throws_NPE_if_Characteristic_arg_is_null() { + underTest.getRawMeasure(FILE_COMPONENT, metric1, (RuleDto) null); + } + + @Test + public void getRawMeasure_for_rule_returns_absent_if_repository_is_empty() { + assertThat(underTest.getRawMeasure(FILE_COMPONENT, metric1, SOME_RULE)).isAbsent(); + } + + @Test + public void getRawMeasure_for_rule_returns_measure_for_specified_rule() { + Measure measure = Measure.newMeasureBuilder().forRule(SOME_RULE.getId()).createNoValue(); + + underTest.add(FILE_COMPONENT, metric1, measure); + underTest.add(FILE_COMPONENT, metric1, Measure.newMeasureBuilder().forRule(222).createNoValue()); + + assertThat(underTest.getRawMeasure(FILE_COMPONENT, metric1, SOME_RULE).get()).isSameAs(measure); + } + + @Test(expected = NullPointerException.class) + public void getRawMeasure_for_characteristic_throws_NPE_if_Component_arg_is_null() { + underTest.getRawMeasure(null, metric1, SOME_CHARACTERISTIC); + } + + @Test(expected = NullPointerException.class) + public void getRawMeasure_for_characteristic_throws_NPE_if_Metric_arg_is_null() { + underTest.getRawMeasure(FILE_COMPONENT, null, SOME_CHARACTERISTIC); + } + + @Test(expected = NullPointerException.class) + public void getRawMeasure_for_characteristic_throws_NPE_if_Characteristic_arg_is_null() { + underTest.getRawMeasure(FILE_COMPONENT, metric1, (Characteristic) null); + } + + @Test + public void getRawMeasure_for_characteristic_returns_absent_if_repository_is_empty() { + assertThat(underTest.getRawMeasure(FILE_COMPONENT, metric1, SOME_CHARACTERISTIC)).isAbsent(); + } + + @Test + public void getRawMeasure_for_characteristic_returns_measure_for_specified_rule() { + when(reportMetricValidator.validate(metric1.getKey())).thenReturn(true); + Measure measure = Measure.newMeasureBuilder().forCharacteristic(SOME_CHARACTERISTIC.getId()).createNoValue(); + + underTest.add(FILE_COMPONENT, metric1, measure); + underTest.add(FILE_COMPONENT, metric1, Measure.newMeasureBuilder().forCharacteristic(333).createNoValue()); + + assertThat(underTest.getRawMeasure(FILE_COMPONENT, metric1, SOME_CHARACTERISTIC).get()).isSameAs(measure); + } + +} |