diff options
11 files changed, 499 insertions, 41 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java index bf03be56377..ebd3a564caf 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java @@ -29,10 +29,9 @@ import org.picocontainer.lifecycle.ReflectionLifecycleStrategy; import org.picocontainer.monitors.NullComponentMonitor; import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Profiler; -import org.sonar.core.platform.Module; -import org.sonar.server.computation.issue.UpdateConflictResolver; import org.sonar.core.issue.tracking.Tracker; import org.sonar.core.platform.ComponentContainer; +import org.sonar.core.platform.Module; import org.sonar.server.computation.ComputationService; import org.sonar.server.computation.ReportQueue; import org.sonar.server.computation.activity.ActivityManager; @@ -63,10 +62,11 @@ import org.sonar.server.computation.issue.ScmAccountToUserLoader; import org.sonar.server.computation.issue.TrackerBaseInputFactory; import org.sonar.server.computation.issue.TrackerExecution; import org.sonar.server.computation.issue.TrackerRawInputFactory; +import org.sonar.server.computation.issue.UpdateConflictResolver; import org.sonar.server.computation.language.LanguageRepositoryImpl; import org.sonar.server.computation.measure.MeasureRepositoryImpl; import org.sonar.server.computation.measure.newcoverage.NewCoverageMetricKeysModule; -import org.sonar.server.computation.metric.MetricRepositoryImpl; +import org.sonar.server.computation.metric.MetricModule; import org.sonar.server.computation.period.PeriodsHolderImpl; import org.sonar.server.computation.qualitygate.EvaluationResultTextConverterImpl; import org.sonar.server.computation.qualitygate.QualityGateHolderImpl; @@ -143,6 +143,8 @@ public class ComputeEngineContainerImpl extends ComponentContainer implements Co return Arrays.asList( ActivityManager.class, + MetricModule.class, + // holders BatchReportDirectoryHolderImpl.class, TreeRootHolderImpl.class, @@ -155,7 +157,6 @@ public class ComputeEngineContainerImpl extends ComponentContainer implements Co // repositories LanguageRepositoryImpl.class, - MetricRepositoryImpl.class, MeasureRepositoryImpl.class, EventRepositoryImpl.class, ProjectSettingsRepository.class, 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 4a180c4655b..04b5fa46cb2 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 @@ -37,6 +37,7 @@ import org.sonar.server.computation.component.Component; import org.sonar.server.computation.debt.Characteristic; 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; @@ -47,13 +48,16 @@ public class MeasureRepositoryImpl implements MeasureRepository { private final BatchReportReader reportReader; private final BatchMeasureToMeasure batchMeasureToMeasure; private final MetricRepository metricRepository; + private final ReportMetricValidator reportMetricValidator; + 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) { + public MeasureRepositoryImpl(DbClient dbClient, BatchReportReader reportReader, MetricRepository metricRepository, ReportMetricValidator reportMetricValidator) { this.dbClient = dbClient; this.reportReader = reportReader; + this.reportMetricValidator = reportMetricValidator; this.batchMeasureToMeasure = new BatchMeasureToMeasure(); this.metricRepository = metricRepository; } @@ -181,8 +185,11 @@ public class MeasureRepositoryImpl implements MeasureRepository { } for (BatchReport.Measure batchMeasure : reportReader.readComponentMeasures(component.getRef())) { - Metric metric = metricRepository.getByKey(batchMeasure.getMetricKey()); - addLocal(component, metric, batchMeasureToMeasure.toMeasure(batchMeasure, metric).get(), OverridePolicy.DO_NOT_OVERRIDE); + 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); + } } loadedComponents.add(component.getRef()); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricModule.java b/server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricModule.java new file mode 100644 index 00000000000..becdb49bff3 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricModule.java @@ -0,0 +1,34 @@ +/* + * 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.metric; + +import org.sonar.core.metric.SensorMetrics; +import org.sonar.core.platform.Module; + +public class MetricModule extends Module { + @Override + protected void configureModule() { + add( + SensorMetrics.class, + ReportMetricValidatorImpl.class, + MetricRepositoryImpl.class); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/metric/ReportMetricValidator.java b/server/sonar-server/src/main/java/org/sonar/server/computation/metric/ReportMetricValidator.java new file mode 100644 index 00000000000..e5c66fee0d3 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/metric/ReportMetricValidator.java @@ -0,0 +1,30 @@ +/* + * 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.metric; + +/** + * Validate metric to know if it can be read from the batch + */ +public interface ReportMetricValidator { + + boolean validate(String metricKey); + +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/metric/ReportMetricValidatorImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/metric/ReportMetricValidatorImpl.java new file mode 100644 index 00000000000..851dc8ae93f --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/metric/ReportMetricValidatorImpl.java @@ -0,0 +1,67 @@ +/* + * 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.metric; + +import com.google.common.base.Function; +import com.google.common.collect.FluentIterable; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; +import org.sonar.core.metric.SensorMetrics; + +public class ReportMetricValidatorImpl implements ReportMetricValidator { + + private static final Logger LOG = Loggers.get(ReportMetricValidatorImpl.class); + + private Map<String, org.sonar.api.measures.Metric> metricByKey; + private Set<String> alreadyLoggedMetricKeys = new HashSet<>(); + + public ReportMetricValidatorImpl(SensorMetrics sensorMetrics) { + this.metricByKey = FluentIterable.from(sensorMetrics.getMetrics()).uniqueIndex(MetricToKey.INSTANCE); + } + + @Override + public boolean validate(String metricKey) { + org.sonar.api.measures.Metric metric = metricByKey.get(metricKey); + if (metric == null) { + if (!alreadyLoggedMetricKeys.contains(metricKey)) { + LOG.warn("The metric '{}' is ignored and should not be send in the batch report", metricKey); + alreadyLoggedMetricKeys.add(metricKey); + } + return false; + } + return true; + } + + private enum MetricToKey implements Function<org.sonar.api.measures.Metric, String> { + INSTANCE; + + @Nullable + @Override + public String apply(@Nonnull org.sonar.api.measures.Metric input) { + return input.key(); + } + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistMeasuresStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistMeasuresStep.java index 263517c5349..a6f6c47e552 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistMeasuresStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistMeasuresStep.java @@ -29,8 +29,9 @@ import java.util.List; import java.util.Map; import javax.annotation.Nonnull; import org.sonar.api.measures.CoreMetrics; -import org.sonar.db.measure.MeasureDto; +import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.measure.MeasureDto; import org.sonar.server.computation.component.Component; import org.sonar.server.computation.component.DbIdsRepository; import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor; @@ -41,7 +42,6 @@ import org.sonar.server.computation.measure.MeasureRepository; import org.sonar.server.computation.measure.MeasureToMeasureDto; import org.sonar.server.computation.metric.Metric; import org.sonar.server.computation.metric.MetricRepository; -import org.sonar.db.DbClient; import static com.google.common.collect.FluentIterable.from; import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER; @@ -49,12 +49,7 @@ import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ public class PersistMeasuresStep implements ComputationStep { /** - * List of metrics that should not be received from the report, as they should only be fed by the compute engine - */ - private static final List<String> FORBIDDEN_METRIC_KEYS = ImmutableList.of(CoreMetrics.DUPLICATIONS_DATA_KEY); - - /** - * List of metrics that should be persisted on file measure (Waiting for SONAR-6688 to be implemented) + * List of metrics that should not be persisted on file measure (Waiting for SONAR-6688 to be implemented) */ private static final List<String> NOT_TO_PERSIST_ON_FILE_METRIC_KEYS = ImmutableList.of( CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION_KEY, @@ -112,9 +107,6 @@ public class PersistMeasuresStep implements ComputationStep { private void persistMeasures(Component component, Multimap<String, Measure> batchReportMeasures, long componentId, long snapshotId) { for (Map.Entry<String, Collection<Measure>> measures : batchReportMeasures.asMap().entrySet()) { String metricKey = measures.getKey(); - if (FORBIDDEN_METRIC_KEYS.contains(metricKey)) { - throw new IllegalStateException(String.format("Measures on metric '%s' cannot be send in the report", metricKey)); - } if (NOT_TO_PERSIST_ON_FILE_METRIC_KEYS.contains(metricKey) && component.getType() == Component.Type.FILE) { continue; } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureRepositoryImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureRepositoryImplTest.java index 114c1305c84..d5d704afd3a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureRepositoryImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureRepositoryImplTest.java @@ -53,6 +53,7 @@ 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 org.sonar.server.db.DbClient; import org.sonar.server.metric.persistence.MetricDao; @@ -90,13 +91,15 @@ public class MeasureRepositoryImplTest { 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 DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new MeasureDao(), new SnapshotDao(), new MetricDao(), new ComponentDao()); private MetricRepository metricRepository = mock(MetricRepository.class); - private MeasureRepositoryImpl underTest = new MeasureRepositoryImpl(dbClient, reportReader, metricRepository); + private MeasureRepositoryImpl underTest = new MeasureRepositoryImpl(dbClient, reportReader, metricRepository, reportMetricValidator); private DbClient mockedDbClient = mock(DbClient.class); private BatchReportReader mockBatchReportReader = mock(BatchReportReader.class); - private MeasureRepositoryImpl underTestWithMock = new MeasureRepositoryImpl(mockedDbClient, mockBatchReportReader, metricRepository); + private MeasureRepositoryImpl underTestWithMock = new MeasureRepositoryImpl(mockedDbClient, mockBatchReportReader, metricRepository, reportMetricValidator); @CheckForNull private DbSession dbSession; @@ -217,7 +220,7 @@ public class MeasureRepositoryImplTest { Measure.newMeasureBuilder().create("sds"), Measure.newMeasureBuilder().create(Measure.Level.OK), Measure.newMeasureBuilder().createNoValue() - ); + ); @DataProvider public static Object[][] measures() { @@ -225,7 +228,7 @@ public class MeasureRepositoryImplTest { @Nullable @Override public Object[] apply(Measure input) { - return new Measure[]{input}; + return new Measure[] {input}; } }).toArray(Object[].class); } @@ -352,9 +355,11 @@ public class MeasureRepositoryImplTest { public void getRawMeasure_returns_measure_from_batch_if_not_added_through_add_method() { String value = "trololo"; + when(reportMetricValidator.validate(METRIC_KEY_1)).thenReturn(true); + reportReader.putMeasures(FILE_COMPONENT.getRef(), ImmutableList.of( BatchReport.Measure.newBuilder().setMetricKey(METRIC_KEY_1).setStringValue(value).build() - )); + )); Optional<Measure> res = underTest.getRawMeasure(FILE_COMPONENT, metric1); @@ -367,10 +372,25 @@ public class MeasureRepositoryImplTest { } @Test + public void getRawMeasure_returns_only_validate_measure_from_batch_if_not_added_through_add_method() { + when(reportMetricValidator.validate(METRIC_KEY_1)).thenReturn(true); + when(reportMetricValidator.validate(METRIC_KEY_2)).thenReturn(false); + + reportReader.putMeasures(FILE_COMPONENT.getRef(), ImmutableList.of( + BatchReport.Measure.newBuilder().setMetricKey(METRIC_KEY_1).setStringValue("value1").build(), + BatchReport.Measure.newBuilder().setMetricKey(METRIC_KEY_2).setStringValue("value2").build() + )); + + assertThat(underTest.getRawMeasure(FILE_COMPONENT, metric1)).isPresent(); + assertThat(underTest.getRawMeasure(FILE_COMPONENT, metric2)).isAbsent(); + } + + @Test public void getRawMeasure_retrieves_added_measure_over_batch_measure() { + when(reportMetricValidator.validate(METRIC_KEY_1)).thenReturn(true); reportReader.putMeasures(FILE_COMPONENT.getRef(), ImmutableList.of( BatchReport.Measure.newBuilder().setMetricKey(METRIC_KEY_1).setStringValue("some value").build() - )); + )); Measure addedMeasure = SOME_MEASURE; underTest.add(FILE_COMPONENT, metric1, addedMeasure); @@ -383,9 +403,10 @@ public class MeasureRepositoryImplTest { @Test public void getRawMeasure_retrieves_measure_from_batch_and_caches_it_locally_so_that_it_can_be_updated() { + when(reportMetricValidator.validate(METRIC_KEY_1)).thenReturn(true); reportReader.putMeasures(FILE_COMPONENT.getRef(), ImmutableList.of( BatchReport.Measure.newBuilder().setMetricKey(METRIC_KEY_1).setStringValue("some value").build() - )); + )); Optional<Measure> measure = underTest.getRawMeasure(FILE_COMPONENT, metric1); @@ -444,6 +465,7 @@ public class MeasureRepositoryImplTest { @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); @@ -454,6 +476,8 @@ public class MeasureRepositoryImplTest { @Test public void getRawMeasures_returns_added_measures_over_batch_measures() { + when(reportMetricValidator.validate(METRIC_KEY_1)).thenReturn(true); + when(reportMetricValidator.validate(METRIC_KEY_2)).thenReturn(true); BatchReport.Measure batchMeasure1 = BatchReport.Measure.newBuilder().setMetricKey(METRIC_KEY_1).setStringValue("some value").build(); BatchReport.Measure batchMeasure2 = BatchReport.Measure.newBuilder().setMetricKey(METRIC_KEY_2).setStringValue("some value").build(); reportReader.putMeasures(FILE_COMPONENT.getRef(), ImmutableList.of(batchMeasure1, batchMeasure2)); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/metric/ReportMetricValidatorImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/metric/ReportMetricValidatorImplTest.java new file mode 100644 index 00000000000..5c98e9b31e8 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/metric/ReportMetricValidatorImplTest.java @@ -0,0 +1,74 @@ +/* + * 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.metric; + +import com.google.common.collect.ImmutableSet; +import java.util.Collections; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.api.measures.Metric; +import org.sonar.api.utils.log.LogTester; +import org.sonar.core.metric.SensorMetrics; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.sonar.api.measures.Metric.Builder; +import static org.sonar.api.measures.Metric.ValueType; + +public class ReportMetricValidatorImplTest { + + @Rule + public LogTester logTester = new LogTester(); + + static final String METRIC_KEY = "metric_key"; + + SensorMetrics sensorMetrics = mock(SensorMetrics.class); + + @Test + public void validate_metric() throws Exception { + when(sensorMetrics.getMetrics()).thenReturn(ImmutableSet.<Metric>of(new Builder(METRIC_KEY, "name", ValueType.INT).create())); + ReportMetricValidator validator = new ReportMetricValidatorImpl(sensorMetrics); + + assertThat(validator.validate(METRIC_KEY)).isTrue(); + assertThat(logTester.logs()).isEmpty(); + } + + @Test + public void not_validate_metric() throws Exception { + when(sensorMetrics.getMetrics()).thenReturn(Collections.<Metric>emptySet()); + ReportMetricValidator validator = new ReportMetricValidatorImpl(sensorMetrics); + + assertThat(validator.validate(METRIC_KEY)).isFalse(); + assertThat(logTester.logs()).containsOnly("The metric 'metric_key' is ignored and should not be send in the batch report"); + } + + @Test + public void not_generate_new_log_when_validating_twice_the_same_metric() throws Exception { + when(sensorMetrics.getMetrics()).thenReturn(Collections.<Metric>emptySet()); + ReportMetricValidator validator = new ReportMetricValidatorImpl(sensorMetrics); + + assertThat(validator.validate(METRIC_KEY)).isFalse(); + assertThat(logTester.logs()).hasSize(1); + assertThat(validator.validate(METRIC_KEY)).isFalse(); + assertThat(logTester.logs()).hasSize(1); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistMeasuresStepTest.java index b15f3172f69..665ea3c43c7 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistMeasuresStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistMeasuresStepTest.java @@ -49,8 +49,6 @@ import org.sonar.server.rule.db.RuleDao; import org.sonar.test.DbTests; import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.api.measures.CoreMetrics.DUPLICATIONS_DATA; -import static org.sonar.api.measures.CoreMetrics.DUPLICATIONS_DATA_KEY; import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION; import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION_KEY; import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION; @@ -202,20 +200,6 @@ public class PersistMeasuresStepTest extends BaseStepTest { assertThat(retrieveDtos()).isEmpty(); } - @Test(expected = IllegalStateException.class) - public void fail_with_ISE_when_trying_to_insert_forbidden_measures() { - metricRepository.add(1, DUPLICATIONS_DATA); - - reportReader.putMeasures(FILE_REF, Arrays.asList( - BatchReport.Measure.newBuilder() - .setValueType(MeasureValueType.STRING) - .setStringValue("{duplications}") - .setMetricKey(DUPLICATIONS_DATA_KEY) - .build())); - - sut.execute(); - } - @Test public void do_not_insert_file_complexity_distribution_metric_on_files() { metricRepository.add(1, FILE_COMPLEXITY_DISTRIBUTION); diff --git a/sonar-core/src/main/java/org/sonar/core/metric/SensorMetrics.java b/sonar-core/src/main/java/org/sonar/core/metric/SensorMetrics.java new file mode 100644 index 00000000000..52f17def834 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/metric/SensorMetrics.java @@ -0,0 +1,185 @@ +/* + * 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.core.metric; + +import com.google.common.base.Function; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import javax.annotation.Nullable; +import org.sonar.api.measures.Metric; +import org.sonar.api.measures.Metrics; + +import static org.sonar.api.measures.CoreMetrics.ACCESSORS; +import static org.sonar.api.measures.CoreMetrics.CLASSES; +import static org.sonar.api.measures.CoreMetrics.COMMENT_LINES; +import static org.sonar.api.measures.CoreMetrics.COMMENT_LINES_DATA; +import static org.sonar.api.measures.CoreMetrics.COMPLEXITY; +import static org.sonar.api.measures.CoreMetrics.COMPLEXITY_IN_CLASSES; +import static org.sonar.api.measures.CoreMetrics.COMPLEXITY_IN_FUNCTIONS; +import static org.sonar.api.measures.CoreMetrics.CONDITIONS_BY_LINE; +import static org.sonar.api.measures.CoreMetrics.CONDITIONS_TO_COVER; +import static org.sonar.api.measures.CoreMetrics.COVERAGE_LINE_HITS_DATA; +import static org.sonar.api.measures.CoreMetrics.COVERED_CONDITIONS_BY_LINE; +import static org.sonar.api.measures.CoreMetrics.DIRECTORIES; +import static org.sonar.api.measures.CoreMetrics.DUPLICATED_BLOCKS; +import static org.sonar.api.measures.CoreMetrics.DUPLICATED_FILES; +import static org.sonar.api.measures.CoreMetrics.DUPLICATED_LINES; +import static org.sonar.api.measures.CoreMetrics.DUPLICATED_LINES_DENSITY; +import static org.sonar.api.measures.CoreMetrics.FILES; +import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION; +import static org.sonar.api.measures.CoreMetrics.FUNCTIONS; +import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION; +import static org.sonar.api.measures.CoreMetrics.GENERATED_LINES; +import static org.sonar.api.measures.CoreMetrics.GENERATED_NCLOC; +import static org.sonar.api.measures.CoreMetrics.IT_CONDITIONS_BY_LINE; +import static org.sonar.api.measures.CoreMetrics.IT_CONDITIONS_TO_COVER; +import static org.sonar.api.measures.CoreMetrics.IT_COVERAGE_LINE_HITS_DATA; +import static org.sonar.api.measures.CoreMetrics.IT_COVERED_CONDITIONS_BY_LINE; +import static org.sonar.api.measures.CoreMetrics.IT_LINES_TO_COVER; +import static org.sonar.api.measures.CoreMetrics.IT_UNCOVERED_CONDITIONS; +import static org.sonar.api.measures.CoreMetrics.IT_UNCOVERED_LINES; +import static org.sonar.api.measures.CoreMetrics.LINES; +import static org.sonar.api.measures.CoreMetrics.LINES_TO_COVER; +import static org.sonar.api.measures.CoreMetrics.NCLOC; +import static org.sonar.api.measures.CoreMetrics.NCLOC_DATA; +import static org.sonar.api.measures.CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION; +import static org.sonar.api.measures.CoreMetrics.OVERALL_CONDITIONS_BY_LINE; +import static org.sonar.api.measures.CoreMetrics.OVERALL_CONDITIONS_TO_COVER; +import static org.sonar.api.measures.CoreMetrics.OVERALL_COVERAGE_LINE_HITS_DATA; +import static org.sonar.api.measures.CoreMetrics.OVERALL_COVERED_CONDITIONS_BY_LINE; +import static org.sonar.api.measures.CoreMetrics.OVERALL_LINES_TO_COVER; +import static org.sonar.api.measures.CoreMetrics.OVERALL_UNCOVERED_CONDITIONS; +import static org.sonar.api.measures.CoreMetrics.OVERALL_UNCOVERED_LINES; +import static org.sonar.api.measures.CoreMetrics.PUBLIC_API; +import static org.sonar.api.measures.CoreMetrics.PUBLIC_UNDOCUMENTED_API; +import static org.sonar.api.measures.CoreMetrics.QUALITY_PROFILES; +import static org.sonar.api.measures.CoreMetrics.SKIPPED_TESTS; +import static org.sonar.api.measures.CoreMetrics.STATEMENTS; +import static org.sonar.api.measures.CoreMetrics.TESTS; +import static org.sonar.api.measures.CoreMetrics.TEST_ERRORS; +import static org.sonar.api.measures.CoreMetrics.TEST_EXECUTION_TIME; +import static org.sonar.api.measures.CoreMetrics.TEST_FAILURES; +import static org.sonar.api.measures.CoreMetrics.TEST_SUCCESS_DENSITY; +import static org.sonar.api.measures.CoreMetrics.UNCOVERED_CONDITIONS; +import static org.sonar.api.measures.CoreMetrics.UNCOVERED_LINES; + +/** + * This class is used to know the list of metrics that can be send by sensor. + * <p/> + * The batch should not send other metrics, and the Compute Engine should not allow other metrics from the batch report. + */ +public class SensorMetrics { + + private static final Set<Metric> ALLOWED_CORE_METRICS = ImmutableSet.<Metric>of( + LINES, + GENERATED_LINES, + NCLOC, + NCLOC_DATA, + GENERATED_NCLOC, + NCLOC_LANGUAGE_DISTRIBUTION, + + COMMENT_LINES, + COMMENT_LINES_DATA, + + PUBLIC_API, + PUBLIC_UNDOCUMENTED_API, + + FILES, + DIRECTORIES, + CLASSES, + FUNCTIONS, + STATEMENTS, + ACCESSORS, + + DUPLICATED_LINES, + DUPLICATED_BLOCKS, + DUPLICATED_FILES, + DUPLICATED_LINES_DENSITY, + + COMPLEXITY, + COMPLEXITY_IN_CLASSES, + COMPLEXITY_IN_FUNCTIONS, + FILE_COMPLEXITY_DISTRIBUTION, + FUNCTION_COMPLEXITY_DISTRIBUTION, + + TESTS, + SKIPPED_TESTS, + TEST_ERRORS, + TEST_FAILURES, + TEST_EXECUTION_TIME, + TEST_SUCCESS_DENSITY, + + LINES_TO_COVER, + UNCOVERED_LINES, + COVERAGE_LINE_HITS_DATA, + CONDITIONS_TO_COVER, + UNCOVERED_CONDITIONS, + COVERED_CONDITIONS_BY_LINE, + CONDITIONS_BY_LINE, + + IT_LINES_TO_COVER, + IT_UNCOVERED_LINES, + IT_COVERAGE_LINE_HITS_DATA, + IT_CONDITIONS_TO_COVER, + IT_UNCOVERED_CONDITIONS, + IT_COVERED_CONDITIONS_BY_LINE, + IT_CONDITIONS_BY_LINE, + + OVERALL_LINES_TO_COVER, + OVERALL_UNCOVERED_LINES, + OVERALL_COVERAGE_LINE_HITS_DATA, + OVERALL_CONDITIONS_TO_COVER, + OVERALL_UNCOVERED_CONDITIONS, + OVERALL_COVERED_CONDITIONS_BY_LINE, + OVERALL_CONDITIONS_BY_LINE, + + QUALITY_PROFILES + ); + + private final Set<Metric> metrics; + + public SensorMetrics(Metrics[] metricsRepositories) { + this.metrics = ImmutableSet.copyOf(Iterables.concat(getPluginMetrics(metricsRepositories), ALLOWED_CORE_METRICS)); + } + + public Set<Metric> getMetrics() { + return metrics; + } + + private static Iterable<Metric> getPluginMetrics(Metrics[] metricsRepositories) { + return FluentIterable.from(Arrays.asList(metricsRepositories)) + .transformAndConcat(FlattenMetrics.INSTANCE); + } + + private enum FlattenMetrics implements Function<Metrics, List<Metric>> { + INSTANCE; + + @Nullable + @Override + public List<Metric> apply(Metrics input) { + return input.getMetrics(); + } + } +} diff --git a/sonar-core/src/test/java/org/sonar/core/metric/SensorMetricsTest.java b/sonar-core/src/test/java/org/sonar/core/metric/SensorMetricsTest.java new file mode 100644 index 00000000000..332e5eff7f8 --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/metric/SensorMetricsTest.java @@ -0,0 +1,60 @@ +/* + * 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.core.metric; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import java.util.List; +import org.junit.Test; +import org.sonar.api.measures.Metric; +import org.sonar.api.measures.Metrics; + +import static com.google.common.collect.Lists.newArrayList; +import static org.assertj.core.api.Assertions.assertThat; + +public class SensorMetricsTest { + + static final SensorMetrics SENSOR_METRICS_WITHOUT_METRIC_PLUGIN = new SensorMetrics(new Metrics[]{}); + static final SensorMetrics SENSOR_METRICS_WITH_PLUGIN = new SensorMetrics(new Metrics[]{new FakeMetrics()}); + + @Test + public void check_number_of_allowed_core_metrics() throws Exception { + assertThat(SENSOR_METRICS_WITHOUT_METRIC_PLUGIN.getMetrics()).hasSize(53); + } + + @Test + public void check_metrics_from_plugin() throws Exception { + List<Metric> metrics = newArrayList(SENSOR_METRICS_WITH_PLUGIN.getMetrics()); + Iterables.removeAll(metrics, SENSOR_METRICS_WITHOUT_METRIC_PLUGIN.getMetrics()); + assertThat(metrics).hasSize(2); + } + + private static class FakeMetrics implements Metrics { + + @Override + public List<Metric> getMetrics() { + return ImmutableList.<Metric>of( + new Metric.Builder("key1", "name1", Metric.ValueType.INT).create(), + new Metric.Builder("key2", "name2", Metric.ValueType.FLOAT).create() + ); + } + } +} |