import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.lang.StringUtils;
-import org.sonar.api.batch.*;
+import org.sonar.api.batch.Decorator;
+import org.sonar.api.batch.DecoratorBarriers;
+import org.sonar.api.batch.DecoratorContext;
+import org.sonar.api.batch.DependedUpon;
+import org.sonar.api.batch.DependsUpon;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.i18n.I18n;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.resources.ResourceUtils;
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.Durations;
+import org.sonar.batch.index.DefaultIndex;
import org.sonar.core.qualitygate.db.QualityGateConditionDto;
import org.sonar.core.timemachine.Periods;
-import java.util.*;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
public class QualityGateVerifier implements Decorator {
private Periods periods;
private I18n i18n;
private Durations durations;
+ private final DefaultIndex index;
- public QualityGateVerifier(QualityGate qualityGate, Snapshot snapshot, Periods periods, I18n i18n, Durations durations) {
+ public QualityGateVerifier(QualityGate qualityGate, Snapshot snapshot, Periods periods, I18n i18n, Durations durations, DefaultIndex index) {
this.qualityGate = qualityGate;
this.snapshot = snapshot;
this.periods = periods;
this.i18n = i18n;
this.durations = durations;
+ this.index = index;
}
@DependedUpon
@DependsUpon
public Collection<Metric> dependsUponMetrics() {
Set<Metric> metrics = Sets.newHashSet();
- for (ResolvedCondition condition: qualityGate.conditions()) {
+ for (ResolvedCondition condition : qualityGate.conditions()) {
metrics.add(condition.metric());
}
return metrics;
@Override
public void decorate(Resource resource, DecoratorContext context) {
if (ResourceUtils.isRootProject(resource)) {
- checkProjectConditions(context);
+ checkProjectConditions(resource, context);
}
}
- private void checkProjectConditions(DecoratorContext context) {
+ private void checkProjectConditions(Resource resource, DecoratorContext context) {
Metric.Level globalLevel = Metric.Level.OK;
List<String> labels = Lists.newArrayList();
- for (ResolvedCondition condition: qualityGate.conditions()) {
+ for (ResolvedCondition condition : qualityGate.conditions()) {
Measure measure = context.getMeasure(condition.metric());
if (measure != null) {
Metric.Level level = ConditionUtils.getLevel(condition, measure);
labels.add(text);
}
- context.saveMeasure(measure);
+ index.updateMeasure(resource, measure);
if (Metric.Level.WARN == level && globalLevel != Metric.Level.ERROR) {
globalLevel = Metric.Level.WARN;
import org.sonar.api.test.IsMeasure;
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.Durations;
+import org.sonar.batch.index.DefaultIndex;
import org.sonar.core.qualitygate.db.QualityGateConditionDto;
import org.sonar.core.timemachine.Periods;
Periods periods;
I18n i18n;
Durations durations;
+ private DefaultIndex index;
@Before
public void before() {
snapshot = mock(Snapshot.class);
qualityGate = mock(QualityGate.class);
when(qualityGate.isEnabled()).thenReturn(true);
- verifier = new QualityGateVerifier(qualityGate, snapshot, periods, i18n, durations);
+ index = mock(DefaultIndex.class);
+ verifier = new QualityGateVerifier(qualityGate, snapshot, periods, i18n, durations, index);
project = new Project("foo");
}
verifier.decorate(project, context);
verify(context).saveMeasure(argThat(new IsMeasure(CoreMetrics.ALERT_STATUS, Metric.Level.OK.toString())));
- verify(context).saveMeasure(argThat(hasLevel(measureClasses, Metric.Level.OK)));
- verify(context).saveMeasure(argThat(hasLevel(measureCoverage, Metric.Level.OK)));
+ verify(index).updateMeasure(eq(project), argThat(hasLevel(measureClasses, Metric.Level.OK)));
+ verify(index).updateMeasure(eq(project), argThat(hasLevel(measureCoverage, Metric.Level.OK)));
}
@Test
public void generate_warnings() {
ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "100"),
- mockCondition(CoreMetrics.COVERAGE, QualityGateConditionDto.OPERATOR_LESS_THAN, null, "95.0")); // generates warning because coverage 35% < 95%
+ mockCondition(CoreMetrics.COVERAGE, QualityGateConditionDto.OPERATOR_LESS_THAN, null, "95.0")); // generates warning because coverage
+ // 35% < 95%
when(qualityGate.conditions()).thenReturn(conditions);
verifier.decorate(project, context);
verify(context).saveMeasure(argThat(matchesMetric(CoreMetrics.ALERT_STATUS, Metric.Level.WARN, null)));
- verify(context).saveMeasure(argThat(hasLevel(measureClasses, Metric.Level.OK)));
- verify(context).saveMeasure(argThat(hasLevel(measureCoverage, Metric.Level.WARN)));
+ verify(index).updateMeasure(eq(project), argThat(hasLevel(measureClasses, Metric.Level.OK)));
+ verify(index).updateMeasure(eq(project), argThat(hasLevel(measureCoverage, Metric.Level.WARN)));
}
@Test
public void globalStatusShouldBeErrorIfWarningsAndErrors() {
ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
- mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_LESS_THAN, null, "100"), // generates warning because classes 20 < 100
- mockCondition(CoreMetrics.COVERAGE, QualityGateConditionDto.OPERATOR_LESS_THAN, "50.0", "80.0")); // generates error because coverage 35% < 50%
+ mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_LESS_THAN, null, "100"), // generates warning because classes 20 <
+ // 100
+ mockCondition(CoreMetrics.COVERAGE, QualityGateConditionDto.OPERATOR_LESS_THAN, "50.0", "80.0")); // generates error because coverage
+ // 35% < 50%
when(qualityGate.conditions()).thenReturn(conditions);
verifier.decorate(project, context);
verify(context).saveMeasure(argThat(matchesMetric(CoreMetrics.ALERT_STATUS, Metric.Level.ERROR, null)));
- verify(context).saveMeasure(argThat(hasLevel(measureClasses, Metric.Level.WARN)));
- verify(context).saveMeasure(argThat(hasLevel(measureCoverage, Metric.Level.ERROR)));
+ verify(index).updateMeasure(eq(project), argThat(hasLevel(measureClasses, Metric.Level.WARN)));
+ verify(index).updateMeasure(eq(project), argThat(hasLevel(measureCoverage, Metric.Level.ERROR)));
}
@Test
when(i18n.message(any(Locale.class), eq("metric.classes.name"), anyString())).thenReturn("Classes");
when(i18n.message(any(Locale.class), eq("metric.coverage.name"), anyString())).thenReturn("Coverages");
ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
- mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_LESS_THAN, null, "10000"), // there are 20 classes, error threshold is higher => alert
- mockCondition(CoreMetrics.COVERAGE, QualityGateConditionDto.OPERATOR_LESS_THAN, "50.0", "80.0"));// coverage is 35%, warning threshold is higher => alert
+ mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_LESS_THAN, null, "10000"), // there are 20 classes, error
+ // threshold is higher => alert
+ mockCondition(CoreMetrics.COVERAGE, QualityGateConditionDto.OPERATOR_LESS_THAN, "50.0", "80.0"));// coverage is 35%, warning threshold
+ // is higher => alert
when(qualityGate.conditions()).thenReturn(conditions);
verifier.decorate(project, context);
ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
// there are 20 classes, error threshold is higher => alert
mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_LESS_THAN, "10000", null)
- );
+ );
when(qualityGate.conditions()).thenReturn(conditions);
verifier.decorate(project, context);
ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "10", 1), // ok because no variation
- mockCondition(CoreMetrics.COVERAGE, QualityGateConditionDto.OPERATOR_LESS_THAN, null, "40.0", 2), // ok because coverage increases of 50%, which is more
+ mockCondition(CoreMetrics.COVERAGE, QualityGateConditionDto.OPERATOR_LESS_THAN, null, "40.0", 2), // ok because coverage increases of
+ // 50%, which is more
// than 40%
- mockCondition(CoreMetrics.COMPLEXITY, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "5", 3) // ok because complexity increases of 2, which is less
+ mockCondition(CoreMetrics.COMPLEXITY, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "5", 3) // ok because complexity increases
+ // of 2, which is less
// than 5
- );
+ );
when(qualityGate.conditions()).thenReturn(conditions);
verifier.decorate(project, context);
verify(context).saveMeasure(argThat(matchesMetric(CoreMetrics.ALERT_STATUS, Metric.Level.OK, null)));
- verify(context).saveMeasure(argThat(hasLevel(measureClasses, Metric.Level.OK)));
- verify(context).saveMeasure(argThat(hasLevel(measureCoverage, Metric.Level.OK)));
- verify(context).saveMeasure(argThat(hasLevel(measureComplexity, Metric.Level.OK)));
+ verify(index).updateMeasure(eq(project), argThat(hasLevel(measureClasses, Metric.Level.OK)));
+ verify(index).updateMeasure(eq(project), argThat(hasLevel(measureCoverage, Metric.Level.OK)));
+ verify(index).updateMeasure(eq(project), argThat(hasLevel(measureComplexity, Metric.Level.OK)));
}
@Test
measureComplexity.setVariation3(70d);
ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
- mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "30", 1), // generates warning because classes increases of 40,
+ mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "30", 1), // generates warning because classes
+ // increases of 40,
// which is greater than 30
- mockCondition(CoreMetrics.COVERAGE, QualityGateConditionDto.OPERATOR_LESS_THAN, null, "10.0", 2), // generates warning because coverage increases of 5%,
+ mockCondition(CoreMetrics.COVERAGE, QualityGateConditionDto.OPERATOR_LESS_THAN, null, "10.0", 2), // generates warning because
+ // coverage increases of 5%,
// which is smaller than 10%
- mockCondition(CoreMetrics.COMPLEXITY, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "60", 3) // generates warning because complexity increases of
+ mockCondition(CoreMetrics.COMPLEXITY, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "60", 3) // generates warning because
+ // complexity increases of
// 70, which is smaller than 60
- );
+ );
when(qualityGate.conditions()).thenReturn(conditions);
verifier.decorate(project, context);
verify(context).saveMeasure(argThat(matchesMetric(CoreMetrics.ALERT_STATUS, Metric.Level.WARN, null)));
- verify(context).saveMeasure(argThat(hasLevel(measureClasses, Metric.Level.WARN)));
- verify(context).saveMeasure(argThat(hasLevel(measureCoverage, Metric.Level.WARN)));
- verify(context).saveMeasure(argThat(hasLevel(measureComplexity, Metric.Level.WARN)));
+ verify(index).updateMeasure(eq(project), argThat(hasLevel(measureClasses, Metric.Level.WARN)));
+ verify(index).updateMeasure(eq(project), argThat(hasLevel(measureCoverage, Metric.Level.WARN)));
+ verify(index).updateMeasure(eq(project), argThat(hasLevel(measureComplexity, Metric.Level.WARN)));
}
@Test
verifier.decorate(project, context);
verify(context).saveMeasure(argThat(matchesMetric(CoreMetrics.ALERT_STATUS, Metric.Level.OK, null)));
- verify(context).saveMeasure(argThat(hasLevel(measureClasses, Metric.Level.OK)));
+ verify(index).updateMeasure(eq(project), argThat(hasLevel(measureClasses, Metric.Level.OK)));
}
@Test
ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
mockCondition(ratingMetric, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "100", 1)
- );
+ );
when(qualityGate.conditions()).thenReturn(conditions);
verifier.decorate(project, context);
verify(context).saveMeasure(argThat(matchesMetric(CoreMetrics.ALERT_STATUS, Metric.Level.OK, null)));
- verify(context).saveMeasure(argThat(hasLevel(measureRatingMetric, Metric.Level.OK)));
+ verify(index).updateMeasure(eq(project), argThat(hasLevel(measureRatingMetric, Metric.Level.OK)));
}
@Test
ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "30", 4)
- );
+ );
when(qualityGate.conditions()).thenReturn(conditions);
verifier.decorate(project, context);
verify(context).saveMeasure(argThat(matchesMetric(CoreMetrics.ALERT_STATUS, Metric.Level.WARN, null)));
- verify(context).saveMeasure(argThat(hasLevel(measureClasses, Metric.Level.WARN)));
+ verify(index).updateMeasure(eq(project), argThat(hasLevel(measureClasses, Metric.Level.WARN)));
}
@Test(expected = NotImplementedException.class)
ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
mockCondition(CoreMetrics.SCM_AUTHORS_BY_LINE, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "30", 1)
- );
+ );
when(qualityGate.conditions()).thenReturn(conditions);
verifier.decorate(project, context);
when(periods.label(snapshot, 1)).thenReturn("since someday");
ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
- mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "30", 1) // generates warning because classes increases of 40,
+ mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "30", 1) // generates warning because classes
+ // increases of 40,
// which is greater than 30
- );
+ );
when(qualityGate.conditions()).thenReturn(conditions);
verifier.decorate(project, context);
when(periods.label(snapshot, 1)).thenReturn("since someday");
ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
- mockCondition(newMetric, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "30", 1) // generates warning because classes increases of 40, which is
+ mockCondition(newMetric, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "30", 1) // generates warning because classes increases
+ // of 40, which is
// greater than 30
- );
+ );
when(qualityGate.conditions()).thenReturn(conditions);
verifier.decorate(project, context);