aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2015-07-10 12:33:09 +0200
committerJulien Lancelot <julien.lancelot@sonarsource.com>2015-07-15 10:44:32 +0200
commitcc6e6c4ba3e48371736d5b3bfffbed39e43fef9b (patch)
tree1178a3a3748b347632ec506b22361781a7763414
parent698e9952c6d633a49c7f1611ea978f811fdab12b (diff)
downloadsonarqube-cc6e6c4ba3e48371736d5b3bfffbed39e43fef9b.tar.gz
sonarqube-cc6e6c4ba3e48371736d5b3bfffbed39e43fef9b.zip
Filter metrics that can be read from the batch
Only plugin metrics and some defined core metrics are allowed to be read from the batch
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java9
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureRepositoryImpl.java13
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricModule.java34
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/metric/ReportMetricValidator.java30
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/metric/ReportMetricValidatorImpl.java67
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistMeasuresStep.java14
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureRepositoryImplTest.java38
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/metric/ReportMetricValidatorImplTest.java74
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistMeasuresStepTest.java16
-rw-r--r--sonar-core/src/main/java/org/sonar/core/metric/SensorMetrics.java185
-rw-r--r--sonar-core/src/test/java/org/sonar/core/metric/SensorMetricsTest.java60
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()
+ );
+ }
+ }
+}