@@ -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; | |||
} | |||
@@ -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; | |||
}) |
@@ -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); |
@@ -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); | |||
} |
@@ -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 + | |||
'}'; | |||
} | |||
} |
@@ -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); | |||
} | |||
@@ -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 |
@@ -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 |
@@ -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 + | |||
'}'; | |||
} | |||
} |
@@ -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) { |
@@ -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) { |
@@ -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 |