From 2ce4dce9c220bdde53d7d22278f24b36490deffc Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Wed, 13 Sep 2017 17:42:20 +0200 Subject: [PATCH] SONAR-9144 add coverage on 5 elements per category + SQL optimisation --- .../DistributedMetricStatsInt.java | 7 + .../issue/notification/MetricStatsInt.java | 7 + .../issue/notification/MetricStatsLong.java | 7 + .../notification/NewIssuesNotification.java | 33 ++++- .../notification/NewIssuesStatistics.java | 20 ++- .../NewIssuesNotificationTest.java | 132 ++++++++++++++++-- .../notification/NewIssuesStatisticsTest.java | 95 +++++++------ 7 files changed, 245 insertions(+), 56 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/notification/DistributedMetricStatsInt.java b/server/sonar-server/src/main/java/org/sonar/server/issue/notification/DistributedMetricStatsInt.java index b0a331270f4..1bd13437209 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/notification/DistributedMetricStatsInt.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/notification/DistributedMetricStatsInt.java @@ -54,4 +54,11 @@ public class DistributedMetricStatsInt { return globalStats.getTotal(); } + @Override + public String toString() { + return "DistributedMetricStatsInt{" + + "globalStats=" + globalStats + + ", statsPerLabel=" + statsPerLabel + + '}'; + } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/notification/MetricStatsInt.java b/server/sonar-server/src/main/java/org/sonar/server/issue/notification/MetricStatsInt.java index f1d546c5293..4ed69a0758a 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/notification/MetricStatsInt.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/notification/MetricStatsInt.java @@ -44,4 +44,11 @@ public class MetricStatsInt { return onLeak + offLeak; } + @Override + public String toString() { + return "MetricStatsInt{" + + "onLeak=" + onLeak + + ", offLeak=" + offLeak + + '}'; + } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/notification/MetricStatsLong.java b/server/sonar-server/src/main/java/org/sonar/server/issue/notification/MetricStatsLong.java index ae43cf4ee2a..442fdbcac21 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/notification/MetricStatsLong.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/notification/MetricStatsLong.java @@ -44,4 +44,11 @@ public class MetricStatsLong { return onLeak + offLeak; } + @Override + public String toString() { + return "MetricStatsLong{" + + "onLeak=" + onLeak + + ", offLeak=" + offLeak + + '}'; + } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/notification/NewIssuesNotification.java b/server/sonar-server/src/main/java/org/sonar/server/issue/notification/NewIssuesNotification.java index 8d26d8d5187..7475b14c97f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/notification/NewIssuesNotification.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/notification/NewIssuesNotification.java @@ -19,10 +19,13 @@ */ package org.sonar.server.issue.notification; +import com.google.common.collect.ImmutableMap; import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Map; +import java.util.Optional; +import java.util.Set; import java.util.function.ToIntFunction; import javax.annotation.Nullable; import org.sonar.api.notifications.Notification; @@ -34,6 +37,8 @@ import org.sonar.api.utils.Durations; import org.sonar.core.util.stream.MoreCollectors; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.RowNotFoundException; +import org.sonar.db.component.ComponentDto; import org.sonar.db.rule.RuleDefinitionDto; import org.sonar.server.issue.notification.NewIssuesStatistics.Metric; import org.sonar.server.user.index.UserDoc; @@ -100,10 +105,20 @@ public class NewIssuesNotification extends Notification { private void setRuleStatistics(DbSession dbSession, NewIssuesStatistics.Stats stats) { Metric metric = Metric.RULE; + List> fiveBiggest = fiveBiggest(stats.getDistributedMetricStats(metric), MetricStatsInt::getOnLeak); + Set ruleKeys = fiveBiggest + .stream() + .map(Map.Entry::getKey) + .map(RuleKey::parse) + .collect(MoreCollectors.toSet(fiveBiggest.size())); + ImmutableMap ruleByRuleKey = dbClient.ruleDao().selectDefinitionByKeys(dbSession, ruleKeys) + .stream() + .collect(MoreCollectors.uniqueIndex(s -> s.getKey().toString())); int i = 1; - for (Map.Entry ruleStats : fiveBiggest(stats.getDistributedMetricStats(metric), MetricStatsInt::getOnLeak)) { + for (Map.Entry ruleStats : fiveBiggest) { String ruleKey = ruleStats.getKey(); - RuleDefinitionDto rule = dbClient.ruleDao().selectOrFailDefinitionByKey(dbSession, RuleKey.parse(ruleKey)); + RuleDefinitionDto rule = Optional.ofNullable(ruleByRuleKey.get(ruleKey)) + .orElseThrow(() -> new RowNotFoundException(String.format("Rule with key '%s' does not exist", ruleKey))); String name = rule.getName() + " (" + rule.getLanguage() + ")"; setFieldValue(metric + DOT + i + LABEL, name); setFieldValue(metric + DOT + i + COUNT, String.valueOf(ruleStats.getValue().getOnLeak())); @@ -114,9 +129,19 @@ public class NewIssuesNotification extends Notification { private void setComponentsStatistics(DbSession dbSession, NewIssuesStatistics.Stats stats) { Metric metric = Metric.COMPONENT; int i = 1; - for (Map.Entry componentStats : fiveBiggest(stats.getDistributedMetricStats(metric), MetricStatsInt::getOnLeak)) { + List> fiveBiggest = fiveBiggest(stats.getDistributedMetricStats(metric), MetricStatsInt::getOnLeak); + Set componentUuids = fiveBiggest + .stream() + .map(Map.Entry::getKey) + .collect(MoreCollectors.toSet(fiveBiggest.size())); + Map componentDtosByUuid = dbClient.componentDao().selectByUuids(dbSession, componentUuids) + .stream() + .collect(MoreCollectors.uniqueIndex(ComponentDto::uuid)); + for (Map.Entry componentStats : fiveBiggest) { String uuid = componentStats.getKey(); - String componentName = dbClient.componentDao().selectOrFailByUuid(dbSession, uuid).name(); + String componentName = Optional.ofNullable(componentDtosByUuid.get(uuid)) + .map(ComponentDto::name) + .orElseThrow(() -> new RowNotFoundException(String.format("Component with uuid '%s' not found", uuid))); setFieldValue(metric + DOT + i + LABEL, componentName); setFieldValue(metric + DOT + i + COUNT, String.valueOf(componentStats.getValue().getOnLeak())); i++; diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/notification/NewIssuesStatistics.java b/server/sonar-server/src/main/java/org/sonar/server/issue/notification/NewIssuesStatistics.java index 8101f45aeb2..3d39a6ccca9 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/notification/NewIssuesStatistics.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/notification/NewIssuesStatistics.java @@ -84,6 +84,14 @@ public class NewIssuesStatistics { } } + @Override + public String toString() { + return "NewIssuesStatistics{" + + "assigneesStatistics=" + assigneesStatistics + + ", globalStatistics=" + globalStatistics + + '}'; + } + public static class Stats { private final Predicate onLeakPredicate; private final Map distributions = new EnumMap<>(Metric.class); @@ -101,7 +109,10 @@ public class NewIssuesStatistics { public void add(Issue issue) { boolean isOnLeak = onLeakPredicate.test(issue); distributions.get(SEVERITY).increment(issue.severity(), isOnLeak); - distributions.get(COMPONENT).increment(issue.componentUuid(), isOnLeak); + String componentUuid = issue.componentUuid(); + if (componentUuid != null) { + distributions.get(COMPONENT).increment(componentUuid, isOnLeak); + } RuleKey ruleKey = issue.ruleKey(); if (ruleKey != null) { distributions.get(RULE).increment(ruleKey.toString(), isOnLeak); @@ -139,6 +150,13 @@ public class NewIssuesStatistics { return getDistributedMetricStats(SEVERITY).getOffLeak() > 0; } + @Override + public String toString() { + return "Stats{" + + "distributions=" + distributions + + ", effortStats=" + effortStats + + '}'; + } } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesNotificationTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesNotificationTest.java index f5ff4dd9a43..430c3b056ba 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesNotificationTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesNotificationTest.java @@ -19,24 +19,38 @@ */ package org.sonar.server.issue.notification; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; +import java.util.Arrays; +import java.util.Collections; import java.util.Date; +import java.util.Random; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import org.junit.Before; import org.junit.Test; -import org.mockito.Mockito; import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.Severity; import org.sonar.api.utils.DateUtils; import org.sonar.api.utils.Duration; import org.sonar.api.utils.Durations; import org.sonar.core.issue.DefaultIssue; +import org.sonar.core.util.stream.MoreCollectors; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.component.ComponentDao; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.rule.RuleDao; import org.sonar.db.rule.RuleDefinitionDto; import org.sonar.server.user.index.UserIndex; +import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyCollection; +import static org.mockito.Matchers.same; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.ASSIGNEE; @@ -48,11 +62,22 @@ import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.TAG public class NewIssuesNotificationTest { - NewIssuesStatistics.Stats stats = new NewIssuesStatistics.Stats(i -> true); - UserIndex userIndex = mock(UserIndex.class); - DbClient dbClient = mock(DbClient.class, Mockito.RETURNS_DEEP_STUBS); - Durations durations = mock(Durations.class); - NewIssuesNotification underTest = new NewIssuesNotification(userIndex, dbClient, durations); + private NewIssuesStatistics.Stats stats = new NewIssuesStatistics.Stats(i -> true); + private UserIndex userIndex = mock(UserIndex.class); + private DbClient dbClient = mock(DbClient.class); + private DbSession dbSession = mock(DbSession.class); + private ComponentDao componentDao = mock(ComponentDao.class); + private RuleDao ruleDao = mock(RuleDao.class); + private Durations durations = mock(Durations.class); + private NewIssuesNotification underTest = new NewIssuesNotification(userIndex, dbClient, durations); + + @Before + public void setUp() throws Exception { + when(dbClient.openSession(anyBoolean())).thenReturn(dbSession); + when(dbClient.componentDao()).thenReturn(componentDao); + when(dbClient.ruleDao()).thenReturn(ruleDao); + when(componentDao.selectByUuids(same(dbSession), anyCollection())).thenReturn(Collections.emptyList()); + } @Test public void set_project_without_branch() { @@ -87,10 +112,15 @@ public class NewIssuesNotificationTest { public void set_statistics() { addIssueNTimes(newIssue1(), 5); addIssueNTimes(newIssue2(), 3); - when(dbClient.componentDao().selectOrFailByUuid(any(DbSession.class), eq("file-uuid")).name()).thenReturn("file-name"); - when(dbClient.componentDao().selectOrFailByUuid(any(DbSession.class), eq("directory-uuid")).name()).thenReturn("directory-name"); - when(dbClient.ruleDao().selectOrFailDefinitionByKey(any(DbSession.class), eq(RuleKey.of("SonarQube", "rule-the-world")))).thenReturn(newRule("Rule the World", "Java")); - when(dbClient.ruleDao().selectOrFailDefinitionByKey(any(DbSession.class), eq(RuleKey.of("SonarQube", "rule-the-universe")))).thenReturn(newRule("Rule the Universe", "Clojure")); + when(componentDao.selectByUuids(dbSession, ImmutableSet.of("file-uuid", "directory-uuid"))) + .thenReturn(Arrays.asList( + new ComponentDto().setUuid("file-uuid").setName("file-name"), + new ComponentDto().setUuid("directory-uuid").setName("directory-name"))); + RuleKey rule1 = RuleKey.of("SonarQube", "rule-the-world"); + RuleKey rule2 = RuleKey.of("SonarQube", "rule-the-universe"); + when(ruleDao.selectDefinitionByKeys(dbSession, ImmutableSet.of(rule1, rule2))) + .thenReturn( + ImmutableList.of(newRule(rule1, "Rule the World", "Java"), newRule(rule2, "Rule the Universe", "Clojure"))); underTest.setStatistics("project-long-name", stats); @@ -115,6 +145,83 @@ public class NewIssuesNotificationTest { assertThat(underTest.getDefaultMessage()).startsWith("8 new issues on project-long-name"); } + @Test + public void add_only_5_assignees_with_biggest_issue_counts() { + Random random = new Random(); + String[] assignees = IntStream.range(0, 6 + random.nextInt(10)).mapToObj(s -> "assignee" + s).toArray(String[]::new); + NewIssuesStatistics.Stats stats = new NewIssuesStatistics.Stats(i -> true); + int i = assignees.length; + for (String assignee : assignees) { + IntStream.range(0, i).mapToObj(j -> new DefaultIssue().setAssignee(assignee)).forEach(stats::add); + i--; + } + + underTest.setStatistics(randomAlphanumeric(20), stats); + + for (int j = 0; j < 5; j++) { + String fieldBase = ASSIGNEE + "." + (j + 1); + assertThat(underTest.getFieldValue(fieldBase + ".label")).as("label of %s", fieldBase).isEqualTo(assignees[j]); + assertThat(underTest.getFieldValue(fieldBase + ".count")).as("count of %s", fieldBase).isEqualTo(String.valueOf(assignees.length - j)); + } + assertThat(underTest.getFieldValue(ASSIGNEE + ".6.label")).isNull(); + assertThat(underTest.getFieldValue(ASSIGNEE + ".6.count")).isNull(); + } + + @Test + public void add_only_5_components_with_biggest_issue_counts() { + Random random = new Random(); + String[] componentUuids = IntStream.range(0, 6 + random.nextInt(10)).mapToObj(s -> "component_uuid_" + s).toArray(String[]::new); + NewIssuesStatistics.Stats stats = new NewIssuesStatistics.Stats(i -> true); + int i = componentUuids.length; + for (String component : componentUuids) { + IntStream.range(0, i).mapToObj(j -> new DefaultIssue().setComponentUuid(component)).forEach(stats::add); + i--; + } + when(componentDao.selectByUuids(dbSession, Arrays.stream(componentUuids).limit(5).collect(Collectors.toSet()))) + .thenReturn( + Arrays.stream(componentUuids).map(uuid -> new ComponentDto().setUuid(uuid).setName("name_" + uuid)).collect(MoreCollectors.toList())); + + underTest.setStatistics(randomAlphanumeric(20), stats); + + for (int j = 0; j < 5; j++) { + String fieldBase = COMPONENT + "." + (j + 1); + assertThat(underTest.getFieldValue(fieldBase + ".label")).as("label of %s", fieldBase).isEqualTo("name_" + componentUuids[j]); + assertThat(underTest.getFieldValue(fieldBase + ".count")).as("count of %s", fieldBase).isEqualTo(String.valueOf(componentUuids.length - j)); + } + assertThat(underTest.getFieldValue(COMPONENT + ".6.label")).isNull(); + assertThat(underTest.getFieldValue(COMPONENT + ".6.count")).isNull(); + } + + @Test + public void add_only_5_rules_with_biggest_issue_counts() { + Random random = new Random(); + String repository = randomAlphanumeric(4); + String[] ruleKeys = IntStream.range(0, 6 + random.nextInt(10)).mapToObj(s -> "rule_" + s).toArray(String[]::new); + NewIssuesStatistics.Stats stats = new NewIssuesStatistics.Stats(i -> true); + int i = ruleKeys.length; + for (String ruleKey : ruleKeys) { + IntStream.range(0, i).mapToObj(j -> new DefaultIssue().setRuleKey(RuleKey.of(repository, ruleKey))).forEach(stats::add); + i--; + } + when(ruleDao.selectDefinitionByKeys(dbSession, Arrays.stream(ruleKeys).limit(5).map(s -> RuleKey.of(repository, s)).collect(MoreCollectors.toSet(5)))) + .thenReturn( + Arrays.stream(ruleKeys).limit(5).map(ruleKey -> new RuleDefinitionDto() + .setRuleKey(RuleKey.of(repository, ruleKey)) + .setName("name_" + ruleKey) + .setLanguage("language_" + ruleKey)) + .collect(MoreCollectors.toList(5))); + + underTest.setStatistics(randomAlphanumeric(20), stats); + + for (int j = 0; j < 5; j++) { + String fieldBase = RULE + "." + (j + 1); + assertThat(underTest.getFieldValue(fieldBase + ".label")).as("label of %s", fieldBase).isEqualTo("name_" + ruleKeys[j] + " (language_" + ruleKeys[j] + ")"); + assertThat(underTest.getFieldValue(fieldBase + ".count")).as("count of %s", fieldBase).isEqualTo(String.valueOf(ruleKeys.length - j)); + } + assertThat(underTest.getFieldValue(RULE + ".6.label")).isNull(); + assertThat(underTest.getFieldValue(RULE + ".6.count")).isNull(); + } + @Test public void set_debt() { when(durations.format(any(Duration.class))).thenReturn("55 min"); @@ -150,8 +257,9 @@ public class NewIssuesNotificationTest { .setEffort(Duration.create(10L)); } - private RuleDefinitionDto newRule(String name, String language) { + private RuleDefinitionDto newRule(RuleKey ruleKey, String name, String language) { return new RuleDefinitionDto() + .setRuleKey(ruleKey) .setName(name) .setLanguage(language); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesStatisticsTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesStatisticsTest.java index b8417cf04e2..0637551a81a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesStatisticsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesStatisticsTest.java @@ -19,6 +19,7 @@ */ package org.sonar.server.issue.notification; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import java.util.Collections; import java.util.List; @@ -159,7 +160,7 @@ public class NewIssuesStatisticsTest { } @Test - public void add_counts_component_if_null_globally_and_per_assignee_as_it_should_not_be_null() { + public void add_does_not_count_component_if_null_neither_globally_nor_per_assignee() { String assignee = randomAlphanumeric(10); underTest.add(new DefaultIssue().setComponentUuid(null).setAssignee(assignee).setNew(new Random().nextBoolean())); @@ -167,8 +168,8 @@ public class NewIssuesStatisticsTest { DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.COMPONENT); Stream.of(globalDistribution, assigneeDistribution) .forEach(distribution -> { - assertThat(distribution.getTotal()).isEqualTo(1); - assertThat(distribution.getForLabel(null).isPresent()).isTrue(); + assertThat(distribution.getTotal()).isEqualTo(0); + assertThat(distribution.getForLabel(null).isPresent()).isFalse(); }); } @@ -204,7 +205,7 @@ public class NewIssuesStatisticsTest { } @Test - public void add_does_not_count_ruleKey_if_neither_neither_globally_nor_per_assignee() { + public void add_does_not_count_ruleKey_if_null_neither_globally_nor_per_assignee() { String assignee = randomAlphanumeric(10); underTest.add(new DefaultIssue().setRuleKey(null).setAssignee(assignee).setNew(new Random().nextBoolean())); @@ -376,15 +377,6 @@ public class NewIssuesStatisticsTest { .forEach(distribution -> assertThat(distribution.getTotal()).isEqualTo(0)); } - private void assertStats(DistributedMetricStatsInt distribution, String label, int onLeak, int offLeak, int total) { - Optional statsOption = distribution.getForLabel(label); - assertThat(statsOption.isPresent()).describedAs("distribution for label %s not found", label).isTrue(); - MetricStatsInt stats = statsOption.get(); - assertThat(stats.getOnLeak()).isEqualTo(onLeak); - assertThat(stats.getOffLeak()).isEqualTo(offLeak); - assertThat(stats.getTotal()).isEqualTo(total); - } - @Test public void add_counts_issue_per_severity_per_assignee() { String assignee = randomAlphanumeric(20); @@ -408,41 +400,66 @@ public class NewIssuesStatisticsTest { assertThat(underTest.globalStatistics().hasIssues()).isFalse(); } - @CheckForNull - private Integer countDistributionTotal(Metric metric, String label) { - return underTest.globalStatistics() - .getDistributedMetricStats(metric) - .getForLabel(label) - .map(MetricStatsInt::getTotal) - .orElse(null); + @Test + public void verify_toString() { + String componentUuid = randomAlphanumeric(2); + String tag = randomAlphanumeric(3); + String assignee = randomAlphanumeric(4); + int effort = 10 + new Random().nextInt(5); + RuleKey ruleKey = RuleKey.of(randomAlphanumeric(5), randomAlphanumeric(6)); + underTest.add(new DefaultIssue() + .setSeverity(Severity.BLOCKER) + .setComponentUuid(componentUuid) + .setTags(ImmutableSet.of(tag)) + .setAssignee(assignee) + .setRuleKey(ruleKey) + .setEffort(Duration.create(effort))); + + assertThat(underTest.toString()) + .isEqualTo("NewIssuesStatistics{" + + "assigneesStatistics={" + assignee + "=" + + "Stats{distributions={" + + "SEVERITY=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " + + "statsPerLabel={" + Severity.BLOCKER + "=MetricStatsInt{onLeak=1, offLeak=0}}}, " + + "TAG=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " + + "statsPerLabel={" + tag + "=MetricStatsInt{onLeak=1, offLeak=0}}}, " + + "COMPONENT=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " + + "statsPerLabel={" + componentUuid + "=MetricStatsInt{onLeak=1, offLeak=0}}}, " + + "ASSIGNEE=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " + + "statsPerLabel={" + assignee + "=MetricStatsInt{onLeak=1, offLeak=0}}}, " + + "RULE=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " + + "statsPerLabel={" + ruleKey.toString() + "=MetricStatsInt{onLeak=1, offLeak=0}}}}, " + + "effortStats=MetricStatsLong{onLeak=" + effort + ", offLeak=0}}}, " + + "globalStatistics=Stats{distributions={" + + "SEVERITY=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " + + "statsPerLabel={" + Severity.BLOCKER + "=MetricStatsInt{onLeak=1, offLeak=0}}}, " + + "TAG=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " + + "statsPerLabel={" + tag + "=MetricStatsInt{onLeak=1, offLeak=0}}}, " + + "COMPONENT=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " + + "statsPerLabel={" + componentUuid + "=MetricStatsInt{onLeak=1, offLeak=0}}}, " + + "ASSIGNEE=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " + + "statsPerLabel={" + assignee + "=MetricStatsInt{onLeak=1, offLeak=0}}}, " + + "RULE=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " + + "statsPerLabel={" + ruleKey.toString() + "=MetricStatsInt{onLeak=1, offLeak=0}}}}, " + + "effortStats=MetricStatsLong{onLeak=" + effort + ", offLeak=0}}}"); } @CheckForNull - private Integer countDistributionOnLeak(Metric metric, String label) { + private Integer countDistributionTotal(Metric metric, String label) { return underTest.globalStatistics() .getDistributedMetricStats(metric) .getForLabel(label) - .map(MetricStatsInt::getOnLeak) + .map(MetricStatsInt::getTotal) .orElse(null); } - @CheckForNull - private Integer countDistributionOffLeak(Metric metric, String label) { - return underTest.globalStatistics() - .getDistributedMetricStats(metric) - .getForLabel(label) - .map(MetricStatsInt::getOffLeak) - .orElse(null); + private void assertStats(DistributedMetricStatsInt distribution, String label, int onLeak, int offLeak, int total) { + Optional statsOption = distribution.getForLabel(label); + assertThat(statsOption.isPresent()).describedAs("distribution for label %s not found", label).isTrue(); + MetricStatsInt stats = statsOption.get(); + assertThat(stats.getOnLeak()).isEqualTo(onLeak); + assertThat(stats.getOffLeak()).isEqualTo(offLeak); + assertThat(stats.getTotal()).isEqualTo(total); } - private DefaultIssue defaultIssue() { - return new DefaultIssue() - .setAssignee("maynard") - .setComponentUuid("file-uuid") - .setNew(true) - .setSeverity(Severity.INFO) - .setRuleKey(RuleKey.of("SonarQube", "rule-the-world")) - .setTags(Lists.newArrayList("bug", "owasp")) - .setEffort(Duration.create(5L)); - } } -- 2.39.5