]> source.dussan.org Git - sonarqube.git/blob
02c9388375648e9d3f176a43ee3ae04feab6690a
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2023 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 3 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 package org.sonar.server.issue.notification;
21
22 import com.google.common.collect.ImmutableSet;
23 import com.google.common.collect.Lists;
24 import java.util.Arrays;
25 import java.util.Collections;
26 import java.util.List;
27 import java.util.Optional;
28 import java.util.Random;
29 import java.util.stream.Collectors;
30 import java.util.stream.IntStream;
31 import java.util.stream.Stream;
32 import javax.annotation.CheckForNull;
33 import org.junit.Test;
34 import org.sonar.api.issue.Issue;
35 import org.sonar.api.rule.RuleKey;
36 import org.sonar.api.rules.RuleType;
37 import org.sonar.api.utils.Duration;
38 import org.sonar.core.issue.DefaultIssue;
39 import org.sonar.server.issue.notification.NewIssuesStatistics.Metric;
40
41 import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
42 import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
43 import static org.assertj.core.api.Assertions.assertThat;
44 import static org.assertj.core.api.Assertions.assertThatThrownBy;
45
46 public class NewIssuesStatisticsTest {
47
48   private final Random random = new Random();
49   private RuleType randomRuleTypeExceptHotspot = RuleType.values()[random.nextInt(RuleType.values().length - 1)];
50   private NewIssuesStatistics underTest = new NewIssuesStatistics(Issue::isNew);
51
52   @Test
53   public void add_fails_with_NPE_if_RuleType_is_null() {
54     String assignee = randomAlphanumeric(10);
55     DefaultIssue issue = new DefaultIssue().setType(null).setAssigneeUuid(assignee).setNew(new Random().nextBoolean());
56
57     assertThatThrownBy(() -> underTest.add(issue))
58       .isInstanceOf(NullPointerException.class);
59   }
60
61   @Test
62   public void add_issues_with_correct_global_statistics() {
63     DefaultIssue issue = new DefaultIssue()
64       .setAssigneeUuid("maynard")
65       .setComponentUuid("file-uuid")
66       .setNew(true)
67       .setType(RuleType.BUG)
68       .setRuleKey(RuleKey.of("SonarQube", "rule-the-world"))
69       .setTags(Lists.newArrayList("bug", "owasp"))
70       .setEffort(Duration.create(5L));
71
72     underTest.add(issue);
73     underTest.add(issue.setAssigneeUuid("james"));
74     underTest.add(issue.setAssigneeUuid("keenan"));
75
76     assertThat(countDistributionTotal(Metric.ASSIGNEE, "maynard")).isOne();
77     assertThat(countDistributionTotal(Metric.ASSIGNEE, "james")).isOne();
78     assertThat(countDistributionTotal(Metric.ASSIGNEE, "keenan")).isOne();
79     assertThat(countDistributionTotal(Metric.ASSIGNEE, "wrong.login")).isNull();
80     assertThat(countDistributionTotal(Metric.COMPONENT, "file-uuid")).isEqualTo(3);
81     assertThat(countDistributionTotal(Metric.COMPONENT, "wrong-uuid")).isNull();
82     assertThat(countDistributionTotal(Metric.RULE_TYPE, RuleType.BUG.name())).isEqualTo(3);
83     assertThat(countDistributionTotal(Metric.RULE_TYPE, RuleType.CODE_SMELL.name())).isNull();
84     assertThat(countDistributionTotal(Metric.TAG, "owasp")).isEqualTo(3);
85     assertThat(countDistributionTotal(Metric.TAG, "wrong-tag")).isNull();
86     assertThat(countDistributionTotal(Metric.RULE, "SonarQube:rule-the-world")).isEqualTo(3);
87     assertThat(countDistributionTotal(Metric.RULE, "SonarQube:has-a-fake-rule")).isNull();
88     assertThat(underTest.globalStatistics().effort().getTotal()).isEqualTo(15L);
89     assertThat(underTest.globalStatistics().hasIssues()).isTrue();
90     assertThat(underTest.hasIssues()).isTrue();
91     assertThat(underTest.getAssigneesStatistics().get("maynard").hasIssues()).isTrue();
92   }
93
94   @Test
95   public void add_counts_issue_per_RuleType_on_current_analysis_globally_and_per_assignee() {
96     String assignee = randomAlphanumeric(10);
97     Arrays.stream(RuleType.values())
98       .map(ruleType -> new DefaultIssue().setType(ruleType).setAssigneeUuid(assignee).setNew(true))
99       .forEach(underTest::add);
100
101     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE_TYPE);
102     DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.RULE_TYPE);
103     Stream.of(globalDistribution, assigneeDistribution)
104       .forEach(distribution -> Arrays.stream(RuleType.values()).forEach(ruleType -> assertStats(distribution, ruleType.name(), 1, 1)));
105   }
106
107   @Test
108   public void add_counts_issue_per_RuleType_off_current_analysis_globally_and_per_assignee() {
109     String assignee = randomAlphanumeric(10);
110     Arrays.stream(RuleType.values())
111       .map(ruleType -> new DefaultIssue().setType(ruleType).setAssigneeUuid(assignee).setNew(false))
112       .forEach(underTest::add);
113
114     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE_TYPE);
115     DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.RULE_TYPE);
116     Stream.of(globalDistribution, assigneeDistribution)
117       .forEach(distribution -> Arrays.stream(RuleType.values()).forEach(ruleType -> assertStats(distribution, ruleType.name(), 0, 1)));
118   }
119
120   @Test
121   public void add_counts_issue_per_component_on_current_analysis_globally_and_per_assignee() {
122     List<String> componentUuids = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList());
123     String assignee = randomAlphanumeric(10);
124     componentUuids.stream()
125       .map(componentUuid -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setComponentUuid(componentUuid).setAssigneeUuid(assignee).setNew(true))
126       .forEach(underTest::add);
127
128     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.COMPONENT);
129     DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.COMPONENT);
130     Stream.of(globalDistribution, assigneeDistribution)
131       .forEach(distribution -> componentUuids.forEach(componentUuid -> assertStats(distribution, componentUuid, 1, 1)));
132   }
133
134   @Test
135   public void add_counts_issue_per_component_off_current_analysis_globally_and_per_assignee() {
136     List<String> componentUuids = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList());
137     String assignee = randomAlphanumeric(10);
138     componentUuids.stream()
139       .map(componentUuid -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setComponentUuid(componentUuid).setAssigneeUuid(assignee).setNew(false))
140       .forEach(underTest::add);
141
142     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.COMPONENT);
143     NewIssuesStatistics.Stats stats = underTest.getAssigneesStatistics().get(assignee);
144     DistributedMetricStatsInt assigneeDistribution = stats.getDistributedMetricStats(Metric.COMPONENT);
145     Stream.of(globalDistribution, assigneeDistribution)
146       .forEach(distribution -> componentUuids.forEach(componentUuid -> assertStats(distribution, componentUuid, 0, 1)));
147   }
148
149   @Test
150   public void add_does_not_count_component_if_null_neither_globally_nor_per_assignee() {
151     String assignee = randomAlphanumeric(10);
152     underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setComponentUuid(null).setAssigneeUuid(assignee).setNew(new Random().nextBoolean()));
153
154     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.COMPONENT);
155     DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.COMPONENT);
156     Stream.of(globalDistribution, assigneeDistribution)
157       .forEach(distribution -> {
158         assertThat(distribution.getTotal()).isZero();
159         assertThat(distribution.getForLabel(null)).isEmpty();
160       });
161   }
162
163   @Test
164   public void add_counts_issue_per_ruleKey_on_current_analysis_globally_and_per_assignee() {
165     String repository = randomAlphanumeric(3);
166     List<String> ruleKeys = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList());
167     String assignee = randomAlphanumeric(10);
168     ruleKeys.stream()
169       .map(ruleKey -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setRuleKey(RuleKey.of(repository, ruleKey)).setAssigneeUuid(assignee).setNew(true))
170       .forEach(underTest::add);
171
172     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE);
173     NewIssuesStatistics.Stats stats = underTest.getAssigneesStatistics().get(assignee);
174     DistributedMetricStatsInt assigneeDistribution = stats.getDistributedMetricStats(Metric.RULE);
175     Stream.of(globalDistribution, assigneeDistribution)
176       .forEach(distribution -> ruleKeys.forEach(ruleKey -> assertStats(distribution, RuleKey.of(repository, ruleKey).toString(), 1, 1)));
177   }
178
179   @Test
180   public void add_counts_issue_per_ruleKey_off_current_analysis_globally_and_per_assignee() {
181     String repository = randomAlphanumeric(3);
182     List<String> ruleKeys = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList());
183     String assignee = randomAlphanumeric(10);
184     ruleKeys.stream()
185       .map(ruleKey -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setRuleKey(RuleKey.of(repository, ruleKey)).setAssigneeUuid(assignee).setNew(false))
186       .forEach(underTest::add);
187
188     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE);
189     DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.RULE);
190     Stream.of(globalDistribution, assigneeDistribution)
191       .forEach(distribution -> ruleKeys.forEach(ruleKey -> assertStats(distribution, RuleKey.of(repository, ruleKey).toString(), 0, 1)));
192   }
193
194   @Test
195   public void add_does_not_count_ruleKey_if_null_neither_globally_nor_per_assignee() {
196     String assignee = randomAlphanumeric(10);
197     underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setRuleKey(null).setAssigneeUuid(assignee).setNew(new Random().nextBoolean()));
198
199     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE);
200     DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.RULE);
201     Stream.of(globalDistribution, assigneeDistribution)
202       .forEach(distribution -> {
203         assertThat(distribution.getTotal()).isZero();
204         assertThat(distribution.getForLabel(null)).isEmpty();
205       });
206   }
207
208   @Test
209   public void add_counts_issue_per_assignee_on_current_analysis_globally_and_per_assignee() {
210     List<String> assignees = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList());
211     assignees.stream()
212       .map(assignee -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setAssigneeUuid(assignee).setNew(true))
213       .forEach(underTest::add);
214
215     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.ASSIGNEE);
216     assignees.forEach(assignee -> assertStats(globalDistribution, assignee, 1, 1));
217     assignees.forEach(assignee -> {
218       NewIssuesStatistics.Stats stats = underTest.getAssigneesStatistics().get(assignee);
219       DistributedMetricStatsInt assigneeStats = stats.getDistributedMetricStats(Metric.ASSIGNEE);
220       assertThat(assigneeStats.getOnCurrentAnalysis()).isOne();
221       assertThat(assigneeStats.getTotal()).isOne();
222       assignees.forEach(s -> {
223         Optional<MetricStatsInt> forLabelOpts = assigneeStats.getForLabel(s);
224         if (s.equals(assignee)) {
225           assertThat(forLabelOpts).isPresent();
226           MetricStatsInt forLabel = forLabelOpts.get();
227           assertThat(forLabel.getOnCurrentAnalysis()).isOne();
228           assertThat(forLabel.getTotal()).isOne();
229         } else {
230           assertThat(forLabelOpts).isEmpty();
231         }
232       });
233     });
234   }
235
236   @Test
237   public void add_counts_issue_per_assignee_off_current_analysis_globally_and_per_assignee() {
238     List<String> assignees = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList());
239     assignees.stream()
240       .map(assignee -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setAssigneeUuid(assignee).setNew(false))
241       .forEach(underTest::add);
242
243     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.ASSIGNEE);
244     assignees.forEach(assignee -> assertStats(globalDistribution, assignee, 0, 1));
245     assignees.forEach(assignee -> {
246       NewIssuesStatistics.Stats stats = underTest.getAssigneesStatistics().get(assignee);
247       DistributedMetricStatsInt assigneeStats = stats.getDistributedMetricStats(Metric.ASSIGNEE);
248       assertThat(assigneeStats.getOnCurrentAnalysis()).isZero();
249       assertThat(assigneeStats.getTotal()).isOne();
250       assignees.forEach(s -> {
251         Optional<MetricStatsInt> forLabelOpts = assigneeStats.getForLabel(s);
252         if (s.equals(assignee)) {
253           assertThat(forLabelOpts).isPresent();
254           MetricStatsInt forLabel = forLabelOpts.get();
255           assertThat(forLabel.getOnCurrentAnalysis()).isZero();
256           assertThat(forLabel.getTotal()).isOne();
257         } else {
258           assertThat(forLabelOpts).isEmpty();
259         }
260       });
261     });
262   }
263
264   @Test
265   public void add_does_not_assignee_if_empty_neither_globally_nor_per_assignee() {
266     underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setAssigneeUuid(null).setNew(new Random().nextBoolean()));
267
268     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.ASSIGNEE);
269     assertThat(globalDistribution.getTotal()).isZero();
270     assertThat(globalDistribution.getForLabel(null)).isEmpty();
271     assertThat(underTest.getAssigneesStatistics()).isEmpty();
272   }
273
274   @Test
275   public void add_counts_issue_per_tags_on_current_analysis_globally_and_per_assignee() {
276     List<String> tags = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList());
277     String assignee = randomAlphanumeric(10);
278     underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setTags(tags).setAssigneeUuid(assignee).setNew(true));
279
280     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.TAG);
281     DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG);
282     Stream.of(globalDistribution, assigneeDistribution)
283       .forEach(distribution -> tags.forEach(tag -> assertStats(distribution, tag, 1, 1)));
284   }
285
286   @Test
287   public void add_counts_issue_per_tags_off_current_analysis_globally_and_per_assignee() {
288     List<String> tags = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList());
289     String assignee = randomAlphanumeric(10);
290     underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setTags(tags).setAssigneeUuid(assignee).setNew(false));
291
292     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.TAG);
293     DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG);
294     Stream.of(globalDistribution, assigneeDistribution)
295       .forEach(distribution -> tags.forEach(tag -> assertStats(distribution, tag, 0, 1)));
296   }
297
298   @Test
299   public void add_does_not_count_tags_if_empty_neither_globally_nor_per_assignee() {
300     String assignee = randomAlphanumeric(10);
301     underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setTags(Collections.emptyList()).setAssigneeUuid(assignee).setNew(new Random().nextBoolean()));
302
303     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.TAG);
304     DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG);
305     Stream.of(globalDistribution, assigneeDistribution)
306       .forEach(distribution -> {
307         assertThat(distribution.getTotal()).isZero();
308         assertThat(distribution.getForLabel(null)).isEmpty();
309       });
310   }
311
312   @Test
313   public void add_sums_effort_on_current_analysis_globally_and_per_assignee() {
314     Random random = new Random();
315     List<Integer> efforts = IntStream.range(0, 1 + random.nextInt(10)).mapToObj(i -> 10_000 * i).collect(Collectors.toList());
316     int expected = efforts.stream().mapToInt(s -> s).sum();
317     String assignee = randomAlphanumeric(10);
318     efforts.stream()
319       .map(effort -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setEffort(Duration.create(effort)).setAssigneeUuid(assignee).setNew(true))
320       .forEach(underTest::add);
321
322     MetricStatsLong globalDistribution = underTest.globalStatistics().effort();
323     MetricStatsLong assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).effort();
324     Stream.of(globalDistribution, assigneeDistribution)
325       .forEach(distribution -> {
326         assertThat(distribution.getOnCurrentAnalysis()).isEqualTo(expected);
327         assertThat(distribution.getOffCurrentAnalysis()).isZero();
328         assertThat(distribution.getTotal()).isEqualTo(expected);
329       });
330   }
331
332   @Test
333   public void add_sums_effort_off_current_analysis_globally_and_per_assignee() {
334     Random random = new Random();
335     List<Integer> efforts = IntStream.range(0, 1 + random.nextInt(10)).mapToObj(i -> 10_000 * i).collect(Collectors.toList());
336     int expected = efforts.stream().mapToInt(s -> s).sum();
337     String assignee = randomAlphanumeric(10);
338     efforts.stream()
339       .map(effort -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setEffort(Duration.create(effort)).setAssigneeUuid(assignee).setNew(false))
340       .forEach(underTest::add);
341
342     MetricStatsLong globalDistribution = underTest.globalStatistics().effort();
343     MetricStatsLong assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).effort();
344     Stream.of(globalDistribution, assigneeDistribution)
345       .forEach(distribution -> {
346         assertThat(distribution.getOnCurrentAnalysis()).isZero();
347         assertThat(distribution.getOffCurrentAnalysis()).isEqualTo(expected);
348         assertThat(distribution.getTotal()).isEqualTo(expected);
349       });
350   }
351
352   @Test
353   public void add_does_not_sum_effort_if_null_neither_globally_nor_per_assignee() {
354     String assignee = randomAlphanumeric(10);
355     underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setEffort(null).setAssigneeUuid(assignee).setNew(new Random().nextBoolean()));
356
357     MetricStatsLong globalDistribution = underTest.globalStatistics().effort();
358     MetricStatsLong assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).effort();
359     Stream.of(globalDistribution, assigneeDistribution)
360       .forEach(distribution -> assertThat(distribution.getTotal()).isZero());
361   }
362
363   @Test
364   public void do_not_have_issues_when_no_issue_added() {
365     assertThat(underTest.globalStatistics().hasIssues()).isFalse();
366   }
367
368   @Test
369   public void verify_toString() {
370     String componentUuid = randomAlphanumeric(2);
371     String tag = randomAlphanumeric(3);
372     String assignee = randomAlphanumeric(4);
373     int effort = 10 + new Random().nextInt(5);
374     RuleKey ruleKey = RuleKey.of(randomAlphanumeric(5), randomAlphanumeric(6));
375     underTest.add(new DefaultIssue()
376       .setType(randomRuleTypeExceptHotspot)
377       .setComponentUuid(componentUuid)
378       .setTags(ImmutableSet.of(tag))
379       .setAssigneeUuid(assignee)
380       .setRuleKey(ruleKey)
381       .setEffort(Duration.create(effort)));
382
383     assertThat(underTest.toString())
384       .isEqualTo("NewIssuesStatistics{" +
385         "assigneesStatistics={" + assignee + "=" +
386         "Stats{distributions={" +
387         "RULE_TYPE=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
388         "statsPerLabel={" + randomRuleTypeExceptHotspot.name() + "=MetricStatsInt{on=1, off=0}}}, " +
389         "TAG=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
390         "statsPerLabel={" + tag + "=MetricStatsInt{on=1, off=0}}}, " +
391         "COMPONENT=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
392         "statsPerLabel={" + componentUuid + "=MetricStatsInt{on=1, off=0}}}, " +
393         "ASSIGNEE=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
394         "statsPerLabel={" + assignee + "=MetricStatsInt{on=1, off=0}}}, " +
395         "RULE=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
396         "statsPerLabel={" + ruleKey.toString() + "=MetricStatsInt{on=1, off=0}}}}, " +
397         "effortStats=MetricStatsLong{on=" + effort + ", off=0}}}, " +
398         "globalStatistics=Stats{distributions={" +
399         "RULE_TYPE=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
400         "statsPerLabel={" + randomRuleTypeExceptHotspot.name() + "=MetricStatsInt{on=1, off=0}}}, " +
401         "TAG=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
402         "statsPerLabel={" + tag + "=MetricStatsInt{on=1, off=0}}}, " +
403         "COMPONENT=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
404         "statsPerLabel={" + componentUuid + "=MetricStatsInt{on=1, off=0}}}, " +
405         "ASSIGNEE=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
406         "statsPerLabel={" + assignee + "=MetricStatsInt{on=1, off=0}}}, " +
407         "RULE=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
408         "statsPerLabel={" + ruleKey.toString() + "=MetricStatsInt{on=1, off=0}}}}, " +
409         "effortStats=MetricStatsLong{on=" + effort + ", off=0}}}");
410   }
411
412   @CheckForNull
413   private Integer countDistributionTotal(Metric metric, String label) {
414     return underTest.globalStatistics()
415       .getDistributedMetricStats(metric)
416       .getForLabel(label)
417       .map(MetricStatsInt::getTotal)
418       .orElse(null);
419   }
420
421   private void assertStats(DistributedMetricStatsInt distribution, String label, int onCurrentAnalysis, int total) {
422     Optional<MetricStatsInt> statsOption = distribution.getForLabel(label);
423     assertThat(statsOption.isPresent()).describedAs("distribution for label %s not found", label).isTrue();
424     MetricStatsInt stats = statsOption.get();
425     assertThat(stats.getOnCurrentAnalysis()).isEqualTo(onCurrentAnalysis);
426     assertThat(stats.getTotal()).isEqualTo(total);
427   }
428
429 }