3 * Copyright (C) 2009-2017 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.ImmutableList;
23 import com.google.common.collect.ImmutableSet;
24 import com.google.common.collect.Lists;
25 import java.util.Arrays;
26 import java.util.Collections;
27 import java.util.Date;
28 import java.util.Random;
29 import java.util.stream.Collectors;
30 import java.util.stream.IntStream;
31 import org.junit.Before;
32 import org.junit.Test;
33 import org.sonar.api.rule.RuleKey;
34 import org.sonar.api.rules.RuleType;
35 import org.sonar.api.utils.DateUtils;
36 import org.sonar.api.utils.Duration;
37 import org.sonar.api.utils.Durations;
38 import org.sonar.core.issue.DefaultIssue;
39 import org.sonar.core.util.stream.MoreCollectors;
40 import org.sonar.db.DbClient;
41 import org.sonar.db.DbSession;
42 import org.sonar.db.component.ComponentDao;
43 import org.sonar.db.component.ComponentDto;
44 import org.sonar.db.rule.RuleDao;
45 import org.sonar.db.rule.RuleDefinitionDto;
46 import org.sonar.server.user.index.UserIndex;
48 import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
49 import static org.assertj.core.api.Assertions.assertThat;
50 import static org.mockito.Matchers.any;
51 import static org.mockito.Matchers.anyBoolean;
52 import static org.mockito.Matchers.anyCollection;
53 import static org.mockito.Matchers.same;
54 import static org.mockito.Mockito.mock;
55 import static org.mockito.Mockito.when;
56 import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.ASSIGNEE;
57 import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.COMPONENT;
58 import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.EFFORT;
59 import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.RULE;
60 import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.RULE_TYPE;
61 import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.TAG;
63 public class NewIssuesNotificationTest {
65 private final Random random = new Random();
66 private final RuleType randomRuleType = RuleType.values()[random.nextInt(RuleType.values().length)];
67 private NewIssuesStatistics.Stats stats = new NewIssuesStatistics.Stats(i -> true);
68 private UserIndex userIndex = mock(UserIndex.class);
69 private DbClient dbClient = mock(DbClient.class);
70 private DbSession dbSession = mock(DbSession.class);
71 private ComponentDao componentDao = mock(ComponentDao.class);
72 private RuleDao ruleDao = mock(RuleDao.class);
73 private Durations durations = mock(Durations.class);
74 private NewIssuesNotification underTest = new NewIssuesNotification(userIndex, dbClient, durations);
77 public void setUp() throws Exception {
78 when(dbClient.openSession(anyBoolean())).thenReturn(dbSession);
79 when(dbClient.componentDao()).thenReturn(componentDao);
80 when(dbClient.ruleDao()).thenReturn(ruleDao);
81 when(componentDao.selectByUuids(same(dbSession), anyCollection())).thenReturn(Collections.emptyList());
85 public void set_project_without_branch() {
86 underTest.setProject("project-key", "project-uuid", "project-long-name", null);
88 assertThat(underTest.getFieldValue(NewIssuesEmailTemplate.FIELD_PROJECT_NAME)).isEqualTo("project-long-name");
89 assertThat(underTest.getFieldValue(NewIssuesEmailTemplate.FIELD_PROJECT_UUID)).isEqualTo("project-uuid");
90 assertThat(underTest.getFieldValue(NewIssuesEmailTemplate.FIELD_PROJECT_KEY)).isEqualTo("project-key");
91 assertThat(underTest.getFieldValue(NewIssuesEmailTemplate.FIELD_BRANCH)).isNull();
95 public void set_project_with_branch() {
96 underTest.setProject("project-key", "project-uuid", "project-long-name", "feature");
98 assertThat(underTest.getFieldValue(NewIssuesEmailTemplate.FIELD_PROJECT_NAME)).isEqualTo("project-long-name");
99 assertThat(underTest.getFieldValue(NewIssuesEmailTemplate.FIELD_PROJECT_UUID)).isEqualTo("project-uuid");
100 assertThat(underTest.getFieldValue(NewIssuesEmailTemplate.FIELD_PROJECT_KEY)).isEqualTo("project-key");
101 assertThat(underTest.getFieldValue(NewIssuesEmailTemplate.FIELD_BRANCH)).isEqualTo("feature");
105 public void set_project_version() {
106 String version = randomAlphanumeric(5);
108 underTest.setProjectVersion(version);
110 assertThat(underTest.getFieldValue(NewIssuesEmailTemplate.FIELD_PROJECT_VERSION)).isEqualTo(version);
114 public void set_project_version_supports_null() {
115 underTest.setProjectVersion(null);
117 assertThat(underTest.getFieldValue(NewIssuesEmailTemplate.FIELD_PROJECT_VERSION)).isNull();
122 public void set_date() {
123 Date date = new Date();
125 underTest.setAnalysisDate(date);
127 assertThat(underTest.getFieldValue(NewIssuesEmailTemplate.FIELD_PROJECT_DATE)).isEqualTo(DateUtils.formatDateTime(date));
131 public void set_statistics() {
132 addIssueNTimes(newIssue1(), 5);
133 addIssueNTimes(newIssue2(), 3);
134 when(componentDao.selectByUuids(dbSession, ImmutableSet.of("file-uuid", "directory-uuid")))
135 .thenReturn(Arrays.asList(
136 new ComponentDto().setUuid("file-uuid").setName("file-name"),
137 new ComponentDto().setUuid("directory-uuid").setName("directory-name")));
138 RuleKey rule1 = RuleKey.of("SonarQube", "rule-the-world");
139 RuleKey rule2 = RuleKey.of("SonarQube", "rule-the-universe");
140 when(ruleDao.selectDefinitionByKeys(dbSession, ImmutableSet.of(rule1, rule2)))
142 ImmutableList.of(newRule(rule1, "Rule the World", "Java"), newRule(rule2, "Rule the Universe", "Clojure")));
144 underTest.setStatistics("project-long-name", stats);
146 assertThat(underTest.getFieldValue(RULE_TYPE + ".BUG.count")).isEqualTo("5");
147 assertThat(underTest.getFieldValue(RULE_TYPE + ".CODE_SMELL.count")).isEqualTo("3");
148 assertThat(underTest.getFieldValue(ASSIGNEE + ".1.label")).isEqualTo("maynard");
149 assertThat(underTest.getFieldValue(ASSIGNEE + ".1.count")).isEqualTo("5");
150 assertThat(underTest.getFieldValue(ASSIGNEE + ".2.label")).isEqualTo("keenan");
151 assertThat(underTest.getFieldValue(ASSIGNEE + ".2.count")).isEqualTo("3");
152 assertThat(underTest.getFieldValue(TAG + ".1.label")).isEqualTo("owasp");
153 assertThat(underTest.getFieldValue(TAG + ".1.count")).isEqualTo("8");
154 assertThat(underTest.getFieldValue(TAG + ".2.label")).isEqualTo("bug");
155 assertThat(underTest.getFieldValue(TAG + ".2.count")).isEqualTo("5");
156 assertThat(underTest.getFieldValue(COMPONENT + ".1.label")).isEqualTo("file-name");
157 assertThat(underTest.getFieldValue(COMPONENT + ".1.count")).isEqualTo("5");
158 assertThat(underTest.getFieldValue(COMPONENT + ".2.label")).isEqualTo("directory-name");
159 assertThat(underTest.getFieldValue(COMPONENT + ".2.count")).isEqualTo("3");
160 assertThat(underTest.getFieldValue(RULE + ".1.label")).isEqualTo("Rule the World (Java)");
161 assertThat(underTest.getFieldValue(RULE + ".1.count")).isEqualTo("5");
162 assertThat(underTest.getFieldValue(RULE + ".2.label")).isEqualTo("Rule the Universe (Clojure)");
163 assertThat(underTest.getFieldValue(RULE + ".2.count")).isEqualTo("3");
164 assertThat(underTest.getDefaultMessage()).startsWith("8 new issues on project-long-name");
168 public void add_only_5_assignees_with_biggest_issue_counts() {
169 String[] assignees = IntStream.range(0, 6 + random.nextInt(10)).mapToObj(s -> "assignee" + s).toArray(String[]::new);
170 NewIssuesStatistics.Stats stats = new NewIssuesStatistics.Stats(i -> true);
171 int i = assignees.length;
172 for (String assignee : assignees) {
173 IntStream.range(0, i).mapToObj(j -> new DefaultIssue().setType(randomRuleType).setAssignee(assignee)).forEach(stats::add);
177 underTest.setStatistics(randomAlphanumeric(20), stats);
179 for (int j = 0; j < 5; j++) {
180 String fieldBase = ASSIGNEE + "." + (j + 1);
181 assertThat(underTest.getFieldValue(fieldBase + ".label")).as("label of %s", fieldBase).isEqualTo(assignees[j]);
182 assertThat(underTest.getFieldValue(fieldBase + ".count")).as("count of %s", fieldBase).isEqualTo(String.valueOf(assignees.length - j));
184 assertThat(underTest.getFieldValue(ASSIGNEE + ".6.label")).isNull();
185 assertThat(underTest.getFieldValue(ASSIGNEE + ".6.count")).isNull();
189 public void add_only_5_components_with_biggest_issue_counts() {
190 String[] componentUuids = IntStream.range(0, 6 + random.nextInt(10)).mapToObj(s -> "component_uuid_" + s).toArray(String[]::new);
191 NewIssuesStatistics.Stats stats = new NewIssuesStatistics.Stats(i -> true);
192 int i = componentUuids.length;
193 for (String component : componentUuids) {
194 IntStream.range(0, i).mapToObj(j -> new DefaultIssue().setType(randomRuleType).setComponentUuid(component)).forEach(stats::add);
197 when(componentDao.selectByUuids(dbSession, Arrays.stream(componentUuids).limit(5).collect(Collectors.toSet())))
199 Arrays.stream(componentUuids).map(uuid -> new ComponentDto().setUuid(uuid).setName("name_" + uuid)).collect(MoreCollectors.toList()));
201 underTest.setStatistics(randomAlphanumeric(20), stats);
203 for (int j = 0; j < 5; j++) {
204 String fieldBase = COMPONENT + "." + (j + 1);
205 assertThat(underTest.getFieldValue(fieldBase + ".label")).as("label of %s", fieldBase).isEqualTo("name_" + componentUuids[j]);
206 assertThat(underTest.getFieldValue(fieldBase + ".count")).as("count of %s", fieldBase).isEqualTo(String.valueOf(componentUuids.length - j));
208 assertThat(underTest.getFieldValue(COMPONENT + ".6.label")).isNull();
209 assertThat(underTest.getFieldValue(COMPONENT + ".6.count")).isNull();
213 public void add_only_5_rules_with_biggest_issue_counts() {
214 String repository = randomAlphanumeric(4);
215 String[] ruleKeys = IntStream.range(0, 6 + random.nextInt(10)).mapToObj(s -> "rule_" + s).toArray(String[]::new);
216 NewIssuesStatistics.Stats stats = new NewIssuesStatistics.Stats(i -> true);
217 int i = ruleKeys.length;
218 for (String ruleKey : ruleKeys) {
219 IntStream.range(0, i).mapToObj(j -> new DefaultIssue().setType(randomRuleType).setRuleKey(RuleKey.of(repository, ruleKey))).forEach(stats::add);
222 when(ruleDao.selectDefinitionByKeys(dbSession, Arrays.stream(ruleKeys).limit(5).map(s -> RuleKey.of(repository, s)).collect(MoreCollectors.toSet(5))))
224 Arrays.stream(ruleKeys).limit(5).map(ruleKey -> new RuleDefinitionDto()
225 .setRuleKey(RuleKey.of(repository, ruleKey))
226 .setName("name_" + ruleKey)
227 .setLanguage("language_" + ruleKey))
228 .collect(MoreCollectors.toList(5)));
230 underTest.setStatistics(randomAlphanumeric(20), stats);
232 for (int j = 0; j < 5; j++) {
233 String fieldBase = RULE + "." + (j + 1);
234 assertThat(underTest.getFieldValue(fieldBase + ".label")).as("label of %s", fieldBase).isEqualTo("name_" + ruleKeys[j] + " (language_" + ruleKeys[j] + ")");
235 assertThat(underTest.getFieldValue(fieldBase + ".count")).as("count of %s", fieldBase).isEqualTo(String.valueOf(ruleKeys.length - j));
237 assertThat(underTest.getFieldValue(RULE + ".6.label")).isNull();
238 assertThat(underTest.getFieldValue(RULE + ".6.count")).isNull();
242 public void set_debt() {
243 when(durations.format(any(Duration.class))).thenReturn("55 min");
245 underTest.setDebt(Duration.create(55));
247 assertThat(underTest.getFieldValue(EFFORT + ".count")).isEqualTo("55 min");
250 private void addIssueNTimes(DefaultIssue issue, int times) {
251 for (int i = 0; i < times; i++) {
256 private DefaultIssue newIssue1() {
257 return new DefaultIssue()
258 .setAssignee("maynard")
259 .setComponentUuid("file-uuid")
260 .setType(RuleType.BUG)
261 .setTags(Lists.newArrayList("bug", "owasp"))
262 .setRuleKey(RuleKey.of("SonarQube", "rule-the-world"))
263 .setEffort(Duration.create(5L));
266 private DefaultIssue newIssue2() {
267 return new DefaultIssue()
268 .setAssignee("keenan")
269 .setComponentUuid("directory-uuid")
270 .setType(RuleType.CODE_SMELL)
271 .setTags(Lists.newArrayList("owasp"))
272 .setRuleKey(RuleKey.of("SonarQube", "rule-the-universe"))
273 .setEffort(Duration.create(10L));
276 private RuleDefinitionDto newRule(RuleKey ruleKey, String name, String language) {
277 return new RuleDefinitionDto()
280 .setLanguage(language);