Browse Source

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
tags/5.2-RC1
Julien Lancelot 9 years ago
parent
commit
cc6e6c4ba3

+ 5
- 4
server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java View File

@@ -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,

+ 10
- 3
server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureRepositoryImpl.java View File

@@ -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());
}

+ 34
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricModule.java View File

@@ -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);
}
}

+ 30
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/metric/ReportMetricValidator.java View File

@@ -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);

}

+ 67
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/metric/ReportMetricValidatorImpl.java View File

@@ -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();
}
}
}

+ 3
- 11
server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistMeasuresStep.java View File

@@ -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;
}

+ 31
- 7
server/sonar-server/src/test/java/org/sonar/server/computation/measure/MeasureRepositoryImplTest.java View File

@@ -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);

@@ -366,11 +371,26 @@ public class MeasureRepositoryImplTest {
assertThat(underTest.getRawMeasure(OTHER_COMPONENT, metric1)).isAbsent();
}

@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));

+ 74
- 0
server/sonar-server/src/test/java/org/sonar/server/computation/metric/ReportMetricValidatorImplTest.java View File

@@ -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);
}
}

+ 0
- 16
server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistMeasuresStepTest.java View File

@@ -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);

+ 185
- 0
sonar-core/src/main/java/org/sonar/core/metric/SensorMetrics.java View File

@@ -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();
}
}
}

+ 60
- 0
sonar-core/src/test/java/org/sonar/core/metric/SensorMetricsTest.java View File

@@ -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()
);
}
}
}

Loading…
Cancel
Save