Browse Source

SONAR-21373 Remove type and debt from email notifications

tags/10.4.0.87286
Eric Giffon 5 months ago
parent
commit
7c69511f06

+ 6
- 18
server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/SendIssueNotificationsStepIT.java View File

@@ -62,7 +62,6 @@ import org.sonar.db.component.BranchType;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.issue.notification.DistributedMetricStatsInt;
import org.sonar.server.issue.notification.IssuesChangesNotification;
import org.sonar.server.issue.notification.MyNewIssuesNotification;
import org.sonar.server.issue.notification.NewIssuesNotification;
@@ -194,7 +193,6 @@ public class SendIssueNotificationsStepIT extends BaseStepTest {
verify(newIssuesNotificationMock).setProject(PROJECT.getKey(), PROJECT.getName(), null, null);
verify(newIssuesNotificationMock).setAnalysisDate(new Date(ANALYSE_DATE));
verify(newIssuesNotificationMock).setStatistics(eq(PROJECT.getName()), any());
verify(newIssuesNotificationMock).setDebt(ISSUE_DURATION);
verifyStatistics(context, 1, 0, 0);
}

@@ -224,13 +222,11 @@ public class SendIssueNotificationsStepIT extends BaseStepTest {
verify(notificationService).deliver(newIssuesNotificationMock);
ArgumentCaptor<NewIssuesStatistics.Stats> statsCaptor = forClass(NewIssuesStatistics.Stats.class);
verify(newIssuesNotificationMock).setStatistics(eq(PROJECT.getName()), statsCaptor.capture());
verify(newIssuesNotificationMock).setDebt(expectedEffort);
NewIssuesStatistics.Stats stats = statsCaptor.getValue();
assertThat(stats.hasIssues()).isTrue();
// just checking all issues have been added to the stats
DistributedMetricStatsInt severity = stats.getDistributedMetricStats(NewIssuesStatistics.Metric.RULE_TYPE);
assertThat(severity.getOnCurrentAnalysis()).isEqualTo(efforts.length);
assertThat(severity.getTotal()).isEqualTo(backDatedEfforts.length + efforts.length);
assertThat(stats.getIssueCount().getOnCurrentAnalysis()).isEqualTo(efforts.length);
assertThat(stats.getIssueCount().getTotal()).isEqualTo(backDatedEfforts.length + efforts.length);
verifyStatistics(context, 1, 0, 0);
}

@@ -268,7 +264,6 @@ public class SendIssueNotificationsStepIT extends BaseStepTest {
verify(newIssuesNotificationMock).setProject(branch.getKey(), branch.longName(), BRANCH_NAME, null);
verify(newIssuesNotificationMock).setAnalysisDate(new Date(ANALYSE_DATE));
verify(newIssuesNotificationMock).setStatistics(eq(branch.longName()), any(NewIssuesStatistics.Stats.class));
verify(newIssuesNotificationMock).setDebt(ISSUE_DURATION);
verifyStatistics(context, 1, 0, 0);
}

@@ -333,7 +328,6 @@ public class SendIssueNotificationsStepIT extends BaseStepTest {
verify(myNewIssuesNotificationMock).setProject(PROJECT.getKey(), PROJECT.getName(), null, null);
verify(myNewIssuesNotificationMock).setAnalysisDate(new Date(ANALYSE_DATE));
verify(myNewIssuesNotificationMock).setStatistics(eq(PROJECT.getName()), any(NewIssuesStatistics.Stats.class));
verify(myNewIssuesNotificationMock).setDebt(ISSUE_DURATION);
verifyStatistics(context, 1, 1, 0);
}

@@ -400,14 +394,12 @@ public class SendIssueNotificationsStepIT extends BaseStepTest {
MyNewIssuesNotification myNewIssuesNotificationMock = myNewIssuesNotificationMocksByUsersName.get("perceval");
ArgumentCaptor<NewIssuesStatistics.Stats> statsCaptor = forClass(NewIssuesStatistics.Stats.class);
verify(myNewIssuesNotificationMock).setStatistics(eq(PROJECT.getName()), statsCaptor.capture());
verify(myNewIssuesNotificationMock).setDebt(expectedEffort);

NewIssuesStatistics.Stats stats = statsCaptor.getValue();
assertThat(stats.hasIssues()).isTrue();
// just checking all issues have been added to the stats
DistributedMetricStatsInt severity = stats.getDistributedMetricStats(NewIssuesStatistics.Metric.RULE_TYPE);
assertThat(severity.getOnCurrentAnalysis()).isEqualTo(assigned.length);
assertThat(severity.getTotal()).isEqualTo(assigned.length);
assertThat(stats.getIssueCount().getOnCurrentAnalysis()).isEqualTo(assigned.length);
assertThat(stats.getIssueCount().getTotal()).isEqualTo(assigned.length);

verifyStatistics(context, 1, 2, 0);
}
@@ -451,13 +443,11 @@ public class SendIssueNotificationsStepIT extends BaseStepTest {
verify(myNewIssuesNotificationMock).setAssignee(any(UserDto.class));
ArgumentCaptor<NewIssuesStatistics.Stats> statsCaptor = forClass(NewIssuesStatistics.Stats.class);
verify(myNewIssuesNotificationMock).setStatistics(eq(PROJECT.getName()), statsCaptor.capture());
verify(myNewIssuesNotificationMock).setDebt(expectedEffort);
NewIssuesStatistics.Stats stats = statsCaptor.getValue();
assertThat(stats.hasIssues()).isTrue();
// just checking all issues have been added to the stats
DistributedMetricStatsInt severity = stats.getDistributedMetricStats(NewIssuesStatistics.Metric.RULE_TYPE);
assertThat(severity.getOnCurrentAnalysis()).isEqualTo(efforts.length);
assertThat(severity.getTotal()).isEqualTo(backDatedEfforts.length + efforts.length);
assertThat(stats.getIssueCount().getOnCurrentAnalysis()).isEqualTo(efforts.length);
assertThat(stats.getIssueCount().getTotal()).isEqualTo(backDatedEfforts.length + efforts.length);

verifyStatistics(context, 1, 1, 0);
}
@@ -668,7 +658,6 @@ public class SendIssueNotificationsStepIT extends BaseStepTest {
when(notification.setProjectVersion(any())).thenReturn(notification);
when(notification.setAnalysisDate(any())).thenReturn(notification);
when(notification.setStatistics(any(), any())).thenReturn(notification);
when(notification.setDebt(any())).thenReturn(notification);
return notification;
}

@@ -679,7 +668,6 @@ public class SendIssueNotificationsStepIT extends BaseStepTest {
when(notification.setProjectVersion(any())).thenReturn(notification);
when(notification.setAnalysisDate(any())).thenReturn(notification);
when(notification.setStatistics(any(), any())).thenReturn(notification);
when(notification.setDebt(any())).thenReturn(notification);
return notification;
}


+ 2
- 5
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/SendIssueNotificationsStep.java View File

@@ -34,7 +34,6 @@ import javax.annotation.CheckForNull;
import org.sonar.api.issue.Issue;
import org.sonar.api.notifications.Notification;
import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.Duration;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
import org.sonar.ce.task.projectanalysis.analysis.Branch;
import org.sonar.ce.task.projectanalysis.component.Component;
@@ -176,8 +175,7 @@ public class SendIssueNotificationsStep implements ComputationStep {
.setProject(project.getKey(), project.getName(), getBranchName(), getPullRequest())
.setProjectVersion(project.getProjectAttributes().getProjectVersion())
.setAnalysisDate(new Date(analysisDate))
.setStatistics(project.getName(), globalStatistics)
.setDebt(Duration.create(globalStatistics.effort().getOnCurrentAnalysis()));
.setStatistics(project.getName(), globalStatistics);
notificationStatistics.newIssuesDeliveries += service.deliverEmails(singleton(notification));
notificationStatistics.newIssues++;

@@ -201,8 +199,7 @@ public class SendIssueNotificationsStep implements ComputationStep {
.setProject(project.getKey(), project.getName(), getBranchName(), getPullRequest())
.setProjectVersion(project.getProjectAttributes().getProjectVersion())
.setAnalysisDate(new Date(analysisDate))
.setStatistics(project.getName(), assigneeStatistics)
.setDebt(Duration.create(assigneeStatistics.effort().getOnCurrentAnalysis()));
.setStatistics(project.getName(), assigneeStatistics);

return myNewIssuesNotification;
})

+ 4
- 16
server/sonar-server-common/src/it/java/org/sonar/server/issue/notification/NewIssuesNotificationIT.java View File

@@ -25,7 +25,6 @@ import java.util.stream.IntStream;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.Durations;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
@@ -48,9 +47,8 @@ import static org.sonar.db.component.ComponentTesting.newDirectory;
import static org.sonar.db.component.ComponentTesting.newFileDto;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.ASSIGNEE;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.COMPONENT;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.EFFORT;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.ISSUE;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.RULE;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.RULE_TYPE;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.TAG;

public class NewIssuesNotificationIT {
@@ -158,8 +156,7 @@ public class NewIssuesNotificationIT {

underTest.setStatistics(project.longName(), stats);

assertThat(underTest.getFieldValue(RULE_TYPE + ".BUG.count")).isEqualTo("5");
assertThat(underTest.getFieldValue(RULE_TYPE + ".CODE_SMELL.count")).isEqualTo("3");
assertThat(underTest.getFieldValue(ISSUE + ".count")).isEqualTo("8");
assertThat(underTest.getFieldValue(ASSIGNEE + ".1.label")).isEqualTo(maynard.getName());
assertThat(underTest.getFieldValue(ASSIGNEE + ".1.count")).isEqualTo("5");
assertThat(underTest.getFieldValue(ASSIGNEE + ".2.label")).isEqualTo(keenan.getName());
@@ -200,8 +197,7 @@ public class NewIssuesNotificationIT {

underTest.setStatistics(project.longName(), stats);

assertThat(underTest.getFieldValue(RULE_TYPE + ".BUG.count")).isEqualTo("0");
assertThat(underTest.getFieldValue(RULE_TYPE + ".CODE_SMELL.count")).isEqualTo("0");
assertThat(underTest.getFieldValue(ISSUE + ".count")).isEqualTo("0");
assertThat(underTest.getFieldValue(ASSIGNEE + ".1.label")).isNull();
assertThat(underTest.getFieldValue(ASSIGNEE + ".1.count")).isNull();
assertThat(underTest.getFieldValue(ASSIGNEE + ".2.label")).isNull();
@@ -243,8 +239,7 @@ public class NewIssuesNotificationIT {

underTest.setStatistics(project.longName(), stats);

assertThat(underTest.getFieldValue(RULE_TYPE + ".BUG.count")).isEqualTo("0");
assertThat(underTest.getFieldValue(RULE_TYPE + ".CODE_SMELL.count")).isEqualTo("3");
assertThat(underTest.getFieldValue(ISSUE + ".count")).isEqualTo("3");
assertThat(underTest.getFieldValue(ASSIGNEE + ".1.label")).isEqualTo(keenan.getName());
assertThat(underTest.getFieldValue(ASSIGNEE + ".1.count")).isEqualTo("3");
assertThat(underTest.getFieldValue(ASSIGNEE + ".2.label")).isNull();
@@ -425,13 +420,6 @@ public class NewIssuesNotificationIT {
assertThat(underTest.getFieldValue(RULE + ".6.count")).isNull();
}

@Test
public void set_debt() {
underTest.setDebt(Duration.create(55));

assertThat(underTest.getFieldValue(EFFORT + ".count")).isEqualTo("55min");
}

@Test
public void RuleDefinition_implements_equals_base_on_name_and_language() {
String name = randomAlphabetic(5);

+ 8
- 35
server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/AbstractNewIssuesEmailTemplate.java View File

@@ -21,17 +21,13 @@ package org.sonar.server.issue.notification;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.Locale;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.api.config.EmailSettings;
import org.sonar.api.notifications.Notification;
import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.DateUtils;
import org.sonar.core.i18n.I18n;
import org.sonar.server.issue.notification.NewIssuesStatistics.Metric;

import static com.google.common.base.Preconditions.checkNotNull;
@@ -57,11 +53,9 @@ public abstract class AbstractNewIssuesEmailTemplate implements EmailTemplate {
static final String FIELD_PULL_REQUEST = "pullRequest";

protected final EmailSettings settings;
protected final I18n i18n;

public AbstractNewIssuesEmailTemplate(EmailSettings settings, I18n i18n) {
protected AbstractNewIssuesEmailTemplate(EmailSettings settings) {
this.settings = settings;
this.i18n = i18n;
}

public static String encode(String toEncode) {
@@ -95,7 +89,7 @@ public abstract class AbstractNewIssuesEmailTemplate implements EmailTemplate {
message.append("Version: ").append(version).append(NEW_LINE);
}
message.append(NEW_LINE);
appendRuleType(message, notification);
appendIssueCount(message, notification);
appendAssignees(message, notification);
appendRules(message, notification);
appendTags(message, notification);
@@ -118,12 +112,11 @@ public abstract class AbstractNewIssuesEmailTemplate implements EmailTemplate {
protected abstract boolean shouldNotFormat(Notification notification);

protected String subject(Notification notification, String fullProjectName) {
int issueCount = Integer.parseInt(notification.getFieldValue(Metric.RULE_TYPE + COUNT));
return String.format("%s: %s new issue%s (new debt: %s)",
String issueCount = notification.getFieldValue(Metric.ISSUE + COUNT);
return String.format("%s: %s new issue%s",
fullProjectName,
issueCount,
issueCount > 1 ? "s" : "",
notification.getFieldValue(Metric.EFFORT + COUNT));
"1".equals(issueCount) ? "" : "s");
}

private static boolean doNotHaveValue(Notification notification, Metric metric) {
@@ -170,30 +163,10 @@ public abstract class AbstractNewIssuesEmailTemplate implements EmailTemplate {
genericAppendOfMetric(Metric.RULE, "Rules", message, notification);
}

protected void appendRuleType(StringBuilder message, Notification notification) {
String count = notification.getFieldValue(Metric.RULE_TYPE + COUNT);
message
.append(String.format("%s new issue%s (new debt: %s)",
count,
Integer.valueOf(count) > 1 ? "s" : "",
notification.getFieldValue(Metric.EFFORT + COUNT)))
.append(NEW_LINE).append(NEW_LINE)
.append(TAB)
.append("Type")
.append(NEW_LINE)
.append(TAB)
.append(TAB);

for (Iterator<RuleType> ruleTypeIterator = Arrays.asList(RuleType.BUG, RuleType.VULNERABILITY, RuleType.CODE_SMELL).iterator(); ruleTypeIterator.hasNext();) {
RuleType ruleType = ruleTypeIterator.next();
String ruleTypeLabel = i18n.message(getLocale(), "issue.type." + ruleType, ruleType.name());
message.append(ruleTypeLabel).append(": ").append(notification.getFieldValue(Metric.RULE_TYPE + DOT + ruleType + COUNT));
if (ruleTypeIterator.hasNext()) {
message.append(TAB);
}
}

protected void appendIssueCount(StringBuilder message, Notification notification) {
String issueCount = notification.getFieldValue(Metric.ISSUE + COUNT);
message
.append(String.format("%s new issue%s", issueCount, "1".equals(issueCount) ? "" : "s"))
.append(NEW_LINE)
.append(NEW_LINE);
}

+ 0
- 54
server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/MetricStatsLong.java View File

@@ -1,54 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2023 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.issue.notification;

public class MetricStatsLong {
private long onCurrentAnalysis = 0;
private long offCurrentAnalysis = 0;

MetricStatsLong add(long toAdd, boolean onCurrentAnalysis) {
if (onCurrentAnalysis) {
this.onCurrentAnalysis += toAdd;
} else {
this.offCurrentAnalysis += toAdd;
}
return this;
}

public long getOnCurrentAnalysis() {
return onCurrentAnalysis;
}

public long getOffCurrentAnalysis() {
return offCurrentAnalysis;
}

public long getTotal() {
return onCurrentAnalysis + offCurrentAnalysis;
}

@Override
public String toString() {
return "MetricStatsLong{" +
"on=" + onCurrentAnalysis +
", off=" + offCurrentAnalysis +
'}';
}
}

+ 4
- 5
server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/MyNewIssuesEmailTemplate.java View File

@@ -23,7 +23,6 @@ import java.util.Date;
import org.sonar.api.config.EmailSettings;
import org.sonar.api.notifications.Notification;
import org.sonar.api.utils.DateUtils;
import org.sonar.core.i18n.I18n;
import org.sonar.server.issue.notification.NewIssuesStatistics.Metric;

/**
@@ -31,8 +30,8 @@ import org.sonar.server.issue.notification.NewIssuesStatistics.Metric;
*/
public class MyNewIssuesEmailTemplate extends AbstractNewIssuesEmailTemplate {

public MyNewIssuesEmailTemplate(EmailSettings settings, I18n i18n) {
super(settings, i18n);
public MyNewIssuesEmailTemplate(EmailSettings settings) {
super(settings);
}

@Override
@@ -47,10 +46,10 @@ public class MyNewIssuesEmailTemplate extends AbstractNewIssuesEmailTemplate {

@Override
protected String subject(Notification notification, String fullProjectName) {
int issueCount = Integer.parseInt(notification.getFieldValue(Metric.RULE_TYPE + COUNT));
String issueCount = notification.getFieldValue(Metric.ISSUE + COUNT);
return String.format("You have %s new issue%s on project %s",
issueCount,
issueCount > 1 ? "s" : "",
"1".equals(issueCount) ? "" : "s",
fullProjectName);
}


+ 2
- 3
server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/NewIssuesEmailTemplate.java View File

@@ -21,15 +21,14 @@ package org.sonar.server.issue.notification;

import org.sonar.api.config.EmailSettings;
import org.sonar.api.notifications.Notification;
import org.sonar.core.i18n.I18n;

/**
* Creates email message for notification "new-issues".
*/
public class NewIssuesEmailTemplate extends AbstractNewIssuesEmailTemplate {

public NewIssuesEmailTemplate(EmailSettings settings, I18n i18n) {
super(settings, i18n);
public NewIssuesEmailTemplate(EmailSettings settings) {
super(settings);
}

@Override

+ 5
- 18
server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/NewIssuesNotification.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.server.issue.notification;

import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
@@ -30,9 +29,7 @@ import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.api.notifications.Notification;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.Durations;
import org.sonar.server.issue.notification.NewIssuesStatistics.Metric;

@@ -43,7 +40,7 @@ import static org.sonar.server.issue.notification.AbstractNewIssuesEmailTemplate
import static org.sonar.server.issue.notification.NewIssuesEmailTemplate.FIELD_PROJECT_DATE;
import static org.sonar.server.issue.notification.NewIssuesEmailTemplate.FIELD_PROJECT_KEY;
import static org.sonar.server.issue.notification.NewIssuesEmailTemplate.FIELD_PROJECT_NAME;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.RULE_TYPE;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.ISSUE;

public class NewIssuesNotification extends Notification {

@@ -125,9 +122,9 @@ public class NewIssuesNotification extends Notification {
}

public NewIssuesNotification setStatistics(String projectName, NewIssuesStatistics.Stats stats) {
setDefaultMessage(stats.getDistributedMetricStats(RULE_TYPE).getOnCurrentAnalysis() + " new issues on " + projectName + ".\n");
setDefaultMessage(stats.getIssueCount().getOnCurrentAnalysis() + " new issues on " + projectName + ".\n");

setRuleTypeStatistics(stats);
setIssueStatistics(stats);
setAssigneesStatistics(stats);
setTagsStatistics(stats);
setComponentsStatistics(stats);
@@ -200,18 +197,8 @@ public class NewIssuesNotification extends Notification {
.toList();
}

public NewIssuesNotification setDebt(Duration debt) {
setFieldValue(Metric.EFFORT + COUNT, durations.format(debt));
return this;
}

private void setRuleTypeStatistics(NewIssuesStatistics.Stats stats) {
DistributedMetricStatsInt distributedMetricStats = stats.getDistributedMetricStats(RULE_TYPE);
setFieldValue(RULE_TYPE + COUNT, String.valueOf(distributedMetricStats.getOnCurrentAnalysis()));
Arrays.stream(RuleType.values())
.forEach(ruleType -> setFieldValue(
RULE_TYPE + DOT + ruleType + COUNT,
String.valueOf(distributedMetricStats.getForLabel(ruleType.name()).map(MetricStatsInt::getOnCurrentAnalysis).orElse(0))));
private void setIssueStatistics(NewIssuesStatistics.Stats stats) {
setFieldValue(ISSUE + COUNT, String.valueOf(stats.getIssueCount().getOnCurrentAnalysis()));
}

@Override

+ 8
- 14
server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/NewIssuesStatistics.java View File

@@ -24,13 +24,11 @@ import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Predicate;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.Duration;
import org.sonar.core.issue.DefaultIssue;

import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.ASSIGNEE;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.COMPONENT;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.RULE;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.RULE_TYPE;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.TAG;

public class NewIssuesStatistics {
@@ -68,7 +66,7 @@ public class NewIssuesStatistics {
}

public enum Metric {
RULE_TYPE(true), TAG(true), COMPONENT(true), ASSIGNEE(true), EFFORT(false), RULE(true);
ISSUE(false), TAG(true), COMPONENT(true), ASSIGNEE(true), RULE(true);
private final boolean isComputedByDistribution;

Metric(boolean isComputedByDistribution) {
@@ -91,7 +89,7 @@ public class NewIssuesStatistics {
public static class Stats {
private final Predicate<DefaultIssue> onCurrentAnalysisPredicate;
private final Map<Metric, DistributedMetricStatsInt> distributions = new EnumMap<>(Metric.class);
private MetricStatsLong effortStats = new MetricStatsLong();
private final MetricStatsInt issueCount = new MetricStatsInt();

public Stats(Predicate<DefaultIssue> onCurrentAnalysisPredicate) {
this.onCurrentAnalysisPredicate = onCurrentAnalysisPredicate;
@@ -104,7 +102,7 @@ public class NewIssuesStatistics {

public void add(DefaultIssue issue) {
boolean onCurrentAnalysis = onCurrentAnalysisPredicate.test(issue);
distributions.get(RULE_TYPE).increment(issue.type().name(), onCurrentAnalysis);
issueCount.increment(onCurrentAnalysis);
String componentUuid = issue.componentUuid();
if (componentUuid != null) {
distributions.get(COMPONENT).increment(componentUuid, onCurrentAnalysis);
@@ -120,33 +118,29 @@ public class NewIssuesStatistics {
for (String tag : issue.tags()) {
distributions.get(TAG).increment(tag, onCurrentAnalysis);
}
Duration effort = issue.effort();
if (effort != null) {
effortStats.add(effort.toMinutes(), onCurrentAnalysis);
}
}

public DistributedMetricStatsInt getDistributedMetricStats(Metric metric) {
return distributions.get(metric);
}

public MetricStatsLong effort() {
return effortStats;
public MetricStatsInt getIssueCount() {
return issueCount;
}

public boolean hasIssues() {
return getDistributedMetricStats(RULE_TYPE).getTotal() > 0;
return getIssueCount().getTotal() > 0;
}

public boolean hasIssuesOnCurrentAnalysis() {
return getDistributedMetricStats(RULE_TYPE).getOnCurrentAnalysis() > 0;
return getIssueCount().getOnCurrentAnalysis() > 0;
}

@Override
public String toString() {
return "Stats{" +
"distributions=" + distributions +
", effortStats=" + effortStats +
", issueCount=" + issueCount +
'}';
}
}

+ 45
- 69
server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/MyNewIssuesEmailTemplateTest.java View File

@@ -23,34 +23,26 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.config.EmailSettings;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.notifications.Notification;
import org.sonar.api.platform.Server;
import org.sonar.server.l18n.I18nRule;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.COMPONENT;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.EFFORT;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.ISSUE;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.RULE;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.RULE_TYPE;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.TAG;

public class MyNewIssuesEmailTemplateTest {

@Rule
public I18nRule i18n = new I18nRule()
.put("issue.type.BUG", "Bug")
.put("issue.type.CODE_SMELL", "Code Smell")
.put("issue.type.VULNERABILITY", "Vulnerability");
private MapSettings settings = new MapSettings();

private Server server = mock(Server.class);
private MyNewIssuesEmailTemplate underTest = new MyNewIssuesEmailTemplate(new EmailSettings(settings.asConfig(), server), i18n);
private MyNewIssuesEmailTemplate underTest = new MyNewIssuesEmailTemplate(new EmailSettings(settings.asConfig(), server));

@Before
public void setUp() {
@@ -74,27 +66,24 @@ public class MyNewIssuesEmailTemplateTest {
EmailMessage message = underTest.format(notification);

// TODO datetime to be completed when test is isolated from JVM timezone
assertThat(message.getMessage()).startsWith(
"Project: Struts\n" +
"\n" +
"32 new issues (new debt: 1d3h)\n" +
"\n" +
" Type\n" +
" Bug: 1 Vulnerability: 3 Code Smell: 0\n" +
"\n" +
" Rules\n" +
" Rule the Universe (Clojure): 42\n" +
" Rule the World (Java): 5\n" +
"\n" +
" Tags\n" +
" oscar: 3\n" +
" cesar: 10\n" +
"\n" +
" Most impacted files\n" +
" /path/to/file: 3\n" +
" /path/to/directory: 7\n" +
"\n" +
"More details at: http://nemo.sonarsource.org/project/issues?id=org.apache%3Astruts&assignees=lo.gin&createdAt=2010-05-18");
assertThat(message.getMessage()).startsWith("""
Project: Struts
32 new issues
Rules
Rule the Universe (Clojure): 42
Rule the World (Java): 5
Tags
oscar: 3
cesar: 10
Most impacted files
/path/to/file: 3
/path/to/directory: 7
More details at: http://nemo.sonarsource.org/project/issues?id=org.apache%3Astruts&assignees=lo.gin&createdAt=2010-05-18""");
}

@Test
@@ -133,16 +122,13 @@ public class MyNewIssuesEmailTemplateTest {
EmailMessage message = underTest.format(notification);

// TODO datetime to be completed when test is isolated from JVM timezone
assertThat(message.getMessage())
.startsWith("Project: Struts\n" +
"Version: 52.0\n" +
"\n" +
"32 new issues (new debt: 1d3h)\n" +
"\n" +
" Type\n" +
" Bug: 1 Vulnerability: 3 Code Smell: 0\n" +
"\n" +
"More details at: http://nemo.sonarsource.org/project/issues?id=org.apache%3Astruts&assignees=lo.gin&createdAt=2010-05-18");
assertThat(message.getMessage()).startsWith("""
Project: Struts
Version: 52.0
32 new issues
More details at: http://nemo.sonarsource.org/project/issues?id=org.apache%3Astruts&assignees=lo.gin&createdAt=2010-05-18""");
}

@Test
@@ -154,17 +140,14 @@ public class MyNewIssuesEmailTemplateTest {
EmailMessage message = underTest.format(notification);

// TODO datetime to be completed when test is isolated from JVM timezone
assertThat(message.getMessage())
.startsWith("Project: Struts\n" +
"Branch: feature1\n" +
"Version: 52.0\n" +
"\n" +
"32 new issues (new debt: 1d3h)\n" +
"\n" +
" Type\n" +
" Bug: 1 Vulnerability: 3 Code Smell: 0\n" +
"\n" +
"More details at: http://nemo.sonarsource.org/project/issues?id=org.apache%3Astruts&assignees=lo.gin&branch=feature1&createdAt=2010-05-18");
assertThat(message.getMessage()).startsWith("""
Project: Struts
Branch: feature1
Version: 52.0
32 new issues
More details at: http://nemo.sonarsource.org/project/issues?id=org.apache%3Astruts&assignees=lo.gin&branch=feature1&createdAt=2010-05-18""");
}

@Test
@@ -176,7 +159,7 @@ public class MyNewIssuesEmailTemplateTest {
assertThat(message.getSubject())
.isEqualTo("You have 1 new issue on project Struts");
assertThat(message.getMessage())
.contains("1 new issue (new debt: 1d3h)\n");
.contains("1 new issue\n");
}

@Test
@@ -187,22 +170,19 @@ public class MyNewIssuesEmailTemplateTest {
EmailMessage message = underTest.format(notification);

// TODO datetime to be completed when test is isolated from JVM timezone
assertThat(message.getMessage())
.startsWith("Project: Struts\n" +
"Branch: feature1\n" +
"\n" +
"32 new issues (new debt: 1d3h)\n" +
"\n" +
" Type\n" +
" Bug: 1 Vulnerability: 3 Code Smell: 0\n" +
"\n" +
"More details at: http://nemo.sonarsource.org/project/issues?id=org.apache%3Astruts&assignees=lo.gin&branch=feature1&createdAt=2010-05-18");
assertThat(message.getMessage()).startsWith("""
Project: Struts
Branch: feature1
32 new issues
More details at: http://nemo.sonarsource.org/project/issues?id=org.apache%3Astruts&assignees=lo.gin&branch=feature1&createdAt=2010-05-18""");
}

@Test
public void do_not_add_footer_when_properties_missing() {
Notification notification = new Notification(MyNewIssuesNotification.MY_NEW_ISSUES_NOTIF_TYPE)
.setFieldValue(RULE_TYPE + ".count", "32")
.setFieldValue(ISSUE + ".count", "32")
.setFieldValue("projectName", "Struts");

EmailMessage message = underTest.format(notification);
@@ -215,11 +195,7 @@ public class MyNewIssuesEmailTemplateTest {
.setFieldValue("projectKey", "org.apache:struts")
.setFieldValue("projectDate", "2010-05-18T14:50:45+0000")
.setFieldValue("assignee", "lo.gin")
.setFieldValue(EFFORT + ".count", "1d3h")
.setFieldValue(RULE_TYPE + ".count", String.valueOf(count))
.setFieldValue(RULE_TYPE + ".BUG.count", "1")
.setFieldValue(RULE_TYPE + ".VULNERABILITY.count", "3")
.setFieldValue(RULE_TYPE + ".CODE_SMELL.count", "0");
.setFieldValue(ISSUE + ".count", String.valueOf(count));
}

private void addTags(Notification notification) {

+ 52
- 76
server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/NewIssuesEmailTemplateTest.java View File

@@ -23,35 +23,27 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.config.EmailSettings;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.notifications.Notification;
import org.sonar.api.platform.Server;
import org.sonar.server.l18n.I18nRule;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.ASSIGNEE;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.COMPONENT;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.EFFORT;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.ISSUE;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.RULE;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.RULE_TYPE;
import static org.sonar.server.issue.notification.NewIssuesStatistics.Metric.TAG;

public class NewIssuesEmailTemplateTest {

@Rule
public I18nRule i18n = new I18nRule()
.put("issue.type.BUG", "Bug")
.put("issue.type.CODE_SMELL", "Code Smell")
.put("issue.type.VULNERABILITY", "Vulnerability");
private MapSettings settings = new MapSettings();

private Server server = mock(Server.class);
private NewIssuesEmailTemplate template = new NewIssuesEmailTemplate(new EmailSettings(settings.asConfig(), server), i18n);
private NewIssuesEmailTemplate template = new NewIssuesEmailTemplate(new EmailSettings(settings.asConfig(), server));

@Before
public void setUp() {
@@ -80,7 +72,7 @@ public class NewIssuesEmailTemplateTest {

EmailMessage message = template.format(notification);

assertThat(message.getSubject()).isEqualTo("Struts: 32 new issues (new debt: 1d3h)");
assertThat(message.getSubject()).isEqualTo("Struts: 32 new issues");
}

@Test
@@ -90,7 +82,7 @@ public class NewIssuesEmailTemplateTest {

EmailMessage message = template.format(notification);

assertThat(message.getSubject()).isEqualTo("Struts (feature1): 32 new issues (new debt: 1d3h)");
assertThat(message.getSubject()).isEqualTo("Struts (feature1): 32 new issues");
}

@Test
@@ -105,32 +97,29 @@ public class NewIssuesEmailTemplateTest {
EmailMessage message = template.format(notification);

// TODO datetime to be completed when test is isolated from JVM timezone
assertThat(message.getMessage())
.startsWith("Project: Struts\n" +
"Version: 42.1.1\n" +
"\n" +
"32 new issues (new debt: 1d3h)\n" +
"\n" +
" Type\n" +
" Bug: 1 Vulnerability: 10 Code Smell: 3\n" +
"\n" +
" Assignees\n" +
" robin.williams: 5\n" +
" al.pacino: 7\n" +
"\n" +
" Rules\n" +
" Rule the Universe (Clojure): 42\n" +
" Rule the World (Java): 5\n" +
"\n" +
" Tags\n" +
" oscar: 3\n" +
" cesar: 10\n" +
"\n" +
" Most impacted files\n" +
" /path/to/file: 3\n" +
" /path/to/directory: 7\n" +
"\n" +
"More details at: http://nemo.sonarsource.org/project/issues?id=org.apache%3Astruts&createdAt=2010-05-1");
assertThat(message.getMessage()).startsWith("""
Project: Struts
Version: 42.1.1
32 new issues
Assignees
robin.williams: 5
al.pacino: 7
Rules
Rule the Universe (Clojure): 42
Rule the World (Java): 5
Tags
oscar: 3
cesar: 10
Most impacted files
/path/to/file: 3
/path/to/directory: 7
More details at: http://nemo.sonarsource.org/project/issues?id=org.apache%3Astruts&createdAt=2010-05-18""");
}

@Test
@@ -140,15 +129,12 @@ public class NewIssuesEmailTemplateTest {
EmailMessage message = template.format(notification);

// TODO datetime to be completed when test is isolated from JVM timezone
assertThat(message.getMessage())
.startsWith("Project: Struts\n" +
"\n" +
"32 new issues (new debt: 1d3h)\n" +
"\n" +
" Type\n" +
" Bug: 1 Vulnerability: 10 Code Smell: 3\n" +
"\n" +
"More details at: http://nemo.sonarsource.org/project/issues?id=org.apache%3Astruts&createdAt=2010-05-1");
assertThat(message.getMessage()).startsWith("""
Project: Struts
32 new issues
More details at: http://nemo.sonarsource.org/project/issues?id=org.apache%3Astruts&createdAt=2010-05-18""");
}

@Test
@@ -158,9 +144,9 @@ public class NewIssuesEmailTemplateTest {
EmailMessage message = template.format(notification);

assertThat(message.getSubject())
.isEqualTo("Struts: 1 new issue (new debt: 1d3h)");
.isEqualTo("Struts: 1 new issue");
assertThat(message.getMessage())
.contains("1 new issue (new debt: 1d3h)\n");
.contains("1 new issue\n");
}

@Test
@@ -171,16 +157,13 @@ public class NewIssuesEmailTemplateTest {
EmailMessage message = template.format(notification);

// TODO datetime to be completed when test is isolated from JVM timezone
assertThat(message.getMessage())
.startsWith("Project: Struts\n" +
"Branch: feature1\n" +
"\n" +
"32 new issues (new debt: 1d3h)\n" +
"\n" +
" Type\n" +
" Bug: 1 Vulnerability: 10 Code Smell: 3\n" +
"\n" +
"More details at: http://nemo.sonarsource.org/project/issues?id=org.apache%3Astruts&branch=feature1&createdAt=2010-05-1");
assertThat(message.getMessage()).startsWith("""
Project: Struts
Branch: feature1
32 new issues
More details at: http://nemo.sonarsource.org/project/issues?id=org.apache%3Astruts&branch=feature1&createdAt=2010-05-18""");
}

@Test
@@ -192,23 +175,20 @@ public class NewIssuesEmailTemplateTest {
EmailMessage message = template.format(notification);

// TODO datetime to be completed when test is isolated from JVM timezone
assertThat(message.getMessage())
.startsWith("Project: Struts\n" +
"Branch: feature1\n" +
"Version: 42.1.1\n" +
"\n" +
"32 new issues (new debt: 1d3h)\n" +
"\n" +
" Type\n" +
" Bug: 1 Vulnerability: 10 Code Smell: 3\n" +
"\n" +
"More details at: http://nemo.sonarsource.org/project/issues?id=org.apache%3Astruts&branch=feature1&createdAt=2010-05-1");
assertThat(message.getMessage()).startsWith("""
Project: Struts
Branch: feature1
Version: 42.1.1
32 new issues
More details at: http://nemo.sonarsource.org/project/issues?id=org.apache%3Astruts&branch=feature1&createdAt=2010-05-18""");
}

@Test
public void do_not_add_footer_when_properties_missing() {
Notification notification = new Notification(NewIssuesNotification.TYPE)
.setFieldValue(RULE_TYPE + ".count", "32")
.setFieldValue(ISSUE + ".count", "32")
.setFieldValue("projectName", "Struts");

EmailMessage message = template.format(notification);
@@ -221,11 +201,7 @@ public class NewIssuesEmailTemplateTest {
.setFieldValue("projectName", "Struts")
.setFieldValue("projectKey", "org.apache:struts")
.setFieldValue("projectDate", "2010-05-18T14:50:45+0000")
.setFieldValue(EFFORT + ".count", "1d3h")
.setFieldValue(RULE_TYPE + ".count", String.valueOf(count))
.setFieldValue(RULE_TYPE + ".BUG.count", "1")
.setFieldValue(RULE_TYPE + ".CODE_SMELL.count", "3")
.setFieldValue(RULE_TYPE + ".VULNERABILITY.count", "10");
.setFieldValue(ISSUE + ".count", String.valueOf(count));
}

private void addAssignees(Notification notification) {

+ 23
- 88
server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/NewIssuesStatisticsTest.java View File

@@ -21,7 +21,6 @@ package org.sonar.server.issue.notification;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
@@ -40,7 +39,6 @@ import org.sonar.server.issue.notification.NewIssuesStatistics.Metric;
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

public class NewIssuesStatisticsTest {

@@ -48,22 +46,12 @@ public class NewIssuesStatisticsTest {
private RuleType randomRuleTypeExceptHotspot = RuleType.values()[random.nextInt(RuleType.values().length - 1)];
private NewIssuesStatistics underTest = new NewIssuesStatistics(Issue::isNew);

@Test
public void add_fails_with_NPE_if_RuleType_is_null() {
String assignee = randomAlphanumeric(10);
DefaultIssue issue = new DefaultIssue().setType(null).setAssigneeUuid(assignee).setNew(new Random().nextBoolean());

assertThatThrownBy(() -> underTest.add(issue))
.isInstanceOf(NullPointerException.class);
}

@Test
public void add_issues_with_correct_global_statistics() {
DefaultIssue issue = new DefaultIssue()
.setAssigneeUuid("maynard")
.setComponentUuid("file-uuid")
.setNew(true)
.setType(RuleType.BUG)
.setRuleKey(RuleKey.of("SonarQube", "rule-the-world"))
.setTags(Lists.newArrayList("bug", "owasp"))
.setEffort(Duration.create(5L));
@@ -78,42 +66,44 @@ public class NewIssuesStatisticsTest {
assertThat(countDistributionTotal(Metric.ASSIGNEE, "wrong.login")).isNull();
assertThat(countDistributionTotal(Metric.COMPONENT, "file-uuid")).isEqualTo(3);
assertThat(countDistributionTotal(Metric.COMPONENT, "wrong-uuid")).isNull();
assertThat(countDistributionTotal(Metric.RULE_TYPE, RuleType.BUG.name())).isEqualTo(3);
assertThat(countDistributionTotal(Metric.RULE_TYPE, RuleType.CODE_SMELL.name())).isNull();
assertThat(countDistributionTotal(Metric.TAG, "owasp")).isEqualTo(3);
assertThat(countDistributionTotal(Metric.TAG, "wrong-tag")).isNull();
assertThat(countDistributionTotal(Metric.RULE, "SonarQube:rule-the-world")).isEqualTo(3);
assertThat(countDistributionTotal(Metric.RULE, "SonarQube:has-a-fake-rule")).isNull();
assertThat(underTest.globalStatistics().effort().getTotal()).isEqualTo(15L);
assertThat(underTest.globalStatistics().getIssueCount().getTotal()).isEqualTo(3);
assertThat(underTest.globalStatistics().hasIssues()).isTrue();
assertThat(underTest.hasIssues()).isTrue();
assertThat(underTest.getAssigneesStatistics().get("maynard").hasIssues()).isTrue();
}

@Test
public void add_counts_issue_per_RuleType_on_current_analysis_globally_and_per_assignee() {
public void add_counts_issues_on_current_analysis_globally_and_per_assignee() {
String assignee = randomAlphanumeric(10);
Arrays.stream(RuleType.values())
.map(ruleType -> new DefaultIssue().setType(ruleType).setAssigneeUuid(assignee).setNew(true))
IntStream.range(0, 10)
.mapToObj(i -> new DefaultIssue().setAssigneeUuid(assignee).setNew(true))
.forEach(underTest::add);

DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE_TYPE);
DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.RULE_TYPE);
Stream.of(globalDistribution, assigneeDistribution)
.forEach(distribution -> Arrays.stream(RuleType.values()).forEach(ruleType -> assertStats(distribution, ruleType.name(), 1, 1)));
MetricStatsInt globalIssueCount = underTest.globalStatistics().getIssueCount();
MetricStatsInt assigneeIssueCount = underTest.getAssigneesStatistics().get(assignee).getIssueCount();
assertThat(globalIssueCount.getOnCurrentAnalysis()).isEqualTo(10);
assertThat(globalIssueCount.getTotal()).isEqualTo(10);
assertThat(assigneeIssueCount.getOnCurrentAnalysis()).isEqualTo(10);
assertThat(assigneeIssueCount.getTotal()).isEqualTo(10);
}

@Test
public void add_counts_issue_per_RuleType_off_current_analysis_globally_and_per_assignee() {
public void add_counts_issues_off_current_analysis_globally_and_per_assignee() {
String assignee = randomAlphanumeric(10);
Arrays.stream(RuleType.values())
.map(ruleType -> new DefaultIssue().setType(ruleType).setAssigneeUuid(assignee).setNew(false))
IntStream.range(0, 10)
.mapToObj(i -> new DefaultIssue().setAssigneeUuid(assignee).setNew(false))
.forEach(underTest::add);

DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE_TYPE);
DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.RULE_TYPE);
Stream.of(globalDistribution, assigneeDistribution)
.forEach(distribution -> Arrays.stream(RuleType.values()).forEach(ruleType -> assertStats(distribution, ruleType.name(), 0, 1)));
MetricStatsInt globalIssueCount = underTest.globalStatistics().getIssueCount();
MetricStatsInt assigneeIssueCount = underTest.getAssigneesStatistics().get(assignee).getIssueCount();
assertThat(globalIssueCount.getOnCurrentAnalysis()).isZero();
assertThat(globalIssueCount.getTotal()).isEqualTo(10);
assertThat(assigneeIssueCount.getOnCurrentAnalysis()).isZero();
assertThat(assigneeIssueCount.getTotal()).isEqualTo(10);
}

@Test
@@ -308,57 +298,6 @@ public class NewIssuesStatisticsTest {
});
}

@Test
public void add_sums_effort_on_current_analysis_globally_and_per_assignee() {
Random random = new Random();
List<Integer> efforts = IntStream.range(0, 1 + random.nextInt(10)).mapToObj(i -> 10_000 * i).toList();
int expected = efforts.stream().mapToInt(s -> s).sum();
String assignee = randomAlphanumeric(10);
efforts.stream()
.map(effort -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setEffort(Duration.create(effort)).setAssigneeUuid(assignee).setNew(true))
.forEach(underTest::add);

MetricStatsLong globalDistribution = underTest.globalStatistics().effort();
MetricStatsLong assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).effort();
Stream.of(globalDistribution, assigneeDistribution)
.forEach(distribution -> {
assertThat(distribution.getOnCurrentAnalysis()).isEqualTo(expected);
assertThat(distribution.getOffCurrentAnalysis()).isZero();
assertThat(distribution.getTotal()).isEqualTo(expected);
});
}

@Test
public void add_sums_effort_off_current_analysis_globally_and_per_assignee() {
Random random = new Random();
List<Integer> efforts = IntStream.range(0, 1 + random.nextInt(10)).mapToObj(i -> 10_000 * i).toList();
int expected = efforts.stream().mapToInt(s -> s).sum();
String assignee = randomAlphanumeric(10);
efforts.stream()
.map(effort -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setEffort(Duration.create(effort)).setAssigneeUuid(assignee).setNew(false))
.forEach(underTest::add);

MetricStatsLong globalDistribution = underTest.globalStatistics().effort();
MetricStatsLong assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).effort();
Stream.of(globalDistribution, assigneeDistribution)
.forEach(distribution -> {
assertThat(distribution.getOnCurrentAnalysis()).isZero();
assertThat(distribution.getOffCurrentAnalysis()).isEqualTo(expected);
assertThat(distribution.getTotal()).isEqualTo(expected);
});
}

@Test
public void add_does_not_sum_effort_if_null_neither_globally_nor_per_assignee() {
String assignee = randomAlphanumeric(10);
underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setEffort(null).setAssigneeUuid(assignee).setNew(new Random().nextBoolean()));

MetricStatsLong globalDistribution = underTest.globalStatistics().effort();
MetricStatsLong assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).effort();
Stream.of(globalDistribution, assigneeDistribution)
.forEach(distribution -> assertThat(distribution.getTotal()).isZero());
}

@Test
public void do_not_have_issues_when_no_issue_added() {
assertThat(underTest.globalStatistics().hasIssues()).isFalse();
@@ -379,12 +318,10 @@ public class NewIssuesStatisticsTest {
.setRuleKey(ruleKey)
.setEffort(Duration.create(effort)));

assertThat(underTest.toString())
.isEqualTo("NewIssuesStatistics{" +
assertThat(underTest)
.hasToString("NewIssuesStatistics{" +
"assigneesStatistics={" + assignee + "=" +
"Stats{distributions={" +
"RULE_TYPE=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
"statsPerLabel={" + randomRuleTypeExceptHotspot.name() + "=MetricStatsInt{on=1, off=0}}}, " +
"TAG=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
"statsPerLabel={" + tag + "=MetricStatsInt{on=1, off=0}}}, " +
"COMPONENT=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
@@ -393,10 +330,8 @@ public class NewIssuesStatisticsTest {
"statsPerLabel={" + assignee + "=MetricStatsInt{on=1, off=0}}}, " +
"RULE=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
"statsPerLabel={" + ruleKey.toString() + "=MetricStatsInt{on=1, off=0}}}}, " +
"effortStats=MetricStatsLong{on=" + effort + ", off=0}}}, " +
"issueCount=MetricStatsInt{on=1, off=0}}}, " +
"globalStatistics=Stats{distributions={" +
"RULE_TYPE=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
"statsPerLabel={" + randomRuleTypeExceptHotspot.name() + "=MetricStatsInt{on=1, off=0}}}, " +
"TAG=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
"statsPerLabel={" + tag + "=MetricStatsInt{on=1, off=0}}}, " +
"COMPONENT=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
@@ -405,7 +340,7 @@ public class NewIssuesStatisticsTest {
"statsPerLabel={" + assignee + "=MetricStatsInt{on=1, off=0}}}, " +
"RULE=DistributedMetricStatsInt{globalStats=MetricStatsInt{on=1, off=0}, " +
"statsPerLabel={" + ruleKey.toString() + "=MetricStatsInt{on=1, off=0}}}}, " +
"effortStats=MetricStatsLong{on=" + effort + ", off=0}}}");
"issueCount=MetricStatsInt{on=1, off=0}}}");
}

@CheckForNull

Loading…
Cancel
Save