@@ -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(); | |||
} | |||
} |
@@ -39,4 +39,9 @@ public interface MetricRepository { | |||
*/ | |||
Metric getById(long id); | |||
/** | |||
* Get iterable of all {@link Metric}. | |||
*/ | |||
Iterable<Metric> getAll(); | |||
} |
@@ -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"); |
@@ -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, |
@@ -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()); | |||
} | |||
@@ -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"; | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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"); | |||
} | |||
} |
@@ -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())); | |||
} | |||
} |
@@ -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); |
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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); |
@@ -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; | |||
} | |||
} |
@@ -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, |
@@ -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(); | |||
} | |||
} |