소스 검색

SONAR-6643 Fill measures with variations

tags/5.2-RC1
Julien Lancelot 9 년 전
부모
커밋
ef9cd05556
20개의 변경된 파일1284개의 추가작업 그리고 23개의 파일을 삭제
  1. 93
    0
      server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureKey.java
  2. 5
    0
      server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricRepository.java
  3. 6
    0
      server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricRepositoryImpl.java
  4. 3
    1
      server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java
  5. 6
    6
      server/sonar-server/src/main/java/org/sonar/server/computation/step/FeedPeriodsStep.java
  6. 252
    0
      server/sonar-server/src/main/java/org/sonar/server/computation/step/FillMeasuresWithVariationsStep.java
  7. 14
    0
      server/sonar-server/src/main/java/org/sonar/server/measure/persistence/MeasureDao.java
  8. 10
    2
      server/sonar-server/src/test/java/org/sonar/server/computation/metric/MetricRepositoryImplTest.java
  9. 355
    0
      server/sonar-server/src/test/java/org/sonar/server/computation/step/FillMeasuresWithVariationsStepTest.java
  10. 128
    5
      server/sonar-server/src/test/java/org/sonar/server/measure/persistence/MeasureDaoTest.java
  11. 9
    5
      server/sonar-server/src/test/resources/org/sonar/server/computation/metric/MetricRepositoryImplTest/shared.xml
  12. 51
    0
      server/sonar-server/src/test/resources/org/sonar/server/computation/step/FillMeasuresWithVariationsStepTest/shared.xml
  13. 87
    0
      server/sonar-server/src/test/resources/org/sonar/server/measure/persistence/MeasureDaoTest/past_measures.xml
  14. 28
    0
      server/sonar-server/src/test/resources/org/sonar/server/measure/persistence/MeasureDaoTest/past_measures_with_characteristic_id.xml
  15. 35
    0
      server/sonar-server/src/test/resources/org/sonar/server/measure/persistence/MeasureDaoTest/past_measures_with_person_id.xml
  16. 45
    0
      server/sonar-server/src/test/resources/org/sonar/server/measure/persistence/MeasureDaoTest/past_measures_with_rule_id.xml
  17. 5
    4
      sonar-core/src/main/java/org/sonar/core/measure/db/MeasureMapper.java
  18. 87
    0
      sonar-core/src/main/java/org/sonar/core/measure/db/PastMeasureDto.java
  19. 15
    0
      sonar-core/src/main/resources/org/sonar/core/measure/db/MeasureMapper.xml
  20. 50
    0
      sonar-core/src/test/java/org/sonar/core/measure/db/PastMeasureDtoTest.java

+ 93
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureKey.java 파일 보기

@@ -0,0 +1,93 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* SonarQube is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package org.sonar.server.computation.measure;

import java.util.Objects;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import org.sonar.core.rule.RuleDto;
import org.sonar.server.computation.debt.Characteristic;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;

@Immutable
public final class MeasureKey {
private static final int DEFAULT_INT_VALUE = -6253;

private final String metricKey;
private final int ruleId;
private final int characteristicId;

public MeasureKey(String metricKey, @Nullable Integer ruleId, @Nullable Integer characteristicId) {
// defensive code in case we badly chose the default value, we want to know it right away!
checkArgument(ruleId == null || ruleId != DEFAULT_INT_VALUE, "Unsupported rule id");
checkArgument(characteristicId == null || characteristicId != DEFAULT_INT_VALUE, "Unsupported characteristic id");

this.metricKey = requireNonNull(metricKey, "MetricKey can not be null");
this.ruleId = ruleId == null ? DEFAULT_INT_VALUE : ruleId;
this.characteristicId = characteristicId == null ? DEFAULT_INT_VALUE : characteristicId;
}

public MeasureKey(String key, @Nullable RuleDto rule, @Nullable Characteristic characteristic) {
this(key, rule == null ? null : rule.getId(), characteristic == null ? null : characteristic.getId());
}

public int getCharacteristicId() {
return characteristicId;
}

public String getMetricKey() {
return metricKey;
}

public int getRuleId() {
return ruleId;
}

@Override
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
MeasureKey that = (MeasureKey) o;
return metricKey.equals(that.metricKey)
&& ruleId == that.ruleId
&& characteristicId == that.characteristicId;
}

@Override
public int hashCode() {
return Objects.hash(metricKey, ruleId, characteristicId);
}

@Override
public String toString() {
return com.google.common.base.Objects.toStringHelper(this)
.add("metricKey", metricKey)
.add("ruleId", ruleId)
.add("characteristicId", characteristicId)
.toString();
}
}

+ 5
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricRepository.java 파일 보기

@@ -39,4 +39,9 @@ public interface MetricRepository {
*/
Metric getById(long id);

/**
* Get iterable of all {@link Metric}.
*/
Iterable<Metric> getAll();

}

+ 6
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricRepositoryImpl.java 파일 보기

@@ -20,6 +20,7 @@
package org.sonar.server.computation.metric;

import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import java.util.List;
import java.util.Map;
import javax.annotation.CheckForNull;
@@ -83,6 +84,11 @@ public class MetricRepositoryImpl implements MetricRepository, Startable {
return res;
}

@Override
public Iterable<Metric> getAll() {
return FluentIterable.from(metricsByKey.values()).toSet();
}

private void verifyMetricsInitialized() {
if (this.metricsByKey == null) {
throw new IllegalStateException("Metric cache has not been initialized");

+ 3
- 1
server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java 파일 보기

@@ -45,6 +45,8 @@ public class ComputationSteps {
ValidateProjectStep.class,
FeedDebtModelStep.class,

FeedPeriodsStep.class,

// Read report
ParseReportStep.class,

@@ -53,9 +55,9 @@ public class ComputationSteps {
// data computation
QualityProfileEventsStep.class,
QualityGateEventsStep.class,
FillMeasuresWithVariationsStep.class,

// Persist data
FeedPeriodsStep.class,
PersistComponentsStep.class,
PersistSnapshotsStep.class,
PersistNumberOfDaysSinceLastCommitStep.class,

+ 6
- 6
server/sonar-server/src/main/java/org/sonar/server/computation/step/FeedPeriodsStep.java 파일 보기

@@ -71,7 +71,7 @@ public class FeedPeriodsStep implements ComputationStep {
private final PeriodsHolderImpl periodsHolder;

public FeedPeriodsStep(DbClient dbClient, Settings settings, TreeRootHolder treeRootHolder, BatchReportReader batchReportReader,
PeriodsHolderImpl periodsHolder) {
PeriodsHolderImpl periodsHolder) {
this.dbClient = dbClient;
this.settings = settings;
this.treeRootHolder = treeRootHolder;
@@ -164,7 +164,7 @@ public class FeedPeriodsStep implements ComputationStep {
if (snapshot == null) {
return null;
}
LOG.debug(String.format("Compare to date %s (analysis of %s)", formatDate(date.getTime()), formatDate(snapshot.getCreatedAt())));
LOG.debug("Compare to date {} (analysis of {})", formatDate(date.getTime()), formatDate(snapshot.getCreatedAt()));
return new Period(index, CoreProperties.TIMEMACHINE_MODE_DATE, DateUtils.formatDate(date), snapshot.getCreatedAt(), snapshot.getId());
}

@@ -176,7 +176,7 @@ public class FeedPeriodsStep implements ComputationStep {
if (snapshot == null) {
return null;
}
LOG.debug(String.format("Compare over %s days (%s, analysis of %s)", String.valueOf(days), formatDate(targetDate), formatDate(snapshot.getCreatedAt())));
LOG.debug("Compare over {} days ({}, analysis of {})", String.valueOf(days), formatDate(targetDate), formatDate(snapshot.getCreatedAt()));
return new Period(index, CoreProperties.TIMEMACHINE_MODE_DAYS, String.valueOf(days), snapshot.getCreatedAt(), snapshot.getId());
}

@@ -186,7 +186,7 @@ public class FeedPeriodsStep implements ComputationStep {
if (snapshot == null) {
return null;
}
LOG.debug(String.format("Compare to previous analysis (%s)", formatDate(snapshot.getCreatedAt())));
LOG.debug("Compare to previous analysis ({})", formatDate(snapshot.getCreatedAt()));
return new Period(index, CoreProperties.TIMEMACHINE_MODE_PREVIOUS_ANALYSIS, formatDate(snapshot.getCreatedAt()), snapshot.getCreatedAt(), snapshot.getId());
}

@@ -197,7 +197,7 @@ public class FeedPeriodsStep implements ComputationStep {
return null;
}
SnapshotDto snapshotDto = snapshotDtos.get(0);
LOG.debug(String.format("Compare to previous version (%s)", formatDate(snapshotDto.getCreatedAt())));
LOG.debug("Compare to previous version ({})", formatDate(snapshotDto.getCreatedAt()));
return new Period(index, CoreProperties.TIMEMACHINE_MODE_PREVIOUS_VERSION, snapshotDto.getVersion(), snapshotDto.getCreatedAt(), snapshotDto.getId());
}

@@ -207,7 +207,7 @@ public class FeedPeriodsStep implements ComputationStep {
if (snapshot == null) {
return null;
}
LOG.debug(String.format("Compare to version (%s) (%s)", version, formatDate(snapshot.getCreatedAt())));
LOG.debug("Compare to version ({}) ({})", version, formatDate(snapshot.getCreatedAt()));
return new Period(index, CoreProperties.TIMEMACHINE_MODE_VERSION, version, snapshot.getCreatedAt(), snapshot.getId());
}


+ 252
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/step/FillMeasuresWithVariationsStep.java 파일 보기

@@ -0,0 +1,252 @@
/*
* 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.step;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.sonar.core.measure.db.PastMeasureDto;
import org.sonar.core.persistence.DbSession;
import org.sonar.server.computation.component.Component;
import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor;
import org.sonar.server.computation.component.TreeRootHolder;
import org.sonar.server.computation.measure.Measure;
import org.sonar.server.computation.measure.MeasureKey;
import org.sonar.server.computation.measure.MeasureRepository;
import org.sonar.server.computation.measure.MeasureVariations;
import org.sonar.server.computation.metric.Metric;
import org.sonar.server.computation.metric.MetricRepository;
import org.sonar.server.computation.period.Period;
import org.sonar.server.computation.period.PeriodsHolder;
import org.sonar.server.db.DbClient;

import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER;

/**
* Set variations on all numeric measures found in the repository.
* This step MUST be executed after all steps that create some measures
*
* Note that measures on developer are not handle yet.
*/
public class FillMeasuresWithVariationsStep implements ComputationStep {

private final DbClient dbClient;
private final TreeRootHolder treeRootHolder;
private final PeriodsHolder periodsHolder;
private final MetricRepository metricRepository;
private final MeasureRepository measureRepository;

private final Function<PastMeasureDto, MeasureKey> pastMeasureToMeasureKey = new Function<PastMeasureDto, MeasureKey>() {
@Nullable
@Override
public MeasureKey apply(@Nonnull PastMeasureDto input) {
Metric metric = metricRepository.getById(input.getMetricId());
return new MeasureKey(metric.getKey(), input.getCharacteristicId(), input.getRuleId());
}
};

public FillMeasuresWithVariationsStep(DbClient dbClient, TreeRootHolder treeRootHolder, PeriodsHolder periodsHolder, MetricRepository metricRepository,
MeasureRepository measureRepository) {
this.dbClient = dbClient;
this.treeRootHolder = treeRootHolder;
this.periodsHolder = periodsHolder;
this.metricRepository = metricRepository;
this.measureRepository = measureRepository;
}

@Override
public void execute() {
DbSession dbSession = dbClient.openSession(false);
try {
Iterable<Metric> metrics = FluentIterable.from(metricRepository.getAll()).filter(NumericMetric.INSTANCE);
new VariationMeasuresVisitor(dbSession, metrics).visit(treeRootHolder.getRoot());
} finally {
dbSession.close();
}
}

private class VariationMeasuresVisitor extends DepthTraversalTypeAwareVisitor {

private final DbSession session;
private final Set<Integer> metricIds;
private final Map<String, Metric> metricByKeys;

public VariationMeasuresVisitor(DbSession session, Iterable<Metric> metrics) {
// measures on files are currently purged, so past measures are not available on files
super(Component.Type.DIRECTORY, PRE_ORDER);
this.session = session;
this.metricIds = FluentIterable.from(metrics).transform(MetricDtoToMetricId.INSTANCE).toSet();
this.metricByKeys = FluentIterable.from(metrics).uniqueIndex(MetricToKey.INSTANCE);
}

@Override
public void visitAny(Component component) {
MeasuresWithVariationRepository measuresWithVariationRepository = computeMeasuresWithVariations(component);
processMeasuresWithVariation(component, measuresWithVariationRepository);
}

private MeasuresWithVariationRepository computeMeasuresWithVariations(Component component) {
MeasuresWithVariationRepository measuresWithVariationRepository = new MeasuresWithVariationRepository();
for (Period period : periodsHolder.getPeriods()) {
List<PastMeasureDto> pastMeasures = dbClient.measureDao().selectByComponentUuidAndProjectSnapshotIdAndMetricIds(session, component.getUuid(), period.getSnapshotId(),
metricIds);
setVariationMeasures(component, pastMeasures, period.getIndex(), measuresWithVariationRepository);
}
return measuresWithVariationRepository;
}

private void processMeasuresWithVariation(Component component, MeasuresWithVariationRepository measuresWithVariationRepository) {
for (MeasureWithVariations measureWithVariations : measuresWithVariationRepository.measures()) {
Metric metric = measureWithVariations.getMetric();
Measure measure = Measure.updatedMeasureBuilder(measureWithVariations.getMeasure())
.setVariations(new MeasureVariations(
measureWithVariations.getVariation(1),
measureWithVariations.getVariation(2),
measureWithVariations.getVariation(3),
measureWithVariations.getVariation(4),
measureWithVariations.getVariation(5)))
.create();
measureRepository.update(component, metric, measure);
}
}

private void setVariationMeasures(Component component, List<PastMeasureDto> pastMeasures, int period, MeasuresWithVariationRepository measuresWithVariationRepository) {
Map<MeasureKey, PastMeasureDto> pastMeasuresByMeasureKey = FluentIterable.from(pastMeasures).uniqueIndex(pastMeasureToMeasureKey);
for (Map.Entry<String, Measure> entry : measureRepository.getRawMeasures(component).entries()) {
String metricKey = entry.getKey();
Measure measure = entry.getValue();
PastMeasureDto pastMeasure = pastMeasuresByMeasureKey.get(new MeasureKey(metricKey, measure.getCharacteristicId(), measure.getRuleId()));
if (pastMeasure != null && pastMeasure.hasValue()) {
Metric metric = metricByKeys.get(metricKey);
measuresWithVariationRepository.add(metric, measure, period, computeVariation(measure, pastMeasure.getValue()));
}
}
}
}

private static double computeVariation(Measure measure, Double pastValue) {
switch (measure.getValueType()) {
case INT:
return measure.getIntValue() - pastValue;
case LONG:
return measure.getLongValue() - pastValue;
case DOUBLE:
return measure.getDoubleValue() - pastValue;
case BOOLEAN:
return (measure.getBooleanValue() ? 1d : 0d) - pastValue;
default:
throw new IllegalArgumentException("Unsupported Measure.ValueType " + measure.getValueType());
}
}

private static final class MeasuresWithVariationRepository {

private final Map<MeasureKey, MeasureWithVariations> measuresWithVariations = new HashMap<>();

public void add(Metric metric, final Measure measure, int variationIndex, double variationValue) {
MeasureKey measureKey = new MeasureKey(metric.getKey(), measure.getCharacteristicId(), measure.getRuleId());
MeasureWithVariations measureWithVariations = measuresWithVariations.get(measureKey);
if (measureWithVariations == null) {
measureWithVariations = new MeasureWithVariations(metric, measure);
measuresWithVariations.put(measureKey, measureWithVariations);
}
measureWithVariations.setVariation(variationIndex, variationValue);
}

public Collection<MeasureWithVariations> measures() {
return measuresWithVariations.values();
}
}

private static final class MeasureWithVariations {
private final Metric metric;
private final Measure measure;
private final Double[] variations = new Double[5];

public MeasureWithVariations(Metric metric, Measure measure) {
this.metric = metric;
this.measure = measure;
}

public Measure getMeasure() {
return measure;
}

public Metric getMetric() {
return metric;
}

public void setVariation(int index, @Nullable Double value) {
variations[index - 1] = value;
}

@CheckForNull
public Double getVariation(int index) {
return variations[index - 1];
}
}

private enum MetricDtoToMetricId implements Function<Metric, Integer> {
INSTANCE;

@Nullable
@Override
public Integer apply(@Nonnull Metric metric) {
return metric.getId();
}
}

private enum MetricToKey implements Function<Metric, String> {
INSTANCE;

@Nullable
@Override
public String apply(@Nonnull Metric metric) {
return metric.getKey();
}
}

private enum NumericMetric implements Predicate<Metric> {
INSTANCE;

@Override
public boolean apply(@Nonnull Metric metric) {
Measure.ValueType valueType = metric.getType().getValueType();
return Measure.ValueType.INT.equals(valueType)
|| Measure.ValueType.LONG.equals(valueType)
|| Measure.ValueType.DOUBLE.equals(valueType)
|| Measure.ValueType.BOOLEAN.equals(valueType);
}
}

@Override
public String getDescription() {
return "Compute differential measures";
}
}

+ 14
- 0
server/sonar-server/src/main/java/org/sonar/server/measure/persistence/MeasureDao.java 파일 보기

@@ -24,10 +24,13 @@ import com.google.common.base.Function;
import com.google.common.collect.Lists;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import javax.annotation.CheckForNull;
import org.sonar.api.server.ServerSide;
import org.sonar.core.component.SnapshotDto;
import org.sonar.core.measure.db.MeasureDto;
import org.sonar.core.measure.db.MeasureMapper;
import org.sonar.core.measure.db.PastMeasureDto;
import org.sonar.core.persistence.DaoComponent;
import org.sonar.core.persistence.DaoUtils;
import org.sonar.core.persistence.DbSession;
@@ -53,6 +56,17 @@ public class MeasureDao implements DaoComponent {
});
}

public List<PastMeasureDto> selectByComponentUuidAndProjectSnapshotIdAndMetricIds(final DbSession session, final String componentUuid, final long projectSnapshotId,
Set<Integer> metricIds) {
return DaoUtils.executeLargeInputs(metricIds, new Function<List<Integer>, List<PastMeasureDto>>() {
@Override
public List<PastMeasureDto> apply(List<Integer> ids) {
return mapper(session).selectByComponentUuidAndProjectSnapshotIdAndStatusAndMetricIds(componentUuid, projectSnapshotId, ids,
SnapshotDto.STATUS_PROCESSED);
}
});
}

public void insert(DbSession session, MeasureDto measureDto) {
mapper(session).insert(measureDto);
}

+ 10
- 2
server/sonar-server/src/test/java/org/sonar/server/computation/metric/MetricRepositoryImplTest.java 파일 보기

@@ -112,12 +112,12 @@ public class MetricRepositoryImplTest {
@Test
public void getById_throws_ISE_of_Metric_is_disabled() {
expectedException.expect(IllegalStateException.class);
expectedException.expectMessage(String.format("Metric with id '%s' does not exist", 3));
expectedException.expectMessage(String.format("Metric with id '%s' does not exist", 100));

dbTester.prepareDbUnit(getClass(), "shared.xml");

underTest.start();
underTest.getById(3);
underTest.getById(100);
}

@Test
@@ -129,4 +129,12 @@ public class MetricRepositoryImplTest {
assertThat(underTest.getById(2).getKey()).isEqualTo("coverage");
}

@Test
public void get_all_metrics() {
dbTester.prepareDbUnit(getClass(), "shared.xml");

underTest.start();
assertThat(underTest.getAll()).extracting("key").containsOnly("ncloc", "coverage", "sqale_index", "development_cost");
}

}

+ 355
- 0
server/sonar-server/src/test/java/org/sonar/server/computation/step/FillMeasuresWithVariationsStepTest.java 파일 보기

@@ -0,0 +1,355 @@
/*
* 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.step;

import java.util.Collections;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.sonar.api.utils.System2;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.component.SnapshotDto;
import org.sonar.core.measure.db.MeasureDto;
import org.sonar.core.metric.db.MetricDto;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.DbTester;
import org.sonar.core.rule.RuleDto;
import org.sonar.core.technicaldebt.db.CharacteristicDao;
import org.sonar.core.technicaldebt.db.CharacteristicDto;
import org.sonar.server.component.ComponentTesting;
import org.sonar.server.component.db.ComponentDao;
import org.sonar.server.component.db.SnapshotDao;
import org.sonar.server.computation.batch.BatchReportReaderRule;
import org.sonar.server.computation.batch.TreeRootHolderRule;
import org.sonar.server.computation.component.Component;
import org.sonar.server.computation.component.DumbComponent;
import org.sonar.server.computation.debt.Characteristic;
import org.sonar.server.computation.issue.RuleCache;
import org.sonar.server.computation.issue.RuleCacheLoader;
import org.sonar.server.computation.measure.Measure;
import org.sonar.server.computation.measure.MeasureRepository;
import org.sonar.server.computation.measure.MeasureRepositoryImpl;
import org.sonar.server.computation.metric.Metric;
import org.sonar.server.computation.metric.Metric.MetricType;
import org.sonar.server.computation.metric.MetricImpl;
import org.sonar.server.computation.metric.MetricRepositoryImpl;
import org.sonar.server.computation.period.Period;
import org.sonar.server.computation.period.PeriodsHolderRule;
import org.sonar.server.db.DbClient;
import org.sonar.server.measure.persistence.MeasureDao;
import org.sonar.server.metric.persistence.MetricDao;
import org.sonar.server.rule.RuleTesting;
import org.sonar.server.rule.db.RuleDao;
import org.sonar.test.DbTests;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.server.component.SnapshotTesting.createForComponent;
import static org.sonar.server.component.SnapshotTesting.createForProject;
import static org.sonar.server.computation.metric.Metric.MetricType.BOOL;
import static org.sonar.server.computation.metric.Metric.MetricType.FLOAT;
import static org.sonar.server.computation.metric.Metric.MetricType.INT;
import static org.sonar.server.metric.ws.MetricTesting.newMetricDto;

@Category(DbTests.class)
public class FillMeasuresWithVariationsStepTest {

static final MetricDto ISSUES_METRIC = newMetricDto().setKey("violations").setValueType(INT.name()).setEnabled(true);
static final MetricDto DEBT_METRIC = newMetricDto().setKey("sqale_index").setValueType(MetricType.WORK_DUR.name()).setEnabled(true);
static final MetricDto FILE_COMPLEXITY_METRIC = newMetricDto().setKey("file_complexity").setValueType(FLOAT.name()).setEnabled(true);
static final MetricDto BUILD_BREAKER_METRIC = newMetricDto().setKey("build_breaker").setValueType(BOOL.name()).setEnabled(true);

static final ComponentDto PROJECT_DTO = ComponentTesting.newProjectDto();

static final Component PROJECT = DumbComponent.builder(Component.Type.PROJECT, 1).setUuid(PROJECT_DTO.uuid()).build();

@ClassRule
public static DbTester dbTester = new DbTester();

@Rule
public BatchReportReaderRule reportReader = new BatchReportReaderRule();

@Rule
public PeriodsHolderRule periodsHolder = new PeriodsHolderRule();

@Rule
public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();

MeasureRepository measureRepository;

MetricRepositoryImpl metricRepository;

DbSession session;

DbClient dbClient;

FillMeasuresWithVariationsStep sut;

@Before
public void setUp() throws Exception {
dbTester.truncateTables();
session = dbTester.myBatis().openSession(false);
dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new ComponentDao(), new SnapshotDao(), new MetricDao(), new MeasureDao(), new RuleDao(System2.INSTANCE),
new CharacteristicDao(dbTester.myBatis()));

dbClient.metricDao().insert(session, ISSUES_METRIC, DEBT_METRIC, FILE_COMPLEXITY_METRIC, BUILD_BREAKER_METRIC);
dbClient.componentDao().insert(session, PROJECT_DTO);
session.commit();

metricRepository = new MetricRepositoryImpl(dbClient);
metricRepository.start();
measureRepository = new MeasureRepositoryImpl(dbClient, reportReader, metricRepository, new RuleCache(new RuleCacheLoader(dbClient)));

sut = new FillMeasuresWithVariationsStep(dbClient, treeRootHolder, periodsHolder, metricRepository, measureRepository);
}

@After
public void tearDown() throws Exception {
session.close();
}

@Test
public void do_nothing_when_no_raw_measure() throws Exception {
SnapshotDto period1ProjectSnapshot = createForProject(PROJECT_DTO);
dbClient.snapshotDao().insert(session, period1ProjectSnapshot);
dbClient.measureDao().insert(session, newMeasureDto(ISSUES_METRIC.getId(), PROJECT_DTO.getId(), period1ProjectSnapshot.getId(), 60d));
session.commit();

periodsHolder.addPeriod(newPeriod(1, period1ProjectSnapshot));

treeRootHolder.setRoot(PROJECT);

sut.execute();

assertThat(measureRepository.getRawMeasures(PROJECT).keys()).isEmpty();
}

@Test
public void do_nothing_when_no_period() throws Exception {
Component project = DumbComponent.builder(Component.Type.PROJECT, 1).setUuid(PROJECT_DTO.uuid()).build();
treeRootHolder.setRoot(project);

sut.execute();

assertThat(measureRepository.getRawMeasures(project).keys()).isEmpty();
}

@Test
public void set_variation() throws Exception {
// Project
SnapshotDto period1ProjectSnapshot = createForProject(PROJECT_DTO);
dbClient.snapshotDao().insert(session, period1ProjectSnapshot);
dbClient.measureDao().insert(session, newMeasureDto(ISSUES_METRIC.getId(), PROJECT_DTO.getId(), period1ProjectSnapshot.getId(), 60d));

// Directory
ComponentDto directoryDto = ComponentTesting.newDirectory(PROJECT_DTO, "dir");
dbClient.componentDao().insert(session, directoryDto);
SnapshotDto period1DirectorySnapshot = createForComponent(directoryDto, period1ProjectSnapshot);
dbClient.snapshotDao().insert(session, period1DirectorySnapshot);
dbClient.measureDao().insert(session, newMeasureDto(ISSUES_METRIC.getId(), directoryDto.getId(), period1DirectorySnapshot.getId(), 10d));
session.commit();

periodsHolder.addPeriod(newPeriod(1, period1ProjectSnapshot));

Component directory = DumbComponent.builder(Component.Type.DIRECTORY, 2).setUuid(directoryDto.uuid()).build();
Component project = DumbComponent.builder(Component.Type.PROJECT, 1).setUuid(PROJECT_DTO.uuid()).addChildren(directory).build();
treeRootHolder.setRoot(project);

addRawMeasure(project, ISSUES_METRIC, Measure.newMeasureBuilder().create(80, null));
addRawMeasure(directory, ISSUES_METRIC, Measure.newMeasureBuilder().create(20, null));

sut.execute();

assertThat(measureRepository.getRawMeasure(project, toMetric(ISSUES_METRIC)).get().getVariations().getVariation1()).isEqualTo(20d);
assertThat(measureRepository.getRawMeasure(directory, toMetric(ISSUES_METRIC)).get().getVariations().getVariation1()).isEqualTo(10d);
}

@Test
public void set_variations_on_all_periods() throws Exception {
SnapshotDto period1ProjectSnapshot = createForProject(PROJECT_DTO).setLast(false);
SnapshotDto period2ProjectSnapshot = createForProject(PROJECT_DTO).setLast(false);
SnapshotDto period3ProjectSnapshot = createForProject(PROJECT_DTO).setLast(false);
SnapshotDto period4ProjectSnapshot = createForProject(PROJECT_DTO).setLast(false);
SnapshotDto period5ProjectSnapshot = createForProject(PROJECT_DTO).setLast(false);
dbClient.snapshotDao().insert(session, period1ProjectSnapshot, period2ProjectSnapshot, period3ProjectSnapshot, period4ProjectSnapshot, period5ProjectSnapshot);

dbClient.measureDao().insert(session,
newMeasureDto(ISSUES_METRIC.getId(), PROJECT_DTO.getId(), period1ProjectSnapshot.getId(), 0d),
newMeasureDto(ISSUES_METRIC.getId(), PROJECT_DTO.getId(), period2ProjectSnapshot.getId(), 20d),
newMeasureDto(ISSUES_METRIC.getId(), PROJECT_DTO.getId(), period3ProjectSnapshot.getId(), 40d),
newMeasureDto(ISSUES_METRIC.getId(), PROJECT_DTO.getId(), period4ProjectSnapshot.getId(), 80d),
newMeasureDto(ISSUES_METRIC.getId(), PROJECT_DTO.getId(), period5ProjectSnapshot.getId(), 100d));
session.commit();

periodsHolder.addPeriod(newPeriod(1, period1ProjectSnapshot));
periodsHolder.addPeriod(newPeriod(2, period2ProjectSnapshot));
periodsHolder.addPeriod(newPeriod(3, period3ProjectSnapshot));
periodsHolder.addPeriod(newPeriod(4, period4ProjectSnapshot));
periodsHolder.addPeriod(newPeriod(5, period5ProjectSnapshot));

treeRootHolder.setRoot(PROJECT);

addRawMeasure(PROJECT, ISSUES_METRIC, Measure.newMeasureBuilder().create(80, null));

sut.execute();

assertThat(measureRepository.getRawMeasures(PROJECT).keys()).hasSize(1);

Measure measure = measureRepository.getRawMeasure(PROJECT, toMetric(ISSUES_METRIC)).get();
assertThat(measure.hasVariations()).isTrue();
assertThat(measure.getVariations().getVariation1()).isEqualTo(80d);
assertThat(measure.getVariations().getVariation2()).isEqualTo(60d);
assertThat(measure.getVariations().getVariation3()).isEqualTo(40d);
assertThat(measure.getVariations().getVariation4()).isEqualTo(0d);
assertThat(measure.getVariations().getVariation5()).isEqualTo(-20d);
}

@Test
public void set_variation_on_all_numeric_metrics() throws Exception {
SnapshotDto period1ProjectSnapshot = createForProject(PROJECT_DTO);
dbClient.snapshotDao().insert(session, period1ProjectSnapshot);
dbClient.measureDao().insert(session,
newMeasureDto(ISSUES_METRIC.getId(), PROJECT_DTO.getId(), period1ProjectSnapshot.getId(), 60d),
newMeasureDto(DEBT_METRIC.getId(), PROJECT_DTO.getId(), period1ProjectSnapshot.getId(), 10d),
newMeasureDto(FILE_COMPLEXITY_METRIC.getId(), PROJECT_DTO.getId(), period1ProjectSnapshot.getId(), 2d),
newMeasureDto(BUILD_BREAKER_METRIC.getId(), PROJECT_DTO.getId(), period1ProjectSnapshot.getId(), 1d)
);
session.commit();

periodsHolder.addPeriod(newPeriod(1, period1ProjectSnapshot));

treeRootHolder.setRoot(PROJECT);

addRawMeasure(PROJECT, ISSUES_METRIC, Measure.newMeasureBuilder().create(80, null));
addRawMeasure(PROJECT, DEBT_METRIC, Measure.newMeasureBuilder().create(5L, null));
addRawMeasure(PROJECT, FILE_COMPLEXITY_METRIC, Measure.newMeasureBuilder().create(3d, null));
addRawMeasure(PROJECT, BUILD_BREAKER_METRIC, Measure.newMeasureBuilder().create(false, null));

sut.execute();

assertThat(measureRepository.getRawMeasures(PROJECT).keys()).hasSize(4);

assertThat(measureRepository.getRawMeasure(PROJECT, toMetric(ISSUES_METRIC)).get().getVariations().getVariation1()).isEqualTo(20d);
assertThat(measureRepository.getRawMeasure(PROJECT, toMetric(DEBT_METRIC)).get().getVariations().getVariation1()).isEqualTo(-5d);
assertThat(measureRepository.getRawMeasure(PROJECT, toMetric(FILE_COMPLEXITY_METRIC)).get().getVariations().getVariation1()).isEqualTo(1d);
assertThat(measureRepository.getRawMeasure(PROJECT, toMetric(BUILD_BREAKER_METRIC)).get().getVariations().getVariation1()).isEqualTo(-1d);
}

@Test
public void set_variation_on_rule_measure() throws Exception {
SnapshotDto period1ProjectSnapshot = createForProject(PROJECT_DTO);
dbClient.snapshotDao().insert(session, period1ProjectSnapshot);

RuleDto rule1 = RuleTesting.newXooX1();
RuleDto rule2 = RuleTesting.newXooX2();
dbClient.ruleDao().insert(session, rule1, rule2);

dbClient.measureDao().insert(session, newMeasureDto(ISSUES_METRIC.getId(), PROJECT_DTO.getId(), period1ProjectSnapshot.getId(), 60d));
dbClient.measureDao().insert(session, newMeasureDto(ISSUES_METRIC.getId(), PROJECT_DTO.getId(), period1ProjectSnapshot.getId(), 40d).setRuleId(rule1.getId()));
dbClient.measureDao().insert(session, newMeasureDto(ISSUES_METRIC.getId(), PROJECT_DTO.getId(), period1ProjectSnapshot.getId(), 20d).setRuleId(rule2.getId()));
session.commit();

periodsHolder.addPeriod(newPeriod(1, period1ProjectSnapshot));

treeRootHolder.setRoot(PROJECT);

measureRepository.add(PROJECT, toMetric(ISSUES_METRIC), Measure.newMeasureBuilder().create(80, null));
measureRepository.add(PROJECT, toMetric(ISSUES_METRIC), Measure.newMeasureBuilder().forRule(rule1.getId()).create(45, null));
measureRepository.add(PROJECT, toMetric(ISSUES_METRIC), Measure.newMeasureBuilder().forRule(rule2.getId()).create(35, null));

sut.execute();

assertThat(measureRepository.getRawMeasure(PROJECT, toMetric(ISSUES_METRIC)).get().getVariations().getVariation1()).isEqualTo(20d);
assertThat(measureRepository.getRawMeasure(PROJECT, toMetric(ISSUES_METRIC), rule1).get().getVariations().getVariation1()).isEqualTo(5d);
assertThat(measureRepository.getRawMeasure(PROJECT, toMetric(ISSUES_METRIC), rule2).get().getVariations().getVariation1()).isEqualTo(15d);
}

@Test
public void set_variation_on_characteristic_measure() throws Exception {
SnapshotDto period1ProjectSnapshot = createForProject(PROJECT_DTO);
dbClient.snapshotDao().insert(session, period1ProjectSnapshot);

CharacteristicDto char1 = new CharacteristicDto().setKey("PORTABILITY");
CharacteristicDto char2 = new CharacteristicDto().setKey("MAINTAINABILITY");
dbClient.debtCharacteristicDao().insert(session, char1, char2);

dbClient.measureDao().insert(session, newMeasureDto(ISSUES_METRIC.getId(), PROJECT_DTO.getId(), period1ProjectSnapshot.getId(), 60d));
dbClient.measureDao().insert(session, newMeasureDto(ISSUES_METRIC.getId(), PROJECT_DTO.getId(), period1ProjectSnapshot.getId(), 40d).setCharacteristicId(char1.getId()));
dbClient.measureDao().insert(session, newMeasureDto(ISSUES_METRIC.getId(), PROJECT_DTO.getId(), period1ProjectSnapshot.getId(), 20d).setCharacteristicId(char2.getId()));
session.commit();

periodsHolder.addPeriod(newPeriod(1, period1ProjectSnapshot));

treeRootHolder.setRoot(PROJECT);

measureRepository.add(PROJECT, toMetric(ISSUES_METRIC), Measure.newMeasureBuilder().create(80, null));
measureRepository.add(PROJECT, toMetric(ISSUES_METRIC), Measure.newMeasureBuilder().forCharacteristic(char1.getId()).create(45, null));
measureRepository.add(PROJECT, toMetric(ISSUES_METRIC), Measure.newMeasureBuilder().forCharacteristic(char2.getId()).create(35, null));

sut.execute();

assertThat(measureRepository.getRawMeasure(PROJECT, toMetric(ISSUES_METRIC)).get().getVariations().getVariation1()).isEqualTo(20d);
assertThat(measureRepository.getRawMeasure(PROJECT, toMetric(ISSUES_METRIC), new Characteristic(char1.getId(), char1.getKey())).get().getVariations().getVariation1())
.isEqualTo(5d);
assertThat(measureRepository.getRawMeasure(PROJECT, toMetric(ISSUES_METRIC), new Characteristic(char2.getId(), char2.getKey())).get().getVariations().getVariation1())
.isEqualTo(15d);
}

@Test
public void read_measure_from_batch() throws Exception {
// Project
SnapshotDto period1ProjectSnapshot = createForProject(PROJECT_DTO);
dbClient.snapshotDao().insert(session, period1ProjectSnapshot);
dbClient.measureDao().insert(session, newMeasureDto(ISSUES_METRIC.getId(), PROJECT_DTO.getId(), period1ProjectSnapshot.getId(), 60d));
session.commit();

periodsHolder.addPeriod(newPeriod(1, period1ProjectSnapshot));

treeRootHolder.setRoot(PROJECT);

reportReader.putMeasures(PROJECT.getRef(), Collections.singletonList(
BatchReport.Measure.newBuilder().setIntValue(80).setMetricKey(ISSUES_METRIC.getKey()).build())
);

sut.execute();

assertThat(measureRepository.getRawMeasure(PROJECT, toMetric(ISSUES_METRIC)).get().getVariations().getVariation1()).isEqualTo(20d);
}

private static MeasureDto newMeasureDto(int metricId, long projectId, long snapshotId, double value) {
return new MeasureDto().setMetricId(metricId).setComponentId(projectId).setSnapshotId(snapshotId).setValue(value);
}

private static Period newPeriod(int index, SnapshotDto snapshotDto) {
return new Period(index, null, null, snapshotDto.getCreatedAt(), snapshotDto.getId());
}

private void addRawMeasure(Component component, MetricDto metric, Measure measure) {
measureRepository.add(component, new MetricImpl(metric.getId(), metric.getKey(), metric.getShortName(), MetricType.valueOf(metric.getValueType())), measure);
}

private static Metric toMetric(MetricDto metric) {
return new MetricImpl(metric.getId(), metric.getKey(), metric.getShortName(), Metric.MetricType.valueOf(metric.getValueType()));
}
}

+ 128
- 5
server/sonar-server/src/test/java/org/sonar/server/measure/persistence/MeasureDaoTest.java 파일 보기

@@ -20,6 +20,7 @@

package org.sonar.server.measure.persistence;

import com.google.common.collect.ImmutableSet;
import java.util.List;
import org.junit.After;
import org.junit.Before;
@@ -27,6 +28,7 @@ import org.junit.ClassRule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.sonar.core.measure.db.MeasureDto;
import org.sonar.core.measure.db.PastMeasureDto;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.DbTester;
import org.sonar.test.DbTests;
@@ -140,6 +142,127 @@ public class MeasureDaoTest {
assertThat(sut.existsByKey(session, "org.struts:struts-core:src/org/struts/RequestContext.java", "unknown")).isFalse();
}

@Test
public void select_past_measures_by_component_uuid_and_root_snapshot_id_and_metric_keys() {
db.prepareDbUnit(getClass(), "past_measures.xml");

List<PastMeasureDto> fileMeasures = sut.selectByComponentUuidAndProjectSnapshotIdAndMetricIds(session, "CDEF", 1000L, ImmutableSet.of(1, 2));
assertThat(fileMeasures).hasSize(2);

PastMeasureDto fileMeasure1 = fileMeasures.get(0);
assertThat(fileMeasure1.getValue()).isEqualTo(5d);
assertThat(fileMeasure1.getMetricId()).isEqualTo(1);
assertThat(fileMeasure1.getRuleId()).isNull();
assertThat(fileMeasure1.getCharacteristicId()).isNull();
assertThat(fileMeasure1.getPersonId()).isNull();

PastMeasureDto fileMeasure2 = fileMeasures.get(1);
assertThat(fileMeasure2.getValue()).isEqualTo(60d);
assertThat(fileMeasure2.getMetricId()).isEqualTo(2);

List<PastMeasureDto> projectMeasures = sut.selectByComponentUuidAndProjectSnapshotIdAndMetricIds(session, "ABCD", 1000L, ImmutableSet.of(1, 2));
assertThat(projectMeasures).hasSize(2);

PastMeasureDto projectMeasure1 = projectMeasures.get(0);
assertThat(projectMeasure1.getValue()).isEqualTo(60d);
assertThat(projectMeasure1.getMetricId()).isEqualTo(1);

PastMeasureDto projectMeasure2 = projectMeasures.get(1);
assertThat(projectMeasure2.getValue()).isEqualTo(80d);
assertThat(projectMeasure2.getMetricId()).isEqualTo(2);

assertThat(sut.selectByComponentUuidAndProjectSnapshotIdAndMetricIds(session, "UNKNOWN", 1000L, ImmutableSet.of(1, 2))).isEmpty();
assertThat(sut.selectByComponentUuidAndProjectSnapshotIdAndMetricIds(session, "CDEF", 987654L, ImmutableSet.of(1, 2))).isEmpty();
assertThat(sut.selectByComponentUuidAndProjectSnapshotIdAndMetricIds(session, "CDEF", 1000L, ImmutableSet.of(123, 456))).isEmpty();
}

@Test
public void select_past_measures_on_rule_by_component_uuid_and_root_snapshot_id_and_metric_keys() {
db.prepareDbUnit(getClass(), "past_measures_with_rule_id.xml");

List<PastMeasureDto> measures = sut.selectByComponentUuidAndProjectSnapshotIdAndMetricIds(session, "ABCD", 1000L, ImmutableSet.of(1));
assertThat(measures).hasSize(3);

PastMeasureDto measure1 = measures.get(0);
assertThat(measure1.getValue()).isEqualTo(60d);
assertThat(measure1.getMetricId()).isEqualTo(1);
assertThat(measure1.getRuleId()).isNull();
assertThat(measure1.getCharacteristicId()).isNull();
assertThat(measure1.getPersonId()).isNull();

PastMeasureDto measure2 = measures.get(1);
assertThat(measure2.getValue()).isEqualTo(20d);
assertThat(measure2.getMetricId()).isEqualTo(1);
assertThat(measure2.getRuleId()).isEqualTo(30);
assertThat(measure2.getCharacteristicId()).isNull();
assertThat(measure2.getPersonId()).isNull();

PastMeasureDto measure3 = measures.get(2);
assertThat(measure3.getValue()).isEqualTo(40d);
assertThat(measure3.getMetricId()).isEqualTo(1);
assertThat(measure3.getRuleId()).isEqualTo(31);
assertThat(measure3.getCharacteristicId()).isNull();
assertThat(measure3.getPersonId()).isNull();
}

@Test
public void select_past_measures_on_characteristic_by_component_uuid_and_root_snapshot_id_and_metric_keys() {
db.prepareDbUnit(getClass(), "past_measures_with_characteristic_id.xml");

List<PastMeasureDto> measures = sut.selectByComponentUuidAndProjectSnapshotIdAndMetricIds(session, "ABCD", 1000L, ImmutableSet.of(1));
assertThat(measures).hasSize(3);

PastMeasureDto measure1 = measures.get(0);
assertThat(measure1.getValue()).isEqualTo(60d);
assertThat(measure1.getMetricId()).isEqualTo(1);
assertThat(measure1.getRuleId()).isNull();
assertThat(measure1.getCharacteristicId()).isNull();
assertThat(measure1.getPersonId()).isNull();

PastMeasureDto measure2 = measures.get(1);
assertThat(measure2.getValue()).isEqualTo(20d);
assertThat(measure2.getMetricId()).isEqualTo(1);
assertThat(measure2.getRuleId()).isNull();
assertThat(measure2.getCharacteristicId()).isEqualTo(10);
assertThat(measure2.getPersonId()).isNull();

PastMeasureDto measure3 = measures.get(2);
assertThat(measure3.getValue()).isEqualTo(40d);
assertThat(measure3.getMetricId()).isEqualTo(1);
assertThat(measure3.getRuleId()).isNull();
assertThat(measure3.getCharacteristicId()).isEqualTo(11);
assertThat(measure3.getPersonId()).isNull();
}

@Test
public void select_past_measures_on_person_by_component_uuid_and_root_snapshot_id_and_metric_keys() {
db.prepareDbUnit(getClass(), "past_measures_with_person_id.xml");

List<PastMeasureDto> measures = sut.selectByComponentUuidAndProjectSnapshotIdAndMetricIds(session, "ABCD", 1000L, ImmutableSet.of(1));
assertThat(measures).hasSize(3);

PastMeasureDto measure1 = measures.get(0);
assertThat(measure1.getValue()).isEqualTo(60d);
assertThat(measure1.getMetricId()).isEqualTo(1);
assertThat(measure1.getRuleId()).isNull();
assertThat(measure1.getCharacteristicId()).isNull();
assertThat(measure1.getPersonId()).isNull();

PastMeasureDto measure2 = measures.get(1);
assertThat(measure2.getValue()).isEqualTo(20d);
assertThat(measure2.getMetricId()).isEqualTo(1);
assertThat(measure2.getRuleId()).isNull();
assertThat(measure2.getCharacteristicId()).isNull();
assertThat(measure2.getPersonId()).isEqualTo(20);

PastMeasureDto measure3 = measures.get(2);
assertThat(measure3.getValue()).isEqualTo(40d);
assertThat(measure3.getMetricId()).isEqualTo(1);
assertThat(measure3.getRuleId()).isNull();
assertThat(measure3.getCharacteristicId()).isNull();
assertThat(measure3.getPersonId()).isEqualTo(21);
}

@Test
public void insert() {
db.prepareDbUnit(getClass(), "empty.xml");
@@ -172,16 +295,16 @@ public class MeasureDaoTest {
db.prepareDbUnit(getClass(), "empty.xml");

sut.insert(session, new MeasureDto()
.setSnapshotId(2L)
.setMetricId(3)
.setComponentId(6L)
.setValue(2.0d),
.setSnapshotId(2L)
.setMetricId(3)
.setComponentId(6L)
.setValue(2.0d),
new MeasureDto()
.setSnapshotId(3L)
.setMetricId(4)
.setComponentId(6L)
.setValue(4.0d)
);
);
session.commit();

assertThat(db.countRowsOfTable("project_measures")).isEqualTo(2);

+ 9
- 5
server/sonar-server/src/test/resources/org/sonar/server/computation/metric/MetricRepositoryImplTest/shared.xml 파일 보기

@@ -1,7 +1,11 @@
<dataset>
<!-- enabled metrics -->
<metrics id="1" name="ncloc" VAL_TYPE="INT" short_name="ncloc_name" enabled="[true]" />
<metrics id="2" name="coverage" VAL_TYPE="INT" short_name="coverage_name" enabled="[true]" />
<!-- disabled metric -->
<metrics id="3" name="complexity" VAL_TYPE="INT" short_name="complexity_name" enabled="[false]" />
<!-- enabled metrics -->
<metrics id="1" name="ncloc" VAL_TYPE="INT" short_name="ncloc_name" enabled="[true]"/>
<metrics id="2" name="coverage" VAL_TYPE="INT" short_name="coverage_name" enabled="[true]"/>
<metrics id="3" name="sqale_index" VAL_TYPE="WORK_DUR" short_name="sqale_index" enabled="[true]"/>
<metrics id="4" name="development_cost" VAL_TYPE="STRING" short_name="development_cost" enabled="[true]"/>

<!-- disabled metric -->
<metrics id="100" name="complexity" VAL_TYPE="INT" short_name="complexity_name" enabled="[false]"/>

</dataset>

+ 51
- 0
server/sonar-server/src/test/resources/org/sonar/server/computation/step/FillMeasuresWithVariationsStepTest/shared.xml 파일 보기

@@ -0,0 +1,51 @@
<dataset>

<metrics id="1" name="ncloc" short_name="ncloc" VAL_TYPE="INT" enabled="true"/>
<metrics id="2" name="coverage" short_name="coverage" VAL_TYPE="PERCENT" enabled="true"/>
<metrics id="3" name="file_complexity" short_name="file_complexity" VAL_TYPE="FLOAT" enabled="true"/>
<metrics id="4" name="test_execution_time" short_name="test_execution_time" VAL_TYPE="MILLISEC" enabled="true"/>

<rules id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck"
plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle"/>

<rules id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck"
plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle"/>

<!-- project -->
<projects id="1" scope="PRJ" qualifier="TRK" kee="PROJECT_KEY" name="project"
root_id="[null]" uuid="ABCD" project_uuid="ABCD" module_uuid="[null]" module_uuid_path=".ABCD."
enabled="true"/>

<!-- directory -->
<projects id="2" scope="DIR" qualifier="PAC" kee="DIRECTORY_KEY" name="org.foo"
root_id="1" uuid="BCDE" project_uuid="ABCD" module_uuid="ABCD" module_uuid_path=".ABCD."
enabled="true"/>

<!-- snapshots -->
<snapshots id="1000" project_id="1" root_project_id="1" root_snapshot_id="[null]"
scope="PRJ" qualifier="TRK" created_at="1225544280000" build_date="1225544280000"
status="P" islast="false"/>
<snapshots id="1001" project_id="2" root_project_id="1" root_snapshot_id="1000"
scope="DIR" qualifier="PAC" created_at="1225544280000" build_date="1225544280000"
status="P" islast="false"/>


<!-- project measures -->
<project_measures id="1" VALUE="60" METRIC_ID="1" SNAPSHOT_ID="1000"
RULE_ID="[null]" text_value="[null]" measure_date="[null]" project_id="[null]"
characteristic_id="[null]" url="[null]" person_id="[null]"/>

<project_measures id="2" VALUE="80" METRIC_ID="2" SNAPSHOT_ID="1000"
RULE_ID="[null]" text_value="[null]" measure_date="[null]" project_id="[null]"
characteristic_id="[null]" url="[null]" person_id="[null]"/>

<!-- package measures -->
<project_measures id="3" VALUE="20" METRIC_ID="1" SNAPSHOT_ID="1001"
RULE_ID="[null]" text_value="[null]" measure_date="[null]" project_id="[null]"
characteristic_id="[null]" url="[null]" person_id="[null]"/>

<project_measures id="4" VALUE="70" METRIC_ID="2" SNAPSHOT_ID="1001"
RULE_ID="[null]" text_value="[null]" measure_date="[null]" project_id="[null]"
characteristic_id="[null]" url="[null]" person_id="[null]"/>

</dataset>

+ 87
- 0
server/sonar-server/src/test/resources/org/sonar/server/measure/persistence/MeasureDaoTest/past_measures.xml 파일 보기

@@ -0,0 +1,87 @@
<dataset>

<metrics delete_historical_data="[null]" id="1" name="ncloc" VAL_TYPE="INT" DESCRIPTION="[null]" domain="[null]" short_name=""
enabled="true" worst_value="[null]" optimized_best_value="[null]" best_value="[null]" direction="0" hidden="false"/>

<metrics delete_historical_data="[null]" id="2" name="coverage" VAL_TYPE="INT" DESCRIPTION="[null]" domain="[null]" short_name=""
enabled="true" worst_value="0" optimized_best_value="true" best_value="100" direction="1" hidden="false"/>


<rules tags="[null]" system_tags="[null]" id="30" name="Check Header" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck"
plugin_config_key="Checker/Treewalker/HeaderCheck" plugin_name="checkstyle" description="[null]" priority="4" status="READY"
is_template="[false]" template_id="[null]"/>

<rules tags="[null]" system_tags="[null]" id="31" name="Equals Avoid Null" plugin_rule_key="com.puppycrawl.tools.checkstyle.checks.coding.EqualsAvoidNullCheck"
plugin_config_key="Checker/TreeWalker/EqualsAvoidNull" plugin_name="checkstyle" description="[null]" priority="4" status="READY"
is_template="[false]" template_id="[null]"/>

<!-- project -->
<projects long_name="[null]" id="1" scope="PRJ" qualifier="TRK" kee="project" name="project"
root_id="[null]" uuid="ABCD" project_uuid="ABCD" module_uuid="[null]" module_uuid_path=".ABCD."
description="[null]"
enabled="true" language="java" copy_resource_id="[null]"/>

<!-- package -->
<projects long_name="[null]" id="2" scope="DIR" qualifier="PAC" kee="project:org.foo" name="org.foo"
root_id="1" uuid="BCDE" project_uuid="ABCD" module_uuid="ABCD" module_uuid_path=".ABCD."
description="[null]"
enabled="true" language="java" copy_resource_id="[null]"/>

<!-- file -->
<projects long_name="org.foo.Bar" id="3" scope="FIL" qualifier="CLA" kee="project:org.foo.Bar"
name="Bar" root_id="[null]" uuid="CDEF" project_uuid="ABCD" module_uuid="ABCD" module_uuid_path=".ABCD."
description="[null]"
enabled="true" language="java" copy_resource_id="[null]"/>


<!-- snapshots -->
<snapshots purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]"
period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]"
period5_param="[null]" period5_date="[null]" id="1000" project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
scope="PRJ" qualifier="TRK" created_at="1225544280000" build_date="1225544280000" version="[null]" path=""
status="P" islast="false" depth="0"/>
<snapshots purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]"
period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]"
period5_param="[null]" period5_date="[null]" id="1001" project_id="2" parent_snapshot_id="1000" root_project_id="1" root_snapshot_id="1000"
scope="DIR" qualifier="PAC" created_at="1225544280000" build_date="1225544280000" version="[null]" path="1000."
status="P" islast="false" depth="1"/>
<snapshots purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]"
period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]"
period5_param="[null]" period5_date="[null]" id="1002" project_id="3" parent_snapshot_id="1001" root_project_id="1" root_snapshot_id="1000"
scope="FIL" qualifier="CLA" created_at="1225544280000" build_date="1225544280000" version="[null]" path="1000.1001."
status="P" islast="false" depth="2"/>


<!-- project measures -->
<project_measures id="1" VALUE="60" METRIC_ID="1" SNAPSHOT_ID="1000" alert_text="[null]" RULES_CATEGORY_ID="[null]"
RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]" person_id="[null]"
variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]" variation_value_4="[null]" variation_value_5="[null]"/>

<project_measures id="2" VALUE="80" METRIC_ID="2" SNAPSHOT_ID="1000" alert_text="[null]" RULES_CATEGORY_ID="[null]"
RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]" person_id="[null]"
variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]" variation_value_4="[null]" variation_value_5="[null]"/>

<!-- package measures -->
<project_measures id="3" VALUE="20" METRIC_ID="1" SNAPSHOT_ID="1001" alert_text="[null]" RULES_CATEGORY_ID="[null]"
RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]" person_id="[null]"
variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]" variation_value_4="[null]" variation_value_5="[null]"/>

<project_measures id="4" VALUE="70" METRIC_ID="2" SNAPSHOT_ID="1001" alert_text="[null]" RULES_CATEGORY_ID="[null]"
RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]" person_id="[null]"
variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]" variation_value_4="[null]" variation_value_5="[null]"/>

<!-- file measures -->
<project_measures id="5" VALUE="5" METRIC_ID="1" SNAPSHOT_ID="1002" alert_text="[null]" RULES_CATEGORY_ID="[null]"
RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]" person_id="[null]"
variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]" variation_value_4="[null]" variation_value_5="[null]"/>

<project_measures id="6" VALUE="60" METRIC_ID="2" SNAPSHOT_ID="1002" alert_text="[null]" RULES_CATEGORY_ID="[null]"
RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]" person_id="[null]"
variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]" variation_value_4="[null]" variation_value_5="[null]"/>
</dataset>

+ 28
- 0
server/sonar-server/src/test/resources/org/sonar/server/measure/persistence/MeasureDaoTest/past_measures_with_characteristic_id.xml 파일 보기

@@ -0,0 +1,28 @@
<dataset>

<metrics id="1" name="sqale_index" VAL_TYPE="WORK_DUR" DESCRIPTION="[null]" short_name="" enabled="true"/>

<!-- Root characteristic -->
<characteristics id="10" kee="PORTABILITY" name="Portability" parent_id="[null]" characteristic_order="1" enabled="[true]" created_at="2013-11-20" updated_at="2013-11-22"/>

<!-- Characteristic -->
<characteristics id="11" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="10" characteristic_order="[null]" enabled="[true]"
created_at="2013-11-20" updated_at="2013-11-22"/>

<!-- project -->
<projects long_name="[null]" id="1" scope="PRJ" qualifier="TRK" kee="project" name="project"
root_id="[null]" uuid="ABCD" project_uuid="ABCD" module_uuid="[null]" module_uuid_path=".ABCD." enabled="true"/>

<!-- snapshots -->
<snapshots id="1000" project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
scope="PRJ" qualifier="TRK" created_at="1225544280000" build_date="1225544280000" version="[null]" path=""
status="P" islast="false" depth="0"/>

<!-- project measures -->
<project_measures id="1" VALUE="60" METRIC_ID="1" SNAPSHOT_ID="1000" RULE_ID="[null]" characteristic_id="[null]"/>

<project_measures id="2" VALUE="20" METRIC_ID="1" SNAPSHOT_ID="1000" RULE_ID="[null]" characteristic_id="10"/>

<project_measures id="3" VALUE="40" METRIC_ID="1" SNAPSHOT_ID="1000" RULE_ID="[null]" characteristic_id="11"/>

</dataset>

+ 35
- 0
server/sonar-server/src/test/resources/org/sonar/server/measure/persistence/MeasureDaoTest/past_measures_with_person_id.xml 파일 보기

@@ -0,0 +1,35 @@
<dataset>

<metrics delete_historical_data="[null]" id="1" name="sqale_index" VAL_TYPE="INT" DESCRIPTION="[null]" domain="[null]" short_name=""
enabled="true" worst_value="[null]" optimized_best_value="[null]" best_value="[null]" direction="0" hidden="false"/>

<!-- project -->
<projects long_name="[null]" id="1" scope="PRJ" qualifier="TRK" kee="project" name="project"
root_id="[null]" uuid="ABCD" project_uuid="ABCD" module_uuid="[null]" module_uuid_path=".ABCD."
description="[null]"
enabled="true" language="java" copy_resource_id="[null]"/>

<!-- snapshots -->
<snapshots purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]"
period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]"
period5_param="[null]" period5_date="[null]" id="1000" project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
scope="PRJ" qualifier="TRK" created_at="1225544280000" build_date="1225544280000" version="[null]" path=""
status="P" islast="false" depth="0"/>

<!-- project measures -->
<project_measures id="1" VALUE="60" METRIC_ID="1" SNAPSHOT_ID="1000" alert_text="[null]" RULES_CATEGORY_ID="[null]"
RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]" person_id="[null]"
variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]" variation_value_4="[null]" variation_value_5="[null]"/>

<project_measures id="2" VALUE="20" METRIC_ID="1" SNAPSHOT_ID="1000" alert_text="[null]" RULES_CATEGORY_ID="[null]"
RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]" person_id="20"
variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]" variation_value_4="[null]" variation_value_5="[null]"/>

<project_measures id="3" VALUE="40" METRIC_ID="1" SNAPSHOT_ID="1000" alert_text="[null]" RULES_CATEGORY_ID="[null]"
RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]" person_id="21"
variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]" variation_value_4="[null]" variation_value_5="[null]"/>

</dataset>

+ 45
- 0
server/sonar-server/src/test/resources/org/sonar/server/measure/persistence/MeasureDaoTest/past_measures_with_rule_id.xml 파일 보기

@@ -0,0 +1,45 @@
<dataset>

<metrics delete_historical_data="[null]" id="1" name="minor_violations" VAL_TYPE="INT" DESCRIPTION="[null]" domain="[null]" short_name=""
enabled="true" worst_value="[null]" optimized_best_value="[null]" best_value="[null]" direction="0" hidden="false"/>

<rules tags="[null]" system_tags="[null]" id="30" name="Classes that override clone should be Cloneable and call super.clone()"
plugin_rule_key="S1182"
plugin_config_key="S1182" plugin_name="squid" description="[null]" priority="4" status="READY"
is_template="[false]" template_id="[null]"/>

<rules tags="[null]" system_tags="[null]" id="31" name="Overriding methods should do more than simply call the same method in the super class"
plugin_rule_key="S1185"
plugin_config_key="S1185" plugin_name="squid" description="[null]" priority="1" status="READY"
is_template="[false]" template_id="[null]"/>

<!-- project -->
<projects long_name="[null]" id="1" scope="PRJ" qualifier="TRK" kee="project" name="project"
root_id="[null]" uuid="ABCD" project_uuid="ABCD" module_uuid="[null]" module_uuid_path=".ABCD."
description="[null]"
enabled="true" language="java" copy_resource_id="[null]"/>

<!-- snapshots -->
<snapshots purge_status="[null]" period1_mode="[null]" period1_param="[null]" period1_date="[null]" period2_mode="[null]" period2_param="[null]" period2_date="[null]"
period3_mode="[null]" period3_param="[null]" period3_date="[null]" period4_mode="[null]" period4_param="[null]" period4_date="[null]" period5_mode="[null]"
period5_param="[null]" period5_date="[null]" id="1000" project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
scope="PRJ" qualifier="TRK" created_at="1225544280000" build_date="1225544280000" version="[null]" path=""
status="P" islast="false" depth="0"/>

<!-- project measures -->
<project_measures id="1" VALUE="60" METRIC_ID="1" SNAPSHOT_ID="1000" alert_text="[null]" RULES_CATEGORY_ID="[null]"
RULE_ID="[null]" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]" person_id="[null]"
variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]" variation_value_4="[null]" variation_value_5="[null]"/>

<project_measures id="2" VALUE="20" METRIC_ID="1" SNAPSHOT_ID="1000" alert_text="[null]" RULES_CATEGORY_ID="[null]"
RULE_ID="30" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]" person_id="[null]"
variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]" variation_value_4="[null]" variation_value_5="[null]"/>

<project_measures id="3" VALUE="40" METRIC_ID="1" SNAPSHOT_ID="1000" alert_text="[null]" RULES_CATEGORY_ID="[null]"
RULE_ID="31" text_value="[null]" tendency="[null]" measure_date="[null]" project_id="[null]"
alert_status="[null]" description="[null]" rule_priority="[null]" characteristic_id="[null]" url="[null]" person_id="[null]"
variation_value_1="[null]" variation_value_2="[null]" variation_value_3="[null]" variation_value_4="[null]" variation_value_5="[null]"/>

</dataset>

+ 5
- 4
sonar-core/src/main/java/org/sonar/core/measure/db/MeasureMapper.java 파일 보기

@@ -20,11 +20,9 @@

package org.sonar.core.measure.db;

import org.apache.ibatis.annotations.Param;

import javax.annotation.CheckForNull;

import java.util.List;
import javax.annotation.CheckForNull;
import org.apache.ibatis.annotations.Param;

public interface MeasureMapper {

@@ -35,6 +33,9 @@ public interface MeasureMapper {
@CheckForNull
MeasureDto selectByComponentAndMetric(@Param("componentKey") String componentKey, @Param("metricKey") String metricKey);

List<PastMeasureDto> selectByComponentUuidAndProjectSnapshotIdAndStatusAndMetricIds(@Param("componentUuid") String componentuuid, @Param("rootSnapshotId") long rootSnapshotId,
@Param("metricIds") List<Integer> metricIds, @Param("status") String status);

long countByComponentAndMetric(@Param("componentKey") String componentKey, @Param("metricKey") String metricKey);

void insert(MeasureDto measureDto);

+ 87
- 0
sonar-core/src/main/java/org/sonar/core/measure/db/PastMeasureDto.java 파일 보기

@@ -0,0 +1,87 @@
/*
* 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.measure.db;

import java.util.Objects;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

public class PastMeasureDto {

private Double value;
private Integer metricId;
private Integer ruleId;
private Integer characteristicId;
private Integer personId;

public double getValue() {
Objects.requireNonNull(value);
return value;
}

public PastMeasureDto setValue(@Nullable Double value) {
this.value = value;
return this;
}

public boolean hasValue() {
return value != null;
}

public Integer getMetricId() {
return metricId;
}

public PastMeasureDto setMetricId(Integer metricId) {
this.metricId = metricId;
return this;
}

@CheckForNull
public Integer getCharacteristicId() {
return characteristicId;
}

public PastMeasureDto setCharacteristicId(@Nullable Integer characteristicId) {
this.characteristicId = characteristicId;
return this;
}

@CheckForNull
public Integer getPersonId() {
return personId;
}

public PastMeasureDto setPersonId(@Nullable Integer personId) {
this.personId = personId;
return this;
}

@CheckForNull
public Integer getRuleId() {
return ruleId;
}

public PastMeasureDto setRuleId(@Nullable Integer ruleId) {
this.ruleId = ruleId;
return this;
}
}

+ 15
- 0
sonar-core/src/main/resources/org/sonar/core/measure/db/MeasureMapper.xml 파일 보기

@@ -70,6 +70,21 @@
</where>
</select>

<select id="selectByComponentUuidAndProjectSnapshotIdAndStatusAndMetricIds" parameterType="map" resultType="org.sonar.core.measure.db.PastMeasureDto">
SELECT pm.metric_id as metricId, pm.rule_id as ruleId, pm.characteristic_id as characteristicId, pm.person_id as personId, pm.value as value
FROM project_measures pm
INNER JOIN snapshots s ON s.id=pm.snapshot_id AND s.status=#{status}
INNER JOIN projects p ON p.id=s.project_id AND p.enabled=${_true}
<where>
AND p.uuid = #{componentUuid}
AND (s.root_snapshot_id=#{rootSnapshotId} OR s.id=#{rootSnapshotId})
AND
<foreach item="metricId" index="index" collection="metricIds" open="(" separator=" or " close=")">
pm.metric_id=#{metricId}
</foreach>
</where>
</select>

<insert id="insert" parameterType="Measure" useGeneratedKeys="false">
INSERT INTO project_measures (
value, metric_id, snapshot_id, rule_id, text_value, project_id, alert_status, alert_text, description,

+ 50
- 0
sonar-core/src/test/java/org/sonar/core/measure/db/PastMeasureDtoTest.java 파일 보기

@@ -0,0 +1,50 @@
/*
* 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.measure.db;

import org.junit.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class PastMeasureDtoTest {

@Test
public void test_getter_and_setter() throws Exception {
PastMeasureDto dto = new PastMeasureDto()
.setValue(1d)
.setMetricId(2)
.setRuleId(3)
.setCharacteristicId(4)
.setPersonId(5);

assertThat(dto.hasValue()).isTrue();
assertThat(dto.getValue()).isEqualTo(1d);
assertThat(dto.getMetricId()).isEqualTo(2);
assertThat(dto.getRuleId()).isEqualTo(3);
assertThat(dto.getCharacteristicId()).isEqualTo(4);
assertThat(dto.getPersonId()).isEqualTo(5);
}

@Test(expected = NullPointerException.class)
public void get_value_throw_a_NPE_if_value_is_null() throws Exception {
new PastMeasureDto().getValue();
}
}

Loading…
취소
저장