Skip to content

Commit

Permalink
Revert "SONAR-6044 Stop storing distribution of issue-related measure…
Browse files Browse the repository at this point in the history
…s by rule"

This reverts commit 217d3d5.

Conflicts:
	server/sonar-server/src/main/java/org/sonar/server/db/migrations/DatabaseMigrations.java
	sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java
	sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql
  • Loading branch information
julienlancelot committed Feb 6, 2015
1 parent ef5cc2f commit 7bc3f41
Show file tree
Hide file tree
Showing 11 changed files with 166 additions and 289 deletions.
Expand Up @@ -30,16 +30,14 @@
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
import org.sonar.api.resources.ResourceUtils;
import org.sonar.api.rule.Severity;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.RulePriority;
import org.sonar.batch.components.Period;
import org.sonar.batch.components.TimeMachineConfiguration;

import javax.annotation.Nullable;

import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.*;

/**
* Computes metrics related to number of issues.
Expand Down Expand Up @@ -90,15 +88,18 @@ public void decorate(Resource resource, DecoratorContext context) {
Collection<Issue> issues = issuable.issues();
boolean shouldSaveNewMetrics = shouldSaveNewMetrics(context);

Multiset<String> severityBag = HashMultiset.create();
ListMultimap<String, Issue> issuesPerSeverity = ArrayListMultimap.create();
Multiset<RulePriority> severityBag = HashMultiset.create();
Map<RulePriority, Multiset<RuleKey>> rulesPerSeverity = Maps.newHashMap();
ListMultimap<RulePriority, Issue> issuesPerSeverity = ArrayListMultimap.create();
int countOpen = 0;
int countReopened = 0;
int countConfirmed = 0;

for (Issue issue : issues) {
severityBag.add(issue.severity());
issuesPerSeverity.put(issue.severity(), issue);
severityBag.add(RulePriority.valueOf(issue.severity()));
Multiset<RuleKey> rulesBag = initRules(rulesPerSeverity, RulePriority.valueOf(issue.severity()));
rulesBag.add(issue.ruleKey());
issuesPerSeverity.put(RulePriority.valueOf(issue.severity()), issue);

if (Issue.STATUS_OPEN.equals(issue.status())) {
countOpen++;
Expand All @@ -109,9 +110,11 @@ public void decorate(Resource resource, DecoratorContext context) {
}
}

for (String severity : Severity.ALL) {
saveIssuesForSeverity(context, severity, severityBag);
saveNewIssuesForSeverity(context, severity, issuesPerSeverity, shouldSaveNewMetrics);
for (RulePriority ruleSeverity : RulePriority.values()) {
saveIssuesForSeverity(context, ruleSeverity, severityBag);
saveIssuesPerRules(context, ruleSeverity, rulesPerSeverity);
saveNewIssuesForSeverity(context, ruleSeverity, issuesPerSeverity, shouldSaveNewMetrics);
saveNewIssuesPerRule(context, ruleSeverity, issues, shouldSaveNewMetrics);
}

saveTotalIssues(context, issues);
Expand All @@ -138,23 +141,83 @@ private void saveNewIssues(DecoratorContext context, Collection<Issue> issues, b
}
}

private void saveIssuesForSeverity(DecoratorContext context, String severity, Multiset<String> severitiesBag) {
Metric metric = SeverityUtils.severityToIssueMetric(severity);
private void saveIssuesForSeverity(DecoratorContext context, RulePriority ruleSeverity, Multiset<RulePriority> severitiesBag) {
Metric metric = SeverityUtils.severityToIssueMetric(ruleSeverity);
if (context.getMeasure(metric) == null) {
Collection<Measure> children = context.getChildrenMeasures(MeasuresFilters.metric(metric));
int sum = MeasureUtils.sum(true, children).intValue() + severitiesBag.count(severity);
int sum = MeasureUtils.sum(true, children).intValue() + severitiesBag.count(ruleSeverity);
context.saveMeasure(metric, (double) sum);
}
}

private void saveNewIssuesForSeverity(DecoratorContext context, String severity, ListMultimap<String, Issue> issuesPerSeverities, boolean shouldSaveNewMetrics) {
private void saveNewIssuesForSeverity(DecoratorContext context, RulePriority severity, ListMultimap<RulePriority, Issue> issuesPerSeverities, boolean shouldSaveNewMetrics) {
if (shouldSaveNewMetrics) {
Metric metric = SeverityUtils.severityToNewMetricIssue(severity);
Measure measure = new Measure(metric);
saveNewIssues(context, measure, issuesPerSeverities.get(severity));
}
}

private void saveIssuesPerRules(DecoratorContext context, RulePriority severity, Map<RulePriority, Multiset<RuleKey>> rulesPerSeverity) {
Metric metric = SeverityUtils.severityToIssueMetric(severity);

Collection<Measure> children = context.getChildrenMeasures(MeasuresFilters.rules(metric));
for (Measure child : children) {
RuleMeasure childRuleMeasure = (RuleMeasure) child;
RuleKey ruleKey = childRuleMeasure.ruleKey();
if (ruleKey != null && MeasureUtils.hasValue(childRuleMeasure)) {
Multiset<RuleKey> rulesBag = initRules(rulesPerSeverity, severity);
rulesBag.add(ruleKey, childRuleMeasure.getIntValue());
}
}

Multiset<RuleKey> rulesBag = rulesPerSeverity.get(severity);
if (rulesBag != null) {
for (Multiset.Entry<RuleKey> entry : rulesBag.entrySet()) {
RuleMeasure measure = RuleMeasure.createForRule(metric, entry.getElement(), (double) entry.getCount());
measure.setSeverity(severity);
context.saveMeasure(measure);
}
}
}

private void saveNewIssuesPerRule(DecoratorContext context, RulePriority severity, Collection<Issue> issues, boolean shouldSaveNewMetrics) {
if (shouldSaveNewMetrics) {
Metric metric = SeverityUtils.severityToNewMetricIssue(severity);
ListMultimap<RuleKey, Measure> childMeasuresPerRuleKeys = ArrayListMultimap.create();
ListMultimap<RuleKey, Issue> issuesPerRuleKeys = ArrayListMultimap.create();
Set<RuleKey> ruleKeys = Sets.newHashSet();

Collection<Measure> children = context.getChildrenMeasures(MeasuresFilters.rules(metric));
for (Measure child : children) {
RuleMeasure childRuleMeasure = (RuleMeasure) child;
RuleKey ruleKey = childRuleMeasure.ruleKey();
if (ruleKey != null) {
childMeasuresPerRuleKeys.put(ruleKey, childRuleMeasure);
ruleKeys.add(ruleKey);
}
}

for (Issue issue : issues) {
if (RulePriority.valueOf(issue.severity()).equals(severity)) {
ruleKeys.add(issue.ruleKey());
issuesPerRuleKeys.put(issue.ruleKey(), issue);
}
}

for (RuleKey ruleKey : ruleKeys) {
RuleMeasure measure = RuleMeasure.createForRule(metric, ruleKey, null);
measure.setSeverity(severity);
for (Period period : timeMachineConfiguration.periods()) {
int variationIndex = period.getIndex();
double sum = MeasureUtils.sumOnVariation(true, variationIndex, childMeasuresPerRuleKeys.get(ruleKey)) + countIssues(issuesPerRuleKeys.get(ruleKey), period);
measure.setVariation(variationIndex, sum);
}
context.saveMeasure(measure);
}
}
}

private void saveNewIssues(DecoratorContext context, Measure measure, Collection<Issue> issues) {
for (Period period : timeMachineConfiguration.periods()) {
int variationIndex = period.getIndex();
Expand All @@ -177,6 +240,15 @@ private int sumChildren(DecoratorContext context, Metric metric) {
return sum;
}

private Multiset<RuleKey> initRules(Map<RulePriority, Multiset<RuleKey>> rulesPerSeverity, RulePriority severity) {
Multiset<RuleKey> rulesBag = rulesPerSeverity.get(severity);
if (rulesBag == null) {
rulesBag = HashMultiset.create();
rulesPerSeverity.put(severity, rulesBag);
}
return rulesBag;
}

private int countIssues(Collection<Issue> issues, Period period) {
// SONAR-3647 Use real snapshot date and not target date in order to stay consistent with other measure variations
Date datePlusOneSecond = period.getDate() != null ? DateUtils.addSeconds(period.getDate(), 1) : null;
Expand All @@ -185,6 +257,9 @@ private int countIssues(Collection<Issue> issues, Period period) {

@VisibleForTesting
int countIssuesAfterDate(Collection<Issue> issues, @Nullable Date date) {
if (issues == null) {
return 0;
}
int count = 0;
for (Issue issue : issues) {
if (isAfter(issue, date)) {
Expand Down
Expand Up @@ -21,44 +21,46 @@

import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Metric;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.RulePriority;

final class SeverityUtils {
private SeverityUtils() {
// only static methods
}

static Metric severityToIssueMetric(String severity) {
switch (severity) {
case Severity.BLOCKER:
return CoreMetrics.BLOCKER_VIOLATIONS;
case Severity.CRITICAL:
return CoreMetrics.CRITICAL_VIOLATIONS;
case Severity.MAJOR:
return CoreMetrics.MAJOR_VIOLATIONS;
case Severity.MINOR:
return CoreMetrics.MINOR_VIOLATIONS;
case Severity.INFO:
return CoreMetrics.INFO_VIOLATIONS;
default:
throw new IllegalArgumentException("Unsupported severity: " + severity);
static Metric severityToIssueMetric(RulePriority severity) {
Metric metric;
if (severity.equals(RulePriority.BLOCKER)) {
metric = CoreMetrics.BLOCKER_VIOLATIONS;
} else if (severity.equals(RulePriority.CRITICAL)) {
metric = CoreMetrics.CRITICAL_VIOLATIONS;
} else if (severity.equals(RulePriority.MAJOR)) {
metric = CoreMetrics.MAJOR_VIOLATIONS;
} else if (severity.equals(RulePriority.MINOR)) {
metric = CoreMetrics.MINOR_VIOLATIONS;
} else if (severity.equals(RulePriority.INFO)) {
metric = CoreMetrics.INFO_VIOLATIONS;
} else {
throw new IllegalArgumentException("Unsupported severity: " + severity);
}
return metric;
}

static Metric severityToNewMetricIssue(String severity) {
switch (severity) {
case Severity.BLOCKER:
return CoreMetrics.NEW_BLOCKER_VIOLATIONS;
case Severity.CRITICAL:
return CoreMetrics.NEW_CRITICAL_VIOLATIONS;
case Severity.MAJOR:
return CoreMetrics.NEW_MAJOR_VIOLATIONS;
case Severity.MINOR:
return CoreMetrics.NEW_MINOR_VIOLATIONS;
case Severity.INFO:
return CoreMetrics.NEW_INFO_VIOLATIONS;
default:
throw new IllegalArgumentException("Unsupported severity: " + severity);
static Metric severityToNewMetricIssue(RulePriority severity) {
Metric metric;
if (severity.equals(RulePriority.BLOCKER)) {
metric = CoreMetrics.NEW_BLOCKER_VIOLATIONS;
} else if (severity.equals(RulePriority.CRITICAL)) {
metric = CoreMetrics.NEW_CRITICAL_VIOLATIONS;
} else if (severity.equals(RulePriority.MAJOR)) {
metric = CoreMetrics.NEW_MAJOR_VIOLATIONS;
} else if (severity.equals(RulePriority.MINOR)) {
metric = CoreMetrics.NEW_MINOR_VIOLATIONS;
} else if (severity.equals(RulePriority.INFO)) {
metric = CoreMetrics.NEW_INFO_VIOLATIONS;
} else {
throw new IllegalArgumentException("Unsupported severity: " + severity);
}
return metric;
}
}
Expand Up @@ -39,6 +39,7 @@
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RulePriority;
import org.sonar.api.test.IsRuleMeasure;
import org.sonar.batch.components.Period;
import org.sonar.batch.components.TimeMachineConfiguration;

Expand Down Expand Up @@ -184,11 +185,40 @@ public void should_count_issues_by_severity() {
verify(context).saveMeasure(CoreMetrics.INFO_VIOLATIONS, 0.0);
}

@Test
public void should_count_issues_per_rule() {
List<Issue> issues = newArrayList();
issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()));
issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()));
issues.add(new DefaultIssue().setRuleKey(ruleA2.ruleKey()).setSeverity(RulePriority.MAJOR.name()));
when(issuable.issues()).thenReturn(issues);

decorator.decorate(resource, context);

verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.CRITICAL_VIOLATIONS, ruleA1, 2.0)));
verify(context, never()).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.MAJOR_VIOLATIONS, ruleA1, 0.0)));
verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.MAJOR_VIOLATIONS, ruleA2, 1.0)));
}

@Test
public void same_rule_should_have_different_severities() {
List<Issue> issues = newArrayList();
issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()));
issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.CRITICAL.name()));
issues.add(new DefaultIssue().setRuleKey(ruleA1.ruleKey()).setSeverity(RulePriority.MINOR.name()));
when(issuable.issues()).thenReturn(issues);

decorator.decorate(resource, context);

verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.CRITICAL_VIOLATIONS, ruleA1, 2.0)));
verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.MINOR_VIOLATIONS, ruleA1, 1.0)));
}

@Test
public void should_count_issues_after_date() {
List<Issue> issues = createIssuesForNewMetrics();

assertThat(decorator.countIssuesAfterDate(Collections.<Issue>emptyList(), fiveDaysAgo)).isEqualTo(0);
assertThat(decorator.countIssuesAfterDate(null, fiveDaysAgo)).isEqualTo(0);
assertThat(decorator.countIssuesAfterDate(issues, fiveDaysAgo)).isEqualTo(1); // 1 rightNow
assertThat(decorator.countIssuesAfterDate(issues, tenDaysAgo)).isEqualTo(3); // 1 rightNow + 2 fiveDaysAgo
assertThat(decorator.countIssuesAfterDate(issues, sameSecond)).isEqualTo(0); // 0
Expand Down Expand Up @@ -221,6 +251,18 @@ public void should_save_severity_new_issues() {
verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_INFO_VIOLATIONS, 0.0, 0.0)));
}

@Test
public void should_save_rule_new_issues() {
when(issuable.issues()).thenReturn(createIssuesForNewMetrics());

decorator.decorate(resource, context);

// remember : period1 is 5daysAgo, period2 is 10daysAgo
verify(context).saveMeasure(argThat(new IsVariationRuleMeasure(CoreMetrics.NEW_CRITICAL_VIOLATIONS, ruleA1, 1.0, 1.0)));
verify(context).saveMeasure(argThat(new IsVariationRuleMeasure(CoreMetrics.NEW_MAJOR_VIOLATIONS, ruleA2, 0.0, 1.0)));
verify(context).saveMeasure(argThat(new IsVariationRuleMeasure(CoreMetrics.NEW_MINOR_VIOLATIONS, ruleB1, 0.0, 1.0)));
}

@Test
public void should_not_save_new_issues_if_measure_already_computed() {
when(context.getMeasure(CoreMetrics.NEW_VIOLATIONS)).thenReturn(new Measure());
Expand Down
Expand Up @@ -84,8 +84,7 @@ public interface DatabaseMigrations {
FeedIssueChangesLongDates.class,
FeedAnalysisReportsLongDates.class,
UpdateProjectsModuleUuidPath.class,
FeedSnapshotsLongDates.class,
FeedIssueComponentUuids.class,
RemoveRuleMeasuresOnIssues.class
FeedSnapshotsLongDates.class
);
}

This file was deleted.

0 comments on commit 7bc3f41

Please sign in to comment.