Only plugin metrics and some defined core metrics are allowed to be read from the batchtags/5.2-RC1
import org.picocontainer.monitors.NullComponentMonitor; | import org.picocontainer.monitors.NullComponentMonitor; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.sonar.api.utils.log.Profiler; | 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.issue.tracking.Tracker; | ||||
import org.sonar.core.platform.ComponentContainer; | import org.sonar.core.platform.ComponentContainer; | ||||
import org.sonar.core.platform.Module; | |||||
import org.sonar.server.computation.ComputationService; | import org.sonar.server.computation.ComputationService; | ||||
import org.sonar.server.computation.ReportQueue; | import org.sonar.server.computation.ReportQueue; | ||||
import org.sonar.server.computation.activity.ActivityManager; | import org.sonar.server.computation.activity.ActivityManager; | ||||
import org.sonar.server.computation.issue.TrackerBaseInputFactory; | import org.sonar.server.computation.issue.TrackerBaseInputFactory; | ||||
import org.sonar.server.computation.issue.TrackerExecution; | import org.sonar.server.computation.issue.TrackerExecution; | ||||
import org.sonar.server.computation.issue.TrackerRawInputFactory; | 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.language.LanguageRepositoryImpl; | ||||
import org.sonar.server.computation.measure.MeasureRepositoryImpl; | import org.sonar.server.computation.measure.MeasureRepositoryImpl; | ||||
import org.sonar.server.computation.measure.newcoverage.NewCoverageMetricKeysModule; | 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.period.PeriodsHolderImpl; | ||||
import org.sonar.server.computation.qualitygate.EvaluationResultTextConverterImpl; | import org.sonar.server.computation.qualitygate.EvaluationResultTextConverterImpl; | ||||
import org.sonar.server.computation.qualitygate.QualityGateHolderImpl; | import org.sonar.server.computation.qualitygate.QualityGateHolderImpl; | ||||
return Arrays.asList( | return Arrays.asList( | ||||
ActivityManager.class, | ActivityManager.class, | ||||
MetricModule.class, | |||||
// holders | // holders | ||||
BatchReportDirectoryHolderImpl.class, | BatchReportDirectoryHolderImpl.class, | ||||
TreeRootHolderImpl.class, | TreeRootHolderImpl.class, | ||||
// repositories | // repositories | ||||
LanguageRepositoryImpl.class, | LanguageRepositoryImpl.class, | ||||
MetricRepositoryImpl.class, | |||||
MeasureRepositoryImpl.class, | MeasureRepositoryImpl.class, | ||||
EventRepositoryImpl.class, | EventRepositoryImpl.class, | ||||
ProjectSettingsRepository.class, | ProjectSettingsRepository.class, |
import org.sonar.server.computation.debt.Characteristic; | import org.sonar.server.computation.debt.Characteristic; | ||||
import org.sonar.server.computation.metric.Metric; | import org.sonar.server.computation.metric.Metric; | ||||
import org.sonar.server.computation.metric.MetricRepository; | import org.sonar.server.computation.metric.MetricRepository; | ||||
import org.sonar.server.computation.metric.ReportMetricValidator; | |||||
import static com.google.common.base.Preconditions.checkArgument; | import static com.google.common.base.Preconditions.checkArgument; | ||||
import static java.lang.String.format; | import static java.lang.String.format; | ||||
private final BatchReportReader reportReader; | private final BatchReportReader reportReader; | ||||
private final BatchMeasureToMeasure batchMeasureToMeasure; | private final BatchMeasureToMeasure batchMeasureToMeasure; | ||||
private final MetricRepository metricRepository; | private final MetricRepository metricRepository; | ||||
private final ReportMetricValidator reportMetricValidator; | |||||
private final MeasureDtoToMeasure measureDtoToMeasure = new MeasureDtoToMeasure(); | private final MeasureDtoToMeasure measureDtoToMeasure = new MeasureDtoToMeasure(); | ||||
private final Set<Integer> loadedComponents = new HashSet<>(); | private final Set<Integer> loadedComponents = new HashSet<>(); | ||||
private final Map<Integer, Map<MeasureKey, Measure>> measures = new HashMap<>(); | 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.dbClient = dbClient; | ||||
this.reportReader = reportReader; | this.reportReader = reportReader; | ||||
this.reportMetricValidator = reportMetricValidator; | |||||
this.batchMeasureToMeasure = new BatchMeasureToMeasure(); | this.batchMeasureToMeasure = new BatchMeasureToMeasure(); | ||||
this.metricRepository = metricRepository; | this.metricRepository = metricRepository; | ||||
} | } | ||||
} | } | ||||
for (BatchReport.Measure batchMeasure : reportReader.readComponentMeasures(component.getRef())) { | 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()); | loadedComponents.add(component.getRef()); | ||||
} | } |
/* | |||||
* 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); | |||||
} | |||||
} |
/* | |||||
* 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); | |||||
} |
/* | |||||
* 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(); | |||||
} | |||||
} | |||||
} |
import java.util.Map; | import java.util.Map; | ||||
import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||
import org.sonar.api.measures.CoreMetrics; | 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.DbSession; | ||||
import org.sonar.db.measure.MeasureDto; | |||||
import org.sonar.server.computation.component.Component; | import org.sonar.server.computation.component.Component; | ||||
import org.sonar.server.computation.component.DbIdsRepository; | import org.sonar.server.computation.component.DbIdsRepository; | ||||
import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor; | import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor; | ||||
import org.sonar.server.computation.measure.MeasureToMeasureDto; | import org.sonar.server.computation.measure.MeasureToMeasureDto; | ||||
import org.sonar.server.computation.metric.Metric; | import org.sonar.server.computation.metric.Metric; | ||||
import org.sonar.server.computation.metric.MetricRepository; | import org.sonar.server.computation.metric.MetricRepository; | ||||
import org.sonar.db.DbClient; | |||||
import static com.google.common.collect.FluentIterable.from; | import static com.google.common.collect.FluentIterable.from; | ||||
import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER; | import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER; | ||||
public class PersistMeasuresStep implements ComputationStep { | 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( | private static final List<String> NOT_TO_PERSIST_ON_FILE_METRIC_KEYS = ImmutableList.of( | ||||
CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION_KEY, | CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION_KEY, | ||||
private void persistMeasures(Component component, Multimap<String, Measure> batchReportMeasures, long componentId, long snapshotId) { | private void persistMeasures(Component component, Multimap<String, Measure> batchReportMeasures, long componentId, long snapshotId) { | ||||
for (Map.Entry<String, Collection<Measure>> measures : batchReportMeasures.asMap().entrySet()) { | for (Map.Entry<String, Collection<Measure>> measures : batchReportMeasures.asMap().entrySet()) { | ||||
String metricKey = measures.getKey(); | 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) { | if (NOT_TO_PERSIST_ON_FILE_METRIC_KEYS.contains(metricKey) && component.getType() == Component.Type.FILE) { | ||||
continue; | continue; | ||||
} | } |
import org.sonar.server.computation.metric.Metric; | import org.sonar.server.computation.metric.Metric; | ||||
import org.sonar.server.computation.metric.MetricImpl; | import org.sonar.server.computation.metric.MetricImpl; | ||||
import org.sonar.server.computation.metric.MetricRepository; | import org.sonar.server.computation.metric.MetricRepository; | ||||
import org.sonar.server.computation.metric.ReportMetricValidator; | |||||
import org.sonar.server.db.DbClient; | import org.sonar.server.db.DbClient; | ||||
import org.sonar.server.metric.persistence.MetricDao; | import org.sonar.server.metric.persistence.MetricDao; | ||||
private static final RuleDto SOME_RULE = RuleDto.createFor(RuleKey.of("A", "1")).setId(963); | 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 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 DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new MeasureDao(), new SnapshotDao(), new MetricDao(), new ComponentDao()); | ||||
private MetricRepository metricRepository = mock(MetricRepository.class); | 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 DbClient mockedDbClient = mock(DbClient.class); | ||||
private BatchReportReader mockBatchReportReader = mock(BatchReportReader.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 | @CheckForNull | ||||
private DbSession dbSession; | private DbSession dbSession; | ||||
Measure.newMeasureBuilder().create("sds"), | Measure.newMeasureBuilder().create("sds"), | ||||
Measure.newMeasureBuilder().create(Measure.Level.OK), | Measure.newMeasureBuilder().create(Measure.Level.OK), | ||||
Measure.newMeasureBuilder().createNoValue() | Measure.newMeasureBuilder().createNoValue() | ||||
); | |||||
); | |||||
@DataProvider | @DataProvider | ||||
public static Object[][] measures() { | public static Object[][] measures() { | ||||
@Nullable | @Nullable | ||||
@Override | @Override | ||||
public Object[] apply(Measure input) { | public Object[] apply(Measure input) { | ||||
return new Measure[]{input}; | |||||
return new Measure[] {input}; | |||||
} | } | ||||
}).toArray(Object[].class); | }).toArray(Object[].class); | ||||
} | } | ||||
public void getRawMeasure_returns_measure_from_batch_if_not_added_through_add_method() { | public void getRawMeasure_returns_measure_from_batch_if_not_added_through_add_method() { | ||||
String value = "trololo"; | String value = "trololo"; | ||||
when(reportMetricValidator.validate(METRIC_KEY_1)).thenReturn(true); | |||||
reportReader.putMeasures(FILE_COMPONENT.getRef(), ImmutableList.of( | reportReader.putMeasures(FILE_COMPONENT.getRef(), ImmutableList.of( | ||||
BatchReport.Measure.newBuilder().setMetricKey(METRIC_KEY_1).setStringValue(value).build() | BatchReport.Measure.newBuilder().setMetricKey(METRIC_KEY_1).setStringValue(value).build() | ||||
)); | |||||
)); | |||||
Optional<Measure> res = underTest.getRawMeasure(FILE_COMPONENT, metric1); | Optional<Measure> res = underTest.getRawMeasure(FILE_COMPONENT, metric1); | ||||
assertThat(underTest.getRawMeasure(OTHER_COMPONENT, metric1)).isAbsent(); | 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 | @Test | ||||
public void getRawMeasure_retrieves_added_measure_over_batch_measure() { | public void getRawMeasure_retrieves_added_measure_over_batch_measure() { | ||||
when(reportMetricValidator.validate(METRIC_KEY_1)).thenReturn(true); | |||||
reportReader.putMeasures(FILE_COMPONENT.getRef(), ImmutableList.of( | reportReader.putMeasures(FILE_COMPONENT.getRef(), ImmutableList.of( | ||||
BatchReport.Measure.newBuilder().setMetricKey(METRIC_KEY_1).setStringValue("some value").build() | BatchReport.Measure.newBuilder().setMetricKey(METRIC_KEY_1).setStringValue("some value").build() | ||||
)); | |||||
)); | |||||
Measure addedMeasure = SOME_MEASURE; | Measure addedMeasure = SOME_MEASURE; | ||||
underTest.add(FILE_COMPONENT, metric1, addedMeasure); | underTest.add(FILE_COMPONENT, metric1, addedMeasure); | ||||
@Test | @Test | ||||
public void getRawMeasure_retrieves_measure_from_batch_and_caches_it_locally_so_that_it_can_be_updated() { | 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( | reportReader.putMeasures(FILE_COMPONENT.getRef(), ImmutableList.of( | ||||
BatchReport.Measure.newBuilder().setMetricKey(METRIC_KEY_1).setStringValue("some value").build() | BatchReport.Measure.newBuilder().setMetricKey(METRIC_KEY_1).setStringValue("some value").build() | ||||
)); | |||||
)); | |||||
Optional<Measure> measure = underTest.getRawMeasure(FILE_COMPONENT, metric1); | Optional<Measure> measure = underTest.getRawMeasure(FILE_COMPONENT, metric1); | ||||
@Test | @Test | ||||
public void getRawMeasure_for_characteristic_returns_measure_for_specified_rule() { | 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(); | Measure measure = Measure.newMeasureBuilder().forCharacteristic(SOME_CHARACTERISTIC.getId()).createNoValue(); | ||||
underTest.add(FILE_COMPONENT, metric1, measure); | underTest.add(FILE_COMPONENT, metric1, measure); | ||||
@Test | @Test | ||||
public void getRawMeasures_returns_added_measures_over_batch_measures() { | 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 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(); | BatchReport.Measure batchMeasure2 = BatchReport.Measure.newBuilder().setMetricKey(METRIC_KEY_2).setStringValue("some value").build(); | ||||
reportReader.putMeasures(FILE_COMPONENT.getRef(), ImmutableList.of(batchMeasure1, batchMeasure2)); | reportReader.putMeasures(FILE_COMPONENT.getRef(), ImmutableList.of(batchMeasure1, batchMeasure2)); |
/* | |||||
* 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); | |||||
} | |||||
} |
import org.sonar.test.DbTests; | import org.sonar.test.DbTests; | ||||
import static org.assertj.core.api.Assertions.assertThat; | 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; | ||||
import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION_KEY; | import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION; | import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION; | ||||
assertThat(retrieveDtos()).isEmpty(); | 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 | @Test | ||||
public void do_not_insert_file_complexity_distribution_metric_on_files() { | public void do_not_insert_file_complexity_distribution_metric_on_files() { | ||||
metricRepository.add(1, FILE_COMPLEXITY_DISTRIBUTION); | metricRepository.add(1, FILE_COMPLEXITY_DISTRIBUTION); |
/* | |||||
* 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(); | |||||
} | |||||
} | |||||
} |
/* | |||||
* 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() | |||||
); | |||||
} | |||||
} | |||||
} |