]> source.dussan.org Git - sonarqube.git/blob
48c45249eed23050cd5b8008d3b930f61cf85298
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2024 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.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.jupiter.api.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;
38
39 import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
40 import static org.apache.commons.lang3.RandomStringUtils.randomAlphanumeric;
41 import static org.assertj.core.api.Assertions.assertThat;
42
43 class NewIssuesStatisticsTest {
44
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);
48
49   @Test
50   void add_issues_with_correct_global_statistics() {
51     DefaultIssue issue = new DefaultIssue()
52       .setAssigneeUuid("maynard")
53       .setComponentUuid("file-uuid")
54       .setNew(true)
55       .setRuleKey(RuleKey.of("SonarQube", "rule-the-world"))
56       .setTags(Lists.newArrayList("bug", "owasp"))
57       .setEffort(Duration.create(5L));
58
59     underTest.add(issue);
60     underTest.add(issue.setAssigneeUuid("james"));
61     underTest.add(issue.setAssigneeUuid("keenan"));
62
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();
77   }
78
79   @Test
80   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);
85
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);
92   }
93
94   @Test
95   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);
100
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);
107   }
108
109   @Test
110   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);
116
117     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.COMPONENT);
118     DistributedMetricStatsInt assigneeDistribution =
119       underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.COMPONENT);
120     Stream.of(globalDistribution, assigneeDistribution)
121       .forEach(distribution -> componentUuids.forEach(componentUuid -> assertStats(distribution, componentUuid, 1, 1)));
122   }
123
124   @Test
125   void add_counts_issue_per_component_off_current_analysis_globally_and_per_assignee() {
126     List<String> componentUuids = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).toList();
127     String assignee = randomAlphanumeric(10);
128     componentUuids.stream()
129       .map(componentUuid -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setComponentUuid(componentUuid).setAssigneeUuid(assignee).setNew(false))
130       .forEach(underTest::add);
131
132     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.COMPONENT);
133     NewIssuesStatistics.Stats stats = underTest.getAssigneesStatistics().get(assignee);
134     DistributedMetricStatsInt assigneeDistribution = stats.getDistributedMetricStats(Metric.COMPONENT);
135     Stream.of(globalDistribution, assigneeDistribution)
136       .forEach(distribution -> componentUuids.forEach(componentUuid -> assertStats(distribution, componentUuid, 0, 1)));
137   }
138
139   @Test
140   void add_does_not_count_component_if_null_neither_globally_nor_per_assignee() {
141     String assignee = randomAlphanumeric(10);
142     underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setComponentUuid(null).setAssigneeUuid(assignee).setNew(new Random().nextBoolean()));
143
144     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.COMPONENT);
145     DistributedMetricStatsInt assigneeDistribution =
146       underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.COMPONENT);
147     Stream.of(globalDistribution, assigneeDistribution)
148       .forEach(distribution -> {
149         assertThat(distribution.getTotal()).isZero();
150         assertThat(distribution.getForLabel(null)).isEmpty();
151       });
152   }
153
154   @Test
155   void add_counts_issue_per_ruleKey_on_current_analysis_globally_and_per_assignee() {
156     String repository = randomAlphanumeric(3);
157     List<String> ruleKeys = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).toList();
158     String assignee = randomAlphanumeric(10);
159     ruleKeys.stream()
160       .map(ruleKey -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setRuleKey(RuleKey.of(repository, ruleKey)).setAssigneeUuid(assignee).setNew(true))
161       .forEach(underTest::add);
162
163     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE);
164     NewIssuesStatistics.Stats stats = underTest.getAssigneesStatistics().get(assignee);
165     DistributedMetricStatsInt assigneeDistribution = stats.getDistributedMetricStats(Metric.RULE);
166     Stream.of(globalDistribution, assigneeDistribution)
167       .forEach(distribution -> ruleKeys.forEach(ruleKey -> assertStats(distribution, RuleKey.of(repository, ruleKey).toString(), 1, 1)));
168   }
169
170   @Test
171   void add_counts_issue_per_ruleKey_off_current_analysis_globally_and_per_assignee() {
172     String repository = randomAlphanumeric(3);
173     List<String> ruleKeys = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).toList();
174     String assignee = randomAlphanumeric(10);
175     ruleKeys.stream()
176       .map(ruleKey -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setRuleKey(RuleKey.of(repository, ruleKey)).setAssigneeUuid(assignee).setNew(false))
177       .forEach(underTest::add);
178
179     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE);
180     DistributedMetricStatsInt assigneeDistribution =
181       underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.RULE);
182     Stream.of(globalDistribution, assigneeDistribution)
183       .forEach(distribution -> ruleKeys.forEach(ruleKey -> assertStats(distribution, RuleKey.of(repository, ruleKey).toString(), 0, 1)));
184   }
185
186   @Test
187   void add_does_not_count_ruleKey_if_null_neither_globally_nor_per_assignee() {
188     String assignee = randomAlphanumeric(10);
189     underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setRuleKey(null).setAssigneeUuid(assignee).setNew(new Random().nextBoolean()));
190
191     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE);
192     DistributedMetricStatsInt assigneeDistribution =
193       underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.RULE);
194     Stream.of(globalDistribution, assigneeDistribution)
195       .forEach(distribution -> {
196         assertThat(distribution.getTotal()).isZero();
197         assertThat(distribution.getForLabel(null)).isEmpty();
198       });
199   }
200
201   @Test
202   void add_counts_issue_per_assignee_on_current_analysis_globally_and_per_assignee() {
203     List<String> assignees = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).toList();
204     assignees.stream()
205       .map(assignee -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setAssigneeUuid(assignee).setNew(true))
206       .forEach(underTest::add);
207
208     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.ASSIGNEE);
209     assignees.forEach(assignee -> assertStats(globalDistribution, assignee, 1, 1));
210     assignees.forEach(assignee -> {
211       NewIssuesStatistics.Stats stats = underTest.getAssigneesStatistics().get(assignee);
212       DistributedMetricStatsInt assigneeStats = stats.getDistributedMetricStats(Metric.ASSIGNEE);
213       assertThat(assigneeStats.getOnCurrentAnalysis()).isOne();
214       assertThat(assigneeStats.getTotal()).isOne();
215       assignees.forEach(s -> {
216         Optional<MetricStatsInt> forLabelOpts = assigneeStats.getForLabel(s);
217         if (s.equals(assignee)) {
218           assertThat(forLabelOpts).isPresent();
219           MetricStatsInt forLabel = forLabelOpts.get();
220           assertThat(forLabel.getOnCurrentAnalysis()).isOne();
221           assertThat(forLabel.getTotal()).isOne();
222         } else {
223           assertThat(forLabelOpts).isEmpty();
224         }
225       });
226     });
227   }
228
229   @Test
230   void add_counts_issue_per_assignee_off_current_analysis_globally_and_per_assignee() {
231     List<String> assignees = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).toList();
232     assignees.stream()
233       .map(assignee -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setAssigneeUuid(assignee).setNew(false))
234       .forEach(underTest::add);
235
236     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.ASSIGNEE);
237     assignees.forEach(assignee -> assertStats(globalDistribution, assignee, 0, 1));
238     assignees.forEach(assignee -> {
239       NewIssuesStatistics.Stats stats = underTest.getAssigneesStatistics().get(assignee);
240       DistributedMetricStatsInt assigneeStats = stats.getDistributedMetricStats(Metric.ASSIGNEE);
241       assertThat(assigneeStats.getOnCurrentAnalysis()).isZero();
242       assertThat(assigneeStats.getTotal()).isOne();
243       assignees.forEach(s -> {
244         Optional<MetricStatsInt> forLabelOpts = assigneeStats.getForLabel(s);
245         if (s.equals(assignee)) {
246           assertThat(forLabelOpts).isPresent();
247           MetricStatsInt forLabel = forLabelOpts.get();
248           assertThat(forLabel.getOnCurrentAnalysis()).isZero();
249           assertThat(forLabel.getTotal()).isOne();
250         } else {
251           assertThat(forLabelOpts).isEmpty();
252         }
253       });
254     });
255   }
256
257   @Test
258   void add_does_not_assignee_if_empty_neither_globally_nor_per_assignee() {
259     underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setAssigneeUuid(null).setNew(new Random().nextBoolean()));
260
261     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.ASSIGNEE);
262     assertThat(globalDistribution.getTotal()).isZero();
263     assertThat(globalDistribution.getForLabel(null)).isEmpty();
264     assertThat(underTest.getAssigneesStatistics()).isEmpty();
265   }
266
267   @Test
268   void add_counts_issue_per_tags_on_current_analysis_globally_and_per_assignee() {
269     List<String> tags = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).toList();
270     String assignee = randomAlphanumeric(10);
271     underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setTags(tags).setAssigneeUuid(assignee).setNew(true));
272
273     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.TAG);
274     DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG);
275     Stream.of(globalDistribution, assigneeDistribution)
276       .forEach(distribution -> tags.forEach(tag -> assertStats(distribution, tag, 1, 1)));
277   }
278
279   @Test
280   void add_counts_issue_per_tags_off_current_analysis_globally_and_per_assignee() {
281     List<String> tags = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).toList();
282     String assignee = randomAlphanumeric(10);
283     underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setTags(tags).setAssigneeUuid(assignee).setNew(false));
284
285     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.TAG);
286     DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG);
287     Stream.of(globalDistribution, assigneeDistribution)
288       .forEach(distribution -> tags.forEach(tag -> assertStats(distribution, tag, 0, 1)));
289   }
290
291   @Test
292   void add_does_not_count_tags_if_empty_neither_globally_nor_per_assignee() {
293     String assignee = randomAlphanumeric(10);
294     underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setTags(Collections.emptyList()).setAssigneeUuid(assignee).setNew(new Random().nextBoolean()));
295
296     DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.TAG);
297     DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG);
298     Stream.of(globalDistribution, assigneeDistribution)
299       .forEach(distribution -> {
300         assertThat(distribution.getTotal()).isZero();
301         assertThat(distribution.getForLabel(null)).isEmpty();
302       });
303   }
304
305   @Test
306   void do_not_have_issues_when_no_issue_added() {
307     assertThat(underTest.globalStatistics().hasIssues()).isFalse();
308   }
309
310   @Test
311   void verify_toString() {
312     String componentUuid = randomAlphanumeric(2);
313     String tag = randomAlphanumeric(3);
314     String assignee = randomAlphanumeric(4);
315     int effort = 10 + new Random().nextInt(5);
316     RuleKey ruleKey = RuleKey.of(randomAlphanumeric(5), randomAlphanumeric(6));
317     underTest.add(new DefaultIssue()
318       .setType(randomRuleTypeExceptHotspot)
319       .setComponentUuid(componentUuid)
320       .setTags(ImmutableSet.of(tag))
321       .setAssigneeUuid(assignee)
322       .setRuleKey(ruleKey)
323       .setEffort(Duration.create(effort)));
324
325     assertThat(underTest)
326       .hasToString("NewIssuesStatistics{" +
327         "assigneesStatistics={" + assignee + "=" +
328         "Stats{distributions={" +
329         "TAG=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
330         "statsPerLabel={" + tag + "=MetricStatsInt{on=1, off=0}}}, " +
331         "COMPONENT=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
332         "statsPerLabel={" + componentUuid + "=MetricStatsInt{on=1, off=0}}}, " +
333         "ASSIGNEE=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
334         "statsPerLabel={" + assignee + "=MetricStatsInt{on=1, off=0}}}, " +
335         "RULE=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
336         "statsPerLabel={" + ruleKey.toString() + "=MetricStatsInt{on=1, off=0}}}}, " +
337         "issueCount=MetricStatsInt{on=1, off=0}}}, " +
338         "globalStatistics=Stats{distributions={" +
339         "TAG=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
340         "statsPerLabel={" + tag + "=MetricStatsInt{on=1, off=0}}}, " +
341         "COMPONENT=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
342         "statsPerLabel={" + componentUuid + "=MetricStatsInt{on=1, off=0}}}, " +
343         "ASSIGNEE=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
344         "statsPerLabel={" + assignee + "=MetricStatsInt{on=1, off=0}}}, " +
345         "RULE=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
346         "statsPerLabel={" + ruleKey.toString() + "=MetricStatsInt{on=1, off=0}}}}, " +
347         "issueCount=MetricStatsInt{on=1, off=0}}}");
348   }
349
350   @CheckForNull
351   private Integer countDistributionTotal(Metric metric, String label) {
352     return underTest.globalStatistics()
353       .getDistributedMetricStats(metric)
354       .getForLabel(label)
355       .map(MetricStatsInt::getTotal)
356       .orElse(null);
357   }
358
359   private void assertStats(DistributedMetricStatsInt distribution, String label, int onCurrentAnalysis, int total) {
360     Optional<MetricStatsInt> statsOption = distribution.getForLabel(label);
361     assertThat(statsOption.isPresent()).describedAs("distribution for label %s not found", label).isTrue();
362     MetricStatsInt stats = statsOption.get();
363     assertThat(stats.getOnCurrentAnalysis()).isEqualTo(onCurrentAnalysis);
364     assertThat(stats.getTotal()).isEqualTo(total);
365   }
366
367 }