3 * Copyright (C) 2009-2024 SonarSource SA
4 * mailto:info AT sonarsource DOT com
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.
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.
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.
20 package org.sonar.server.issue.notification;
22 import com.google.common.collect.ImmutableSet;
23 import com.google.common.collect.Lists;
24 import java.util.Collections;
25 import java.util.List;
26 import java.util.Optional;
27 import java.util.Random;
28 import java.util.stream.IntStream;
29 import java.util.stream.Stream;
30 import javax.annotation.CheckForNull;
31 import org.junit.Test;
32 import org.sonar.api.issue.Issue;
33 import org.sonar.api.rule.RuleKey;
34 import org.sonar.api.rules.RuleType;
35 import org.sonar.api.utils.Duration;
36 import org.sonar.core.issue.DefaultIssue;
37 import org.sonar.server.issue.notification.NewIssuesStatistics.Metric;
39 import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
40 import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
41 import static org.assertj.core.api.Assertions.assertThat;
43 public class NewIssuesStatisticsTest {
45 private final Random random = new Random();
46 private RuleType randomRuleTypeExceptHotspot = RuleType.values()[random.nextInt(RuleType.values().length - 1)];
47 private NewIssuesStatistics underTest = new NewIssuesStatistics(Issue::isNew);
50 public void add_issues_with_correct_global_statistics() {
51 DefaultIssue issue = new DefaultIssue()
52 .setAssigneeUuid("maynard")
53 .setComponentUuid("file-uuid")
55 .setRuleKey(RuleKey.of("SonarQube", "rule-the-world"))
56 .setTags(Lists.newArrayList("bug", "owasp"))
57 .setEffort(Duration.create(5L));
60 underTest.add(issue.setAssigneeUuid("james"));
61 underTest.add(issue.setAssigneeUuid("keenan"));
63 assertThat(countDistributionTotal(Metric.ASSIGNEE, "maynard")).isOne();
64 assertThat(countDistributionTotal(Metric.ASSIGNEE, "james")).isOne();
65 assertThat(countDistributionTotal(Metric.ASSIGNEE, "keenan")).isOne();
66 assertThat(countDistributionTotal(Metric.ASSIGNEE, "wrong.login")).isNull();
67 assertThat(countDistributionTotal(Metric.COMPONENT, "file-uuid")).isEqualTo(3);
68 assertThat(countDistributionTotal(Metric.COMPONENT, "wrong-uuid")).isNull();
69 assertThat(countDistributionTotal(Metric.TAG, "owasp")).isEqualTo(3);
70 assertThat(countDistributionTotal(Metric.TAG, "wrong-tag")).isNull();
71 assertThat(countDistributionTotal(Metric.RULE, "SonarQube:rule-the-world")).isEqualTo(3);
72 assertThat(countDistributionTotal(Metric.RULE, "SonarQube:has-a-fake-rule")).isNull();
73 assertThat(underTest.globalStatistics().getIssueCount().getTotal()).isEqualTo(3);
74 assertThat(underTest.globalStatistics().hasIssues()).isTrue();
75 assertThat(underTest.hasIssues()).isTrue();
76 assertThat(underTest.getAssigneesStatistics().get("maynard").hasIssues()).isTrue();
80 public void add_counts_issues_on_current_analysis_globally_and_per_assignee() {
81 String assignee = randomAlphanumeric(10);
82 IntStream.range(0, 10)
83 .mapToObj(i -> new DefaultIssue().setAssigneeUuid(assignee).setNew(true))
84 .forEach(underTest::add);
86 MetricStatsInt globalIssueCount = underTest.globalStatistics().getIssueCount();
87 MetricStatsInt assigneeIssueCount = underTest.getAssigneesStatistics().get(assignee).getIssueCount();
88 assertThat(globalIssueCount.getOnCurrentAnalysis()).isEqualTo(10);
89 assertThat(globalIssueCount.getTotal()).isEqualTo(10);
90 assertThat(assigneeIssueCount.getOnCurrentAnalysis()).isEqualTo(10);
91 assertThat(assigneeIssueCount.getTotal()).isEqualTo(10);
95 public void add_counts_issues_off_current_analysis_globally_and_per_assignee() {
96 String assignee = randomAlphanumeric(10);
97 IntStream.range(0, 10)
98 .mapToObj(i -> new DefaultIssue().setAssigneeUuid(assignee).setNew(false))
99 .forEach(underTest::add);
101 MetricStatsInt globalIssueCount = underTest.globalStatistics().getIssueCount();
102 MetricStatsInt assigneeIssueCount = underTest.getAssigneesStatistics().get(assignee).getIssueCount();
103 assertThat(globalIssueCount.getOnCurrentAnalysis()).isZero();
104 assertThat(globalIssueCount.getTotal()).isEqualTo(10);
105 assertThat(assigneeIssueCount.getOnCurrentAnalysis()).isZero();
106 assertThat(assigneeIssueCount.getTotal()).isEqualTo(10);
110 public void add_counts_issue_per_component_on_current_analysis_globally_and_per_assignee() {
111 List<String> componentUuids = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).toList();
112 String assignee = randomAlphanumeric(10);
113 componentUuids.stream()
114 .map(componentUuid -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setComponentUuid(componentUuid).setAssigneeUuid(assignee).setNew(true))
115 .forEach(underTest::add);
117 DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.COMPONENT);
118 DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.COMPONENT);
119 Stream.of(globalDistribution, assigneeDistribution)
120 .forEach(distribution -> componentUuids.forEach(componentUuid -> assertStats(distribution, componentUuid, 1, 1)));
124 public void add_counts_issue_per_component_off_current_analysis_globally_and_per_assignee() {
125 List<String> componentUuids = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).toList();
126 String assignee = randomAlphanumeric(10);
127 componentUuids.stream()
128 .map(componentUuid -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setComponentUuid(componentUuid).setAssigneeUuid(assignee).setNew(false))
129 .forEach(underTest::add);
131 DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.COMPONENT);
132 NewIssuesStatistics.Stats stats = underTest.getAssigneesStatistics().get(assignee);
133 DistributedMetricStatsInt assigneeDistribution = stats.getDistributedMetricStats(Metric.COMPONENT);
134 Stream.of(globalDistribution, assigneeDistribution)
135 .forEach(distribution -> componentUuids.forEach(componentUuid -> assertStats(distribution, componentUuid, 0, 1)));
139 public void add_does_not_count_component_if_null_neither_globally_nor_per_assignee() {
140 String assignee = randomAlphanumeric(10);
141 underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setComponentUuid(null).setAssigneeUuid(assignee).setNew(new Random().nextBoolean()));
143 DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.COMPONENT);
144 DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.COMPONENT);
145 Stream.of(globalDistribution, assigneeDistribution)
146 .forEach(distribution -> {
147 assertThat(distribution.getTotal()).isZero();
148 assertThat(distribution.getForLabel(null)).isEmpty();
153 public void add_counts_issue_per_ruleKey_on_current_analysis_globally_and_per_assignee() {
154 String repository = randomAlphanumeric(3);
155 List<String> ruleKeys = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).toList();
156 String assignee = randomAlphanumeric(10);
158 .map(ruleKey -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setRuleKey(RuleKey.of(repository, ruleKey)).setAssigneeUuid(assignee).setNew(true))
159 .forEach(underTest::add);
161 DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE);
162 NewIssuesStatistics.Stats stats = underTest.getAssigneesStatistics().get(assignee);
163 DistributedMetricStatsInt assigneeDistribution = stats.getDistributedMetricStats(Metric.RULE);
164 Stream.of(globalDistribution, assigneeDistribution)
165 .forEach(distribution -> ruleKeys.forEach(ruleKey -> assertStats(distribution, RuleKey.of(repository, ruleKey).toString(), 1, 1)));
169 public void add_counts_issue_per_ruleKey_off_current_analysis_globally_and_per_assignee() {
170 String repository = randomAlphanumeric(3);
171 List<String> ruleKeys = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).toList();
172 String assignee = randomAlphanumeric(10);
174 .map(ruleKey -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setRuleKey(RuleKey.of(repository, ruleKey)).setAssigneeUuid(assignee).setNew(false))
175 .forEach(underTest::add);
177 DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE);
178 DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.RULE);
179 Stream.of(globalDistribution, assigneeDistribution)
180 .forEach(distribution -> ruleKeys.forEach(ruleKey -> assertStats(distribution, RuleKey.of(repository, ruleKey).toString(), 0, 1)));
184 public void add_does_not_count_ruleKey_if_null_neither_globally_nor_per_assignee() {
185 String assignee = randomAlphanumeric(10);
186 underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setRuleKey(null).setAssigneeUuid(assignee).setNew(new Random().nextBoolean()));
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 -> {
192 assertThat(distribution.getTotal()).isZero();
193 assertThat(distribution.getForLabel(null)).isEmpty();
198 public void add_counts_issue_per_assignee_on_current_analysis_globally_and_per_assignee() {
199 List<String> assignees = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).toList();
201 .map(assignee -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setAssigneeUuid(assignee).setNew(true))
202 .forEach(underTest::add);
204 DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.ASSIGNEE);
205 assignees.forEach(assignee -> assertStats(globalDistribution, assignee, 1, 1));
206 assignees.forEach(assignee -> {
207 NewIssuesStatistics.Stats stats = underTest.getAssigneesStatistics().get(assignee);
208 DistributedMetricStatsInt assigneeStats = stats.getDistributedMetricStats(Metric.ASSIGNEE);
209 assertThat(assigneeStats.getOnCurrentAnalysis()).isOne();
210 assertThat(assigneeStats.getTotal()).isOne();
211 assignees.forEach(s -> {
212 Optional<MetricStatsInt> forLabelOpts = assigneeStats.getForLabel(s);
213 if (s.equals(assignee)) {
214 assertThat(forLabelOpts).isPresent();
215 MetricStatsInt forLabel = forLabelOpts.get();
216 assertThat(forLabel.getOnCurrentAnalysis()).isOne();
217 assertThat(forLabel.getTotal()).isOne();
219 assertThat(forLabelOpts).isEmpty();
226 public void add_counts_issue_per_assignee_off_current_analysis_globally_and_per_assignee() {
227 List<String> assignees = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).toList();
229 .map(assignee -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setAssigneeUuid(assignee).setNew(false))
230 .forEach(underTest::add);
232 DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.ASSIGNEE);
233 assignees.forEach(assignee -> assertStats(globalDistribution, assignee, 0, 1));
234 assignees.forEach(assignee -> {
235 NewIssuesStatistics.Stats stats = underTest.getAssigneesStatistics().get(assignee);
236 DistributedMetricStatsInt assigneeStats = stats.getDistributedMetricStats(Metric.ASSIGNEE);
237 assertThat(assigneeStats.getOnCurrentAnalysis()).isZero();
238 assertThat(assigneeStats.getTotal()).isOne();
239 assignees.forEach(s -> {
240 Optional<MetricStatsInt> forLabelOpts = assigneeStats.getForLabel(s);
241 if (s.equals(assignee)) {
242 assertThat(forLabelOpts).isPresent();
243 MetricStatsInt forLabel = forLabelOpts.get();
244 assertThat(forLabel.getOnCurrentAnalysis()).isZero();
245 assertThat(forLabel.getTotal()).isOne();
247 assertThat(forLabelOpts).isEmpty();
254 public void add_does_not_assignee_if_empty_neither_globally_nor_per_assignee() {
255 underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setAssigneeUuid(null).setNew(new Random().nextBoolean()));
257 DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.ASSIGNEE);
258 assertThat(globalDistribution.getTotal()).isZero();
259 assertThat(globalDistribution.getForLabel(null)).isEmpty();
260 assertThat(underTest.getAssigneesStatistics()).isEmpty();
264 public void add_counts_issue_per_tags_on_current_analysis_globally_and_per_assignee() {
265 List<String> tags = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).toList();
266 String assignee = randomAlphanumeric(10);
267 underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setTags(tags).setAssigneeUuid(assignee).setNew(true));
269 DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.TAG);
270 DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG);
271 Stream.of(globalDistribution, assigneeDistribution)
272 .forEach(distribution -> tags.forEach(tag -> assertStats(distribution, tag, 1, 1)));
276 public void add_counts_issue_per_tags_off_current_analysis_globally_and_per_assignee() {
277 List<String> tags = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).toList();
278 String assignee = randomAlphanumeric(10);
279 underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setTags(tags).setAssigneeUuid(assignee).setNew(false));
281 DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.TAG);
282 DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG);
283 Stream.of(globalDistribution, assigneeDistribution)
284 .forEach(distribution -> tags.forEach(tag -> assertStats(distribution, tag, 0, 1)));
288 public void add_does_not_count_tags_if_empty_neither_globally_nor_per_assignee() {
289 String assignee = randomAlphanumeric(10);
290 underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setTags(Collections.emptyList()).setAssigneeUuid(assignee).setNew(new Random().nextBoolean()));
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 -> {
296 assertThat(distribution.getTotal()).isZero();
297 assertThat(distribution.getForLabel(null)).isEmpty();
302 public void do_not_have_issues_when_no_issue_added() {
303 assertThat(underTest.globalStatistics().hasIssues()).isFalse();
307 public void verify_toString() {
308 String componentUuid = randomAlphanumeric(2);
309 String tag = randomAlphanumeric(3);
310 String assignee = randomAlphanumeric(4);
311 int effort = 10 + new Random().nextInt(5);
312 RuleKey ruleKey = RuleKey.of(randomAlphanumeric(5), randomAlphanumeric(6));
313 underTest.add(new DefaultIssue()
314 .setType(randomRuleTypeExceptHotspot)
315 .setComponentUuid(componentUuid)
316 .setTags(ImmutableSet.of(tag))
317 .setAssigneeUuid(assignee)
319 .setEffort(Duration.create(effort)));
321 assertThat(underTest)
322 .hasToString("NewIssuesStatistics{" +
323 "assigneesStatistics={" + assignee + "=" +
324 "Stats{distributions={" +
325 "TAG=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
326 "statsPerLabel={" + tag + "=MetricStatsInt{on=1, off=0}}}, " +
327 "COMPONENT=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
328 "statsPerLabel={" + componentUuid + "=MetricStatsInt{on=1, off=0}}}, " +
329 "ASSIGNEE=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
330 "statsPerLabel={" + assignee + "=MetricStatsInt{on=1, off=0}}}, " +
331 "RULE=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
332 "statsPerLabel={" + ruleKey.toString() + "=MetricStatsInt{on=1, off=0}}}}, " +
333 "issueCount=MetricStatsInt{on=1, off=0}}}, " +
334 "globalStatistics=Stats{distributions={" +
335 "TAG=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
336 "statsPerLabel={" + tag + "=MetricStatsInt{on=1, off=0}}}, " +
337 "COMPONENT=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
338 "statsPerLabel={" + componentUuid + "=MetricStatsInt{on=1, off=0}}}, " +
339 "ASSIGNEE=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
340 "statsPerLabel={" + assignee + "=MetricStatsInt{on=1, off=0}}}, " +
341 "RULE=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
342 "statsPerLabel={" + ruleKey.toString() + "=MetricStatsInt{on=1, off=0}}}}, " +
343 "issueCount=MetricStatsInt{on=1, off=0}}}");
347 private Integer countDistributionTotal(Metric metric, String label) {
348 return underTest.globalStatistics()
349 .getDistributedMetricStats(metric)
351 .map(MetricStatsInt::getTotal)
355 private void assertStats(DistributedMetricStatsInt distribution, String label, int onCurrentAnalysis, int total) {
356 Optional<MetricStatsInt> statsOption = distribution.getForLabel(label);
357 assertThat(statsOption.isPresent()).describedAs("distribution for label %s not found", label).isTrue();
358 MetricStatsInt stats = statsOption.get();
359 assertThat(stats.getOnCurrentAnalysis()).isEqualTo(onCurrentAnalysis);
360 assertThat(stats.getTotal()).isEqualTo(total);