--- /dev/null
+----------------------------------------------------------------
+Thu Apr 28 00:17:56 CEST 2011:
+Booting Derby version The Apache Software Foundation - Apache Derby - 10.7.1.1 - (1040133): instance a816c00e-012f-990a-3e0e-000004e64398
+on database directory memory:/Users/sbrandhof/projects/github/sonar/plugins/sonar-core-plugin/sonar with class loader sun.misc.Launcher$AppClassLoader@1ef6a746
+Loaded from file:/Users/sbrandhof/.m2/repository/org/apache/derby/derby/10.7.1.1/derby-10.7.1.1.jar
+java.vendor=Apple Inc.
+java.runtime.version=1.6.0_24-b07-334-10M3326
+Database Class Loader started - derby.database.classpath=''
+----------------------------------------------------------------
+Thu Apr 28 00:18:01 CEST 2011:
+Shutting down instance a816c00e-012f-990a-3e0e-000004e64398 on database directory memory:/Users/sbrandhof/projects/github/sonar/plugins/sonar-core-plugin/sonar with class loader sun.misc.Launcher$AppClassLoader@1ef6a746
+Thu Apr 28 00:18:01 CEST 2011 Thread[main,5,main] Cleanup action starting
+java.sql.SQLException: Database 'memory:sonar' not found.
+ at org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(Unknown Source)
+ at org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Unknown Source)
+ at org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Unknown Source)
+ at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Unknown Source)
+ at org.apache.derby.impl.jdbc.EmbedConnection.newSQLException(Unknown Source)
+ at org.apache.derby.impl.jdbc.EmbedConnection.handleDBNotFound(Unknown Source)
+ at org.apache.derby.impl.jdbc.EmbedConnection.<init>(Unknown Source)
+ at org.apache.derby.impl.jdbc.EmbedConnection30.<init>(Unknown Source)
+ at org.apache.derby.impl.jdbc.EmbedConnection40.<init>(Unknown Source)
+ at org.apache.derby.jdbc.Driver40.getNewEmbedConnection(Unknown Source)
+ at org.apache.derby.jdbc.InternalDriver.connect(Unknown Source)
+ at org.apache.derby.jdbc.EmbeddedDriver.connect(Unknown Source)
+ at java.sql.DriverManager.getConnection(DriverManager.java:582)
+ at java.sql.DriverManager.getConnection(DriverManager.java:207)
+ at org.sonar.test.persistence.DatabaseTestCase.stopDatabase(DatabaseTestCase.java:89)
+ at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+ at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+ at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+ at java.lang.reflect.Method.invoke(Method.java:597)
+ at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
+ at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
+ at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
+ at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:37)
+ at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
+ at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:59)
+ at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:120)
+ at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:145)
+ at org.apache.maven.surefire.Surefire.run(Surefire.java:104)
+ at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+ at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+ at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+ at java.lang.reflect.Method.invoke(Method.java:597)
+ at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:290)
+ at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1017)
+Caused by: java.sql.SQLException: Database 'memory:sonar' not found.
+ at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source)
+ at org.apache.derby.impl.jdbc.SQLExceptionFactory40.wrapArgsForTransportAcrossDRDA(Unknown Source)
+ ... 34 more
+============= begin nested exception, level (1) ===========
+java.sql.SQLException: Database 'memory:sonar' not found.
+ at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source)
+ at org.apache.derby.impl.jdbc.SQLExceptionFactory40.wrapArgsForTransportAcrossDRDA(Unknown Source)
+ at org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(Unknown Source)
+ at org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Unknown Source)
+ at org.apache.derby.impl.jdbc.Util.newEmbedSQLException(Unknown Source)
+ at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Unknown Source)
+ at org.apache.derby.impl.jdbc.EmbedConnection.newSQLException(Unknown Source)
+ at org.apache.derby.impl.jdbc.EmbedConnection.handleDBNotFound(Unknown Source)
+ at org.apache.derby.impl.jdbc.EmbedConnection.<init>(Unknown Source)
+ at org.apache.derby.impl.jdbc.EmbedConnection30.<init>(Unknown Source)
+ at org.apache.derby.impl.jdbc.EmbedConnection40.<init>(Unknown Source)
+ at org.apache.derby.jdbc.Driver40.getNewEmbedConnection(Unknown Source)
+ at org.apache.derby.jdbc.InternalDriver.connect(Unknown Source)
+ at org.apache.derby.jdbc.EmbeddedDriver.connect(Unknown Source)
+ at java.sql.DriverManager.getConnection(DriverManager.java:582)
+ at java.sql.DriverManager.getConnection(DriverManager.java:207)
+ at org.sonar.test.persistence.DatabaseTestCase.stopDatabase(DatabaseTestCase.java:89)
+ at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+ at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+ at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+ at java.lang.reflect.Method.invoke(Method.java:597)
+ at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
+ at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
+ at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
+ at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:37)
+ at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
+ at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:59)
+ at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:120)
+ at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:145)
+ at org.apache.maven.surefire.Surefire.run(Surefire.java:104)
+ at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+ at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+ at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+ at java.lang.reflect.Method.invoke(Method.java:597)
+ at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:290)
+ at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1017)
+============= end nested exception, level (1) ===========
+Cleanup action completed
*/
package org.sonar.plugins.core.timemachine;
+import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.batch.*;
-import org.sonar.api.database.model.MeasureModel;
import org.sonar.api.measures.*;
-import org.sonar.api.qualitymodel.Characteristic;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
import org.sonar.api.resources.Scopes;
-import org.sonar.api.rules.RulePriority;
import org.sonar.batch.components.PastMeasuresLoader;
import org.sonar.batch.components.PastSnapshot;
import org.sonar.batch.components.TimeMachineConfiguration;
public class VariationDecorator implements Decorator {
private List<PastSnapshot> projectPastSnapshots;
- private PastMeasuresLoader pastMeasuresLoader;
private MetricFinder metricFinder;
+ private PastMeasuresLoader pastMeasuresLoader;
+
public VariationDecorator(PastMeasuresLoader pastMeasuresLoader, MetricFinder metricFinder, TimeMachineConfiguration configuration) {
this(pastMeasuresLoader, metricFinder, configuration.getProjectPastSnapshots());
-
}
-
- VariationDecorator(PastMeasuresLoader pastMeasuresLoader, MetricFinder metricFinder, List<PastSnapshot> projectPastSnapshots) {
+ public VariationDecorator(PastMeasuresLoader pastMeasuresLoader, MetricFinder metricFinder, List<PastSnapshot> projectPastSnapshots) {
this.pastMeasuresLoader = pastMeasuresLoader;
this.projectPastSnapshots = projectPastSnapshots;
this.metricFinder = metricFinder;
}
private void calculateVariation(Resource resource, DecoratorContext context, PastSnapshot pastSnapshot) {
- List<MeasureModel> pastMeasures = pastMeasuresLoader.getPastMeasures(resource, pastSnapshot);
+ List<Object[]> pastMeasures = pastMeasuresLoader.getPastMeasures(resource, pastSnapshot);
compareWithPastMeasures(context, pastSnapshot.getIndex(), pastMeasures);
}
- void compareWithPastMeasures(DecoratorContext context, int index, List<MeasureModel> pastMeasures) {
- Map<MeasureKey, MeasureModel> pastMeasuresByKey = Maps.newHashMap();
- for (MeasureModel pastMeasure : pastMeasures) {
+ void compareWithPastMeasures(DecoratorContext context, int index, List<Object[]> pastMeasures) {
+ Map<MeasureKey, Object[]> pastMeasuresByKey = Maps.newHashMap();
+ for (Object[] pastMeasure : pastMeasures) {
pastMeasuresByKey.put(new MeasureKey(pastMeasure), pastMeasure);
}
// for each measure, search equivalent past measure
- for (Measure measure : context.getMeasures(MeasuresFilters.all())) {
+ for (Measure measure : context.getMeasures(new CustomMeasureFilter())) {
// compare with past measure
- Integer metricId = (measure.getMetric().getId()!=null ? measure.getMetric().getId() : metricFinder.findByKey(measure.getMetric().getKey()).getId());
- MeasureModel pastMeasure = pastMeasuresByKey.get(new MeasureKey(measure, metricId));
+ Integer metricId = (measure.getMetric().getId() != null ? measure.getMetric().getId() : metricFinder.findByKey(measure.getMetric().getKey()).getId());
+ Integer characteristicId = (measure.getCharacteristic() != null ? measure.getCharacteristic().getId() : null);
+
+ Object[] pastMeasure = pastMeasuresByKey.get(new MeasureKey(metricId, characteristicId));
if (updateVariation(measure, pastMeasure, index)) {
context.saveMeasure(measure);
}
}
}
- boolean updateVariation(Measure measure, MeasureModel pastMeasure, int index) {
- if (pastMeasure != null && pastMeasure.getValue() != null && measure.getValue() != null) {
- double variation = (measure.getValue().doubleValue() - pastMeasure.getValue().doubleValue());
+ boolean updateVariation(Measure measure, Object[] pastMeasure, int index) {
+ if (pastMeasure != null && PastMeasuresLoader.hasValue(pastMeasure) && measure.getValue() != null) {
+ double variation = (measure.getValue().doubleValue() - PastMeasuresLoader.getValue(pastMeasure));
measure.setVariation(index, variation);
return true;
}
return getClass().getSimpleName();
}
- static class MeasureKey {
+ static class CustomMeasureFilter implements MeasuresFilter<Collection<Measure>> {
+ public Collection<Measure> filter(Collection<Measure> measures) {
+ List<Measure> result = Lists.newArrayList();
+ for (Measure measure : measures) {
+ if (!(measure instanceof RuleMeasure)) {
+ result.add(measure);
+ }
+ }
+ return result;
+ }
+ }
+
+ static final class MeasureKey {
Integer metricId;
- Integer ruleId;
- RulePriority priority;
- Characteristic characteristic;
-
- MeasureKey(MeasureModel model) {
- metricId = model.getMetricId();
- ruleId = model.getRuleId();
- priority = model.getRulePriority();
- characteristic = model.getCharacteristic();
+ Integer characteristicId;
+
+ MeasureKey(Object[] pastFields) {
+ metricId = PastMeasuresLoader.getMetricId(pastFields);
+ characteristicId = PastMeasuresLoader.getCharacteristicId(pastFields);
}
- MeasureKey(Measure measure, Integer metricId) {
+ MeasureKey(Integer metricId, Integer characteristicId) {
this.metricId = metricId;
- this.characteristic = measure.getCharacteristic();
- // TODO merge RuleMeasure into Measure
- if (measure instanceof RuleMeasure) {
- RuleMeasure rm = (RuleMeasure) measure;
- this.ruleId = (rm.getRule() == null ? null : rm.getRule().getId());
- this.priority = rm.getRulePriority();
- }
+ this.characteristicId = characteristicId;
}
@Override
if (o == null || getClass() != o.getClass()) {
return false;
}
-
MeasureKey that = (MeasureKey) o;
- if (characteristic != null ? !characteristic.equals(that.characteristic) : that.characteristic != null) {
+ if (characteristicId != null ? !characteristicId.equals(that.characteristicId) : that.characteristicId != null) {
return false;
}
if (!metricId.equals(that.metricId)) {
return false;
}
- if (priority != that.priority) {
- return false;
- }
- if (ruleId != null ? !ruleId.equals(that.ruleId) : that.ruleId != null) {
- return false;
- }
return true;
}
@Override
public int hashCode() {
int result = metricId.hashCode();
- result = 31 * result + (ruleId != null ? ruleId.hashCode() : 0);
- result = 31 * result + (priority != null ? priority.hashCode() : 0);
- result = 31 * result + (characteristic != null ? characteristic.hashCode() : 0);
+ result = 31 * result + (characteristicId != null ? characteristicId.hashCode() : 0);
return result;
}
}
public class VariationDecoratorTest extends AbstractDbUnitTestCase {
- public static final Metric NCLOC = new Metric("ncloc").setId(12);
- public static final Metric COVERAGE = new Metric("coverage").setId(16);
+ public static final int NCLOC_ID = 12;
+ public static final Metric NCLOC = new Metric("ncloc").setId(NCLOC_ID);
+
+ public static final int COVERAGE_ID = 16;
+ public static final Metric COVERAGE = new Metric("coverage").setId(COVERAGE_ID);
@Test
public void shouldNotCalculateVariationsOnFiles() {
// first past analysis
when(pastMeasuresLoader.getPastMeasures(javaPackage, pastSnapshot1)).thenReturn(Arrays.asList(
- newMeasureModel(NCLOC, 180.0),
- newMeasureModel(COVERAGE, 75.0)));
+ new Object[]{NCLOC_ID, null, 180.0},
+ new Object[]{COVERAGE_ID, null, 75.0}));
// second past analysis
- when(pastMeasuresLoader.getPastMeasures(javaPackage, pastSnapshot3)).thenReturn(Arrays.asList(
- newMeasureModel(NCLOC, 240.0)));
+ when(pastMeasuresLoader.getPastMeasures(javaPackage, pastSnapshot3)).thenReturn(Arrays.<Object[]>asList(
+ new Object[]{NCLOC_ID, null, 240.0}));
// current analysis
DecoratorContext context = mock(DecoratorContext.class);
Measure currentCoverage = newMeasure(COVERAGE, 80.0);
when(context.getMeasures(Matchers.<MeasuresFilter>anyObject())).thenReturn(Arrays.asList(currentNcloc, currentCoverage));
- VariationDecorator decorator = new VariationDecorator(pastMeasuresLoader, mock(MetricFinder.class), Arrays.asList(pastSnapshot1, pastSnapshot3));
+ VariationDecorator decorator = new VariationDecorator(pastMeasuresLoader, mock(MetricFinder.class),
+ Arrays.asList(pastSnapshot1, pastSnapshot3));
decorator.decorate(javaPackage, context);
// context updated for each variation : 2 times for ncloc and 1 time for coverage
import org.apache.commons.lang.ObjectUtils;
import org.sonar.api.BatchExtension;
import org.sonar.api.database.DatabaseSession;
-import org.sonar.api.database.model.MeasureModel;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.measures.Metric;
import org.sonar.api.measures.MetricFinder;
return metricByIds.values();
}
- public List<MeasureModel> getPastMeasures(Resource resource, PastSnapshot projectPastSnapshot) {
- return getPastMeasures(resource, projectPastSnapshot.getProjectSnapshot());
- }
-
- public List<MeasureModel> getPastMeasures(Resource resource, Snapshot projectSnapshot) {
- if (isPersisted(resource) && projectSnapshot!=null) {
- return getPastMeasures(resource.getId(), projectSnapshot);
+ public List<Object[]> getPastMeasures(Resource resource, PastSnapshot projectPastSnapshot) {
+ if (isPersisted(resource) && projectPastSnapshot != null && projectPastSnapshot.getProjectSnapshot()!=null) {
+ return getPastMeasures(resource.getId(), projectPastSnapshot.getProjectSnapshot());
}
return Collections.emptyList();
}
- public List<MeasureModel> getPastMeasures(int resourceId, Snapshot projectSnapshot) {
- // TODO improvement : select only some columns
- // TODO support measure on characteristics
- String hql = "select m from " + MeasureModel.class.getSimpleName() + " m, " + Snapshot.class.getSimpleName() + " s " +
- "where m.snapshotId=s.id and m.metricId in (:metricIds) and m.ruleId=null and m.rulePriority=null and m.characteristic=null "
- + "and (s.rootId=:rootSnapshotId or s.id=:rootSnapshotId) and s.resourceId=:resourceId and s.status=:status";
- return session.createQuery(hql)
+ public List<Object[]> getPastMeasures(int resourceId, Snapshot projectSnapshot) {
+ String sql = "select m.metric_id, m.characteristic_id, m.value from project_measures m, snapshots s" +
+ " where m.snapshot_id=s.id and m.metric_id in (:metricIds) and m.rule_id is null and m.rule_priority is null " +
+ " and (s.root_snapshot_id=:rootSnapshotId or s.id=:rootSnapshotId) and s.project_id=:resourceId and s.status=:status";
+ return session.createNativeQuery(sql)
.setParameter("metricIds", metricByIds.keySet())
.setParameter("rootSnapshotId", ObjectUtils.defaultIfNull(projectSnapshot.getRootId(), projectSnapshot.getId()))
.setParameter("resourceId", resourceId)
}
private boolean isPersisted(Resource resource) {
- return resource.getId()!=null;
+ return resource.getId() != null;
+ }
+
+ public static Integer getMetricId(Object[] row) {
+ return (Integer) row[0];
+ }
+
+ public static Integer getCharacteristicId(Object[] row) {
+ return (Integer) row[1];
+ }
+
+ public static boolean hasValue(Object[] row) {
+ return row[2] != null;
+ }
+
+ public static double getValue(Object[] row) {
+ return ((Number) row[2]).doubleValue();
}
}
import static org.hamcrest.CoreMatchers.anyOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.nullValue;
import static org.junit.internal.matchers.IsCollectionContaining.hasItems;
public class PastMeasuresLoaderTest extends AbstractDbUnitTestCase {
Snapshot projectSnapshot = getSession().getSingleResult(Snapshot.class, "id", PROJECT_SNAPSHOT_ID);
PastMeasuresLoader loader = new PastMeasuresLoader(getSession(), metrics);
- List<MeasureModel> measures = loader.getPastMeasures(FILE_ID, projectSnapshot);
+ List<Object[]> measures = loader.getPastMeasures(FILE_ID, projectSnapshot);
assertThat(measures.size(), is(2));
- for (MeasureModel measure : measures) {
- assertThat(measure.getId(), anyOf(is(5L), is(6L)));
- assertThat(measure.getValue(), anyOf(is(5.0), is(60.0)));
- }
+ Object[] pastMeasure = measures.get(0);
+ assertThat(PastMeasuresLoader.getMetricId(pastMeasure), is(1));
+ assertThat(PastMeasuresLoader.getCharacteristicId(pastMeasure), nullValue());
+ assertThat(PastMeasuresLoader.getValue(pastMeasure), is(5.0));
+
+ pastMeasure = measures.get(1);
+ assertThat(PastMeasuresLoader.getMetricId(pastMeasure), is(2));
+ assertThat(PastMeasuresLoader.getCharacteristicId(pastMeasure), nullValue());
+ assertThat(PastMeasuresLoader.getValue(pastMeasure), is(60.0));
}
@Test
Snapshot projectSnapshot = getSession().getSingleResult(Snapshot.class, "id", PROJECT_SNAPSHOT_ID);
PastMeasuresLoader loader = new PastMeasuresLoader(getSession(), metrics);
- List<MeasureModel> measures = loader.getPastMeasures(PROJECT_ID, projectSnapshot);
+ List<Object[]> measures = loader.getPastMeasures(PROJECT_ID, projectSnapshot);
assertThat(measures.size(), is(2));
- for (MeasureModel measure : measures) {
- assertThat(measure.getId(), anyOf(is(1L), is(2L)));
- assertThat(measure.getValue(), anyOf(is(60.0), is(80.0)));
- }
+ Object[] pastMeasure = measures.get(0);
+ assertThat(PastMeasuresLoader.getMetricId(pastMeasure), is(1));
+ assertThat(PastMeasuresLoader.getCharacteristicId(pastMeasure), nullValue());
+ assertThat(PastMeasuresLoader.getValue(pastMeasure), is(60.0));
+
+ pastMeasure = measures.get(1);
+ assertThat(PastMeasuresLoader.getMetricId(pastMeasure), is(2));
+ assertThat(PastMeasuresLoader.getCharacteristicId(pastMeasure), nullValue());
+ assertThat(PastMeasuresLoader.getValue(pastMeasure), is(80.0));
}
@Test