diff options
author | Evgeny Mandrikov <mandrikov@gmail.com> | 2011-07-26 14:25:57 +0400 |
---|---|---|
committer | Evgeny Mandrikov <mandrikov@gmail.com> | 2011-07-26 18:23:56 +0400 |
commit | b508728dc8d993a5b4ad5839b9553228b3ef4b47 (patch) | |
tree | 3582bdc3962c5c10438cadde42849610e42214e3 /plugins/sonar-email-notifications-plugin | |
parent | fea2ef37ed0a1dfa73ebdd87799f5caa298aa2f2 (diff) | |
download | sonarqube-b508728dc8d993a5b4ad5839b9553228b3ef4b47.tar.gz sonarqube-b508728dc8d993a5b4ad5839b9553228b3ef4b47.zip |
SONAR-2596,SONAR-2601 UI for email notifications
* Add email configuration to sidebar menu
* I18n for email and notifications settings
* Email configuration properties must be secured
* Rename sonar-email-plugin to sonar-email-notifications-plugin
Diffstat (limited to 'plugins/sonar-email-notifications-plugin')
15 files changed, 1488 insertions, 0 deletions
diff --git a/plugins/sonar-email-notifications-plugin/pom.xml b/plugins/sonar-email-notifications-plugin/pom.xml new file mode 100644 index 00000000000..181e56b59e3 --- /dev/null +++ b/plugins/sonar-email-notifications-plugin/pom.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.codehaus.sonar</groupId> + <artifactId>sonar</artifactId> + <version>2.10-SNAPSHOT</version> + <relativePath>../..</relativePath> + </parent> + + <groupId>org.codehaus.sonar.plugins</groupId> + <artifactId>sonar-email-notifications-plugin</artifactId> + <packaging>sonar-plugin</packaging> + + <name>Sonar :: Plugins :: Email Notifications</name> + <description>Email Notifications</description> + + <dependencies> + <dependency> + <groupId>org.codehaus.sonar</groupId> + <artifactId>sonar-plugin-api</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.codehaus.sonar</groupId> + <artifactId>sonar-core</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-email</artifactId> + <version>1.2</version> + </dependency> + + <!-- unit tests --> + <dependency> + <groupId>org.codehaus.sonar</groupId> + <artifactId>sonar-testing-harness</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>dumbster</groupId> + <artifactId>dumbster</artifactId> + <version>1.6</version> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.codehaus.sonar</groupId> + <artifactId>sonar-packaging-maven-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <pluginName>Email notifications</pluginName> + <pluginClass>org.sonar.plugins.emailnotifications.EmailNotificationsPlugin</pluginClass> + </configuration> + </plugin> + </plugins> + </build> +</project> diff --git a/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/EmailConfiguration.java b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/EmailConfiguration.java new file mode 100644 index 00000000000..907d9bf599c --- /dev/null +++ b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/EmailConfiguration.java @@ -0,0 +1,86 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.emailnotifications; + +import org.apache.commons.configuration.Configuration; +import org.sonar.api.CoreProperties; +import org.sonar.api.ServerExtension; + +/** + * Ruby uses constants from this class. + * + * @since 2.10 + */ +public class EmailConfiguration implements ServerExtension { + + public static final String SMTP_HOST = "email.smtp_host.secured"; + public static final String SMTP_HOST_DEFAULT = ""; + public static final String SMTP_PORT = "email.smtp_port.secured"; + public static final String SMTP_PORT_DEFAULT = "25"; + public static final String SMTP_USE_TLS = "email.smtp_use_tls.secured"; + public static final boolean SMTP_USE_TLS_DEFAULT = false; + public static final String SMTP_USERNAME = "email.smtp_username.secured"; + public static final String SMTP_USERNAME_DEFAULT = ""; + public static final String SMTP_PASSWORD = "email.smtp_password.secured"; + public static final String SMTP_PASSWORD_DEFAULT = ""; + public static final String FROM = "email.from"; + public static final String FROM_DEFAULT = "noreply@nowhere"; + public static final String PREFIX = "email.prefix"; + public static final String PREFIX_DEFAULT = "[SONAR]"; + + private Configuration configuration; + + public EmailConfiguration(Configuration configuration) { + this.configuration = configuration; + } + + public String getSmtpHost() { + return configuration.getString(SMTP_HOST, SMTP_HOST_DEFAULT); + } + + public String getSmtpPort() { + return configuration.getString(SMTP_PORT, SMTP_PORT_DEFAULT); + } + + public boolean isUseTLS() { + return configuration.getBoolean(SMTP_USE_TLS, SMTP_USE_TLS_DEFAULT); + } + + public String getSmtpUsername() { + return configuration.getString(SMTP_USERNAME, SMTP_USERNAME_DEFAULT); + } + + public String getSmtpPassword() { + return configuration.getString(SMTP_PASSWORD, SMTP_PASSWORD_DEFAULT); + } + + public String getFrom() { + return configuration.getString(FROM, FROM_DEFAULT); + } + + public String getPrefix() { + return configuration.getString(PREFIX, PREFIX_DEFAULT); + } + + public String getServerBaseURL() { + return configuration.getString(CoreProperties.SERVER_BASE_URL, CoreProperties.SERVER_BASE_URL_DEFAULT_VALUE); + } + +} diff --git a/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/EmailNotificationChannel.java b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/EmailNotificationChannel.java new file mode 100644 index 00000000000..74fb59d5d0e --- /dev/null +++ b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/EmailNotificationChannel.java @@ -0,0 +1,190 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.emailnotifications; + +import java.net.MalformedURLException; +import java.net.URL; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.mail.EmailException; +import org.apache.commons.mail.SimpleEmail; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.api.database.model.User; +import org.sonar.api.notifications.Notification; +import org.sonar.api.notifications.NotificationChannel; +import org.sonar.api.security.UserFinder; +import org.sonar.plugins.emailnotifications.api.EmailMessage; +import org.sonar.plugins.emailnotifications.api.EmailTemplate; + +/** + * References: + * <ul> + * <li><a href="http://tools.ietf.org/html/rfc4021">Registration of Mail and MIME Header Fields</a></li> + * <li><a href="http://tools.ietf.org/html/rfc2919">List-Id: A Structured Field and Namespace for the Identification of Mailing Lists</a></li> + * <li><a href="https://github.com/blog/798-threaded-email-notifications">GitHub: Threaded Email Notifications</a></li> + * </ul> + * + * @since 2.10 + */ +public class EmailNotificationChannel extends NotificationChannel { + + private static final Logger LOG = LoggerFactory.getLogger(EmailNotificationChannel.class); + + /** + * @see org.apache.commons.mail.Email#setSocketConnectionTimeout(int) + * @see org.apache.commons.mail.Email#setSocketTimeout(int) + */ + private static final int SOCKET_TIMEOUT = 30000; + + /** + * Email Header Field: "List-ID". + * Value of this field should contain mailing list identifier as specified in <a href="http://tools.ietf.org/html/rfc2919">RFC 2919</a>. + */ + private static final String LIST_ID_HEADER = "List-ID"; + + /** + * Email Header Field: "List-Archive". + * Value of this field should contain URL of mailing list archive as specified in <a href="http://tools.ietf.org/html/rfc2369">RFC 2369</a>. + */ + private static final String LIST_ARCHIVE_HEADER = "List-Archive"; + + /** + * Email Header Field: "In-Reply-To". + * Value of this field should contain related message identifier as specified in <a href="http://tools.ietf.org/html/rfc2822">RFC 2822</a>. + */ + private static final String IN_REPLY_TO_HEADER = "In-Reply-To"; + + /** + * Email Header Field: "References". + * Value of this field should contain related message identifier as specified in <a href="http://tools.ietf.org/html/rfc2822">RFC 2822</a> + */ + private static final String REFERENCES_HEADER = "References"; + + private static final String FROM_NAME_DEFAULT = "Sonar"; + private static final String SUBJECT_DEFAULT = "Notification"; + + private EmailConfiguration configuration; + private EmailTemplate[] templates; + private UserFinder userFinder; + + public EmailNotificationChannel(EmailConfiguration configuration, EmailTemplate[] templates, UserFinder userFinder) { + this.configuration = configuration; + this.templates = templates; + this.userFinder = userFinder; + } + + @Override + public void deliver(Notification notification, String username) { + User user = userFinder.findByLogin(username); + if (StringUtils.isBlank(user.getEmail())) { + LOG.warn("Email not defined for user: " + username); + return; + } + EmailMessage emailMessage = format(notification); + if (emailMessage != null) { + emailMessage.setTo(user.getEmail()); + deliver(emailMessage); + } + } + + private EmailMessage format(Notification notification) { + for (EmailTemplate template : templates) { + EmailMessage email = template.format(notification); + if (email != null) { + return email; + } + } + LOG.warn("Email template not found for notification: {}", notification); + return null; + } + + /** + * Visibility has been relaxed for tests. + */ + void deliver(EmailMessage emailMessage) { + if (StringUtils.isBlank(configuration.getSmtpHost())) { + LOG.warn("SMTP host was not configured - email will not be sent"); + return; + } + try { + send(emailMessage); + } catch (EmailException e) { + LOG.error("Unable to send email", e); + } + } + + private void send(EmailMessage emailMessage) throws EmailException { + LOG.info("Sending email: {}", emailMessage); + String host = null; + try { + host = new URL(configuration.getServerBaseURL()).getHost(); + } catch (MalformedURLException e) { + // ignore + } + + SimpleEmail email = new SimpleEmail(); + if (StringUtils.isNotBlank(host)) { + /* + * Set headers for proper threading: GMail will not group messages, even if they have same subject, but don't have "In-Reply-To" and + * "References" headers. TODO investigate threading in other clients like KMail, Thunderbird, Outlook + */ + if (StringUtils.isNotEmpty(emailMessage.getMessageId())) { + String messageId = "<" + emailMessage.getMessageId() + "@" + host + ">"; + email.addHeader(IN_REPLY_TO_HEADER, messageId); + email.addHeader(REFERENCES_HEADER, messageId); + } + // Set headers for proper filtering + email.addHeader(LIST_ID_HEADER, "Sonar <sonar." + host + ">"); + email.addHeader(LIST_ARCHIVE_HEADER, configuration.getServerBaseURL()); + } + // Set general information + email.setFrom(configuration.getFrom(), StringUtils.defaultIfBlank(emailMessage.getFrom(), FROM_NAME_DEFAULT)); + email.addTo(emailMessage.getTo(), " "); + String subject = StringUtils.defaultIfBlank(StringUtils.trimToEmpty(configuration.getPrefix()) + " ", "") + + StringUtils.defaultString(emailMessage.getSubject(), SUBJECT_DEFAULT); + email.setSubject(subject); + email.setMsg(emailMessage.getMessage()); + // Send + email.setHostName(configuration.getSmtpHost()); + email.setSmtpPort(Integer.parseInt(configuration.getSmtpPort())); + email.setTLS(configuration.isUseTLS()); + if (StringUtils.isNotBlank(configuration.getSmtpUsername()) || StringUtils.isNotBlank(configuration.getSmtpPassword())) { + email.setAuthentication(configuration.getSmtpUsername(), configuration.getSmtpPassword()); + } + email.setSocketConnectionTimeout(SOCKET_TIMEOUT); + email.setSocketTimeout(SOCKET_TIMEOUT); + email.send(); + } + + /** + * Send test email. This method called from Ruby. + * + * @throws EmailException when unable to send + */ + public void sendTestEmail(String toAddress, String subject, String message) throws EmailException { + EmailMessage emailMessage = new EmailMessage(); + emailMessage.setTo(toAddress); + emailMessage.setSubject(subject); + emailMessage.setMessage(message); + send(emailMessage); + } + +} diff --git a/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/EmailNotificationsPlugin.java b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/EmailNotificationsPlugin.java new file mode 100644 index 00000000000..c5cc4ccc7de --- /dev/null +++ b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/EmailNotificationsPlugin.java @@ -0,0 +1,42 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.emailnotifications; + +import org.sonar.api.SonarPlugin; +import org.sonar.plugins.emailnotifications.reviews.ChangesInReviewAssignedToMe; +import org.sonar.plugins.emailnotifications.reviews.ChangesInReviewCreatedByMe; +import org.sonar.plugins.emailnotifications.reviews.ReviewEmailTemplate; + +import java.util.Arrays; +import java.util.List; + +public class EmailNotificationsPlugin extends SonarPlugin { + + public List getExtensions() { + return Arrays.asList( + EmailConfiguration.class, + EmailNotificationChannel.class, + + ReviewEmailTemplate.class, + ChangesInReviewAssignedToMe.class, + ChangesInReviewCreatedByMe.class); + } + +} diff --git a/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/api/EmailMessage.java b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/api/EmailMessage.java new file mode 100644 index 00000000000..f03d90caea6 --- /dev/null +++ b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/api/EmailMessage.java @@ -0,0 +1,115 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.emailnotifications.api; + +import org.apache.commons.lang.builder.ToStringBuilder; + +/** + * @since 2.10 + */ +public class EmailMessage { + + private String from; + private String to; + private String subject; + private String message; + private String messageId; + + /** + * @param from full name of user, who initiated this message or null, if message was initiated by Sonar + */ + public EmailMessage setFrom(String from) { + this.from = from; + return this; + } + + /** + * @see #setFrom(String) + */ + public String getFrom() { + return from; + } + + /** + * @param to email address where to send this message + */ + public EmailMessage setTo(String to) { + this.to = to; + return this; + } + + /** + * @see #setTo(String) + */ + public String getTo() { + return to; + } + + /** + * @param subject message subject + */ + public EmailMessage setSubject(String subject) { + this.subject = subject; + return this; + } + + /** + * @see #setSubject(String) + */ + public String getSubject() { + return subject; + } + + /** + * @param message message body + */ + public EmailMessage setMessage(String message) { + this.message = message; + return this; + } + + /** + * @see #setMessage(String) + */ + public String getMessage() { + return message; + } + + /** + * @param messageId id of message for threading + */ + public EmailMessage setMessageId(String messageId) { + this.messageId = messageId; + return this; + } + + /** + * @see #setMessageId(String) + */ + public String getMessageId() { + return messageId; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } + +} diff --git a/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/api/EmailTemplate.java b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/api/EmailTemplate.java new file mode 100644 index 00000000000..fe638eada73 --- /dev/null +++ b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/api/EmailTemplate.java @@ -0,0 +1,32 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.emailnotifications.api; + +import org.sonar.api.ServerExtension; +import org.sonar.api.notifications.Notification; + +/** + * @since 2.10 + */ +public abstract class EmailTemplate implements ServerExtension { + + public abstract EmailMessage format(Notification notification); + +} diff --git a/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/reviews/ChangesInReviewAssignedToMe.java b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/reviews/ChangesInReviewAssignedToMe.java new file mode 100644 index 00000000000..c5859ee13da --- /dev/null +++ b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/reviews/ChangesInReviewAssignedToMe.java @@ -0,0 +1,48 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.emailnotifications.reviews; + +import org.apache.commons.lang.StringUtils; +import org.sonar.api.notifications.Notification; +import org.sonar.api.notifications.NotificationDispatcher; + +/** + * This dispatcher means: "notify me when when someone changes review assigned to me". + * + * @since 2.10 + */ +public class ChangesInReviewAssignedToMe extends NotificationDispatcher { + + @Override + public void dispatch(Notification notification, Context context) { + if (StringUtils.startsWith(notification.getType(), "review")) { + String author = notification.getFieldValue("author"); // author of change + String oldAssignee = notification.getFieldValue("old.assignee"); // previous assignee + String assignee = notification.getFieldValue("assignee"); // current assignee + if (!StringUtils.equals(author, oldAssignee)) { + context.addUser(oldAssignee); + } + if (!StringUtils.equals(author, assignee)) { + context.addUser(assignee); + } + } + } + +} diff --git a/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/reviews/ChangesInReviewCreatedByMe.java b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/reviews/ChangesInReviewCreatedByMe.java new file mode 100644 index 00000000000..85f104637d0 --- /dev/null +++ b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/reviews/ChangesInReviewCreatedByMe.java @@ -0,0 +1,44 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.emailnotifications.reviews; + +import org.apache.commons.lang.StringUtils; +import org.sonar.api.notifications.Notification; +import org.sonar.api.notifications.NotificationDispatcher; + +/** + * This dispatcher means: "notify me when when someone changes review created by me". + * + * @since 2.10 + */ +public class ChangesInReviewCreatedByMe extends NotificationDispatcher { + + @Override + public void dispatch(Notification notification, Context context) { + if (StringUtils.startsWith(notification.getType(), "review")) { + String author = notification.getFieldValue("author"); // author of change + String creator = notification.getFieldValue("creator"); // creator of review + if (!StringUtils.equals(author, creator)) { + context.addUser(creator); + } + } + } + +} diff --git a/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/reviews/ReviewEmailTemplate.java b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/reviews/ReviewEmailTemplate.java new file mode 100644 index 00000000000..f09082a2d07 --- /dev/null +++ b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/reviews/ReviewEmailTemplate.java @@ -0,0 +1,117 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.emailnotifications.reviews; + +import org.apache.commons.lang.StringUtils; +import org.sonar.api.database.model.User; +import org.sonar.api.notifications.Notification; +import org.sonar.api.security.UserFinder; +import org.sonar.plugins.emailnotifications.EmailConfiguration; +import org.sonar.plugins.emailnotifications.api.EmailMessage; +import org.sonar.plugins.emailnotifications.api.EmailTemplate; + +/** + * Creates email message for notification "review-changed". + * + * @since 2.10 + */ +public class ReviewEmailTemplate extends EmailTemplate { + + private EmailConfiguration configuration; + private UserFinder userFinder; + + public ReviewEmailTemplate(EmailConfiguration configuration, UserFinder userFinder) { + this.configuration = configuration; + this.userFinder = userFinder; + } + + @Override + public EmailMessage format(Notification notification) { + if ( !"review-changed".equals(notification.getType())) { + return null; + } + String reviewId = notification.getFieldValue("reviewId"); + String author = notification.getFieldValue("author"); + StringBuilder sb = new StringBuilder(); + + append(sb, "Status", notification.getFieldValue("old.status"), notification.getFieldValue("new.status")); + append(sb, "Resolution", notification.getFieldValue("old.resolution"), notification.getFieldValue("new.resolution")); + append(sb, "Assignee", getUserFullName(notification.getFieldValue("old.assignee")), getUserFullName(notification.getFieldValue("new.assignee"))); + appendComment(sb, notification); + appendFooter(sb, notification); + + EmailMessage message = new EmailMessage() + .setMessageId("review/" + reviewId) + .setSubject("Review #" + reviewId) + .setMessage(sb.toString()); + if (author != null) { + message.setFrom(getUserFullName(author)); + } + return message; + } + + private void append(StringBuilder sb, String name, String oldValue, String newValue) { + if (oldValue != null || newValue != null) { + sb.append(name).append(": "); + if (newValue != null) { + sb.append(newValue); + } + if (oldValue != null) { + sb.append(" (was ").append(oldValue).append(")"); + } + sb.append('\n'); + } + } + + private void appendComment(StringBuilder sb, Notification notification) { + String newComment = notification.getFieldValue("new.comment"); + String oldComment = notification.getFieldValue("old.comment"); + + if (newComment != null) { // comment was added or modified + sb.append("Comment:\n ").append(newComment).append('\n'); + if (oldComment != null) { // comment was modified + sb.append("Was:\n ").append(oldComment).append('\n'); + } + } else if (oldComment != null) { // comment was deleted + sb.append("Comment deleted, was:\n ").append(oldComment).append('\n'); + } + } + + private void appendFooter(StringBuilder sb, Notification notification) { + String reviewId = notification.getFieldValue("reviewId"); + sb.append("\n--\n") + .append("See it in Sonar: ").append(configuration.getServerBaseURL()).append("/review/view/").append(reviewId).append('\n'); + } + + /** + * Visibility has been relaxed for tests. + */ + String getUserFullName(String login) { + if (login == null) { + return null; + } + User user = userFinder.findByLogin(login); + if (user == null) { // most probably user was deleted + return login; + } + return StringUtils.defaultIfBlank(user.getName(), login); + } + +} diff --git a/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/EmailConfigurationTest.java b/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/EmailConfigurationTest.java new file mode 100644 index 00000000000..92c3ab5c1df --- /dev/null +++ b/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/EmailConfigurationTest.java @@ -0,0 +1,53 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.emailnotifications; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +import org.apache.commons.configuration.BaseConfiguration; +import org.apache.commons.configuration.Configuration; +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.CoreProperties; + +public class EmailConfigurationTest { + + private EmailConfiguration emailConfiguration; + + @Before + public void setUp() { + Configuration configuration = new BaseConfiguration(); + emailConfiguration = new EmailConfiguration(configuration); + } + + @Test + public void shouldReturnDefaultValues() { + assertThat(emailConfiguration.getSmtpHost(), is("")); + assertThat(emailConfiguration.getSmtpPort(), is("25")); + assertThat(emailConfiguration.getSmtpUsername(), is("")); + assertThat(emailConfiguration.getSmtpPassword(), is("")); + assertThat(emailConfiguration.isUseTLS(), is(false)); + assertThat(emailConfiguration.getFrom(), is("noreply@nowhere")); + assertThat(emailConfiguration.getPrefix(), is("[SONAR]")); + assertThat(emailConfiguration.getServerBaseURL(), is(CoreProperties.SERVER_BASE_URL_DEFAULT_VALUE)); + } + +} diff --git a/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/EmailNotificationChannelTest.java b/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/EmailNotificationChannelTest.java new file mode 100644 index 00000000000..18c1e238de5 --- /dev/null +++ b/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/EmailNotificationChannelTest.java @@ -0,0 +1,182 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.emailnotifications; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.net.ServerSocket; + +import org.apache.commons.mail.EmailException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.sonar.plugins.emailnotifications.api.EmailMessage; + +import com.dumbster.smtp.SimpleSmtpServer; +import com.dumbster.smtp.SmtpMessage; + +public class EmailNotificationChannelTest { + + private static int port; + + private SimpleSmtpServer server; + + private EmailConfiguration configuration; + private EmailNotificationChannel channel; + + @BeforeClass + public static void selectPort() { + port = getNextAvailablePort(); + } + + private static int getNextAvailablePort() { + try { + ServerSocket socket = new ServerSocket(0); + int unusedPort = socket.getLocalPort(); + socket.close(); + return unusedPort; + } catch (IOException e) { + throw new RuntimeException("Error getting an available port from system", e); + } + } + + @Before + public void setUp() { + server = SimpleSmtpServer.start(port); + configuration = mock(EmailConfiguration.class); + channel = new EmailNotificationChannel(configuration, null, null); + } + + @After + public void tearDown() { + if (!server.isStopped()) { + server.stop(); + } + } + + @Test + public void shouldSendTestEmail() throws Exception { + configure(); + channel.sendTestEmail("user@nowhere", "Test Message from Sonar", "This is a test message from Sonar."); + + assertThat(server.getReceivedEmailSize(), is(1)); + SmtpMessage email = (SmtpMessage) server.getReceivedEmail().next(); + + assertThat(email.getHeaderValue("From"), is("Sonar <server@nowhere>")); + assertThat(email.getHeaderValue("To"), is("<user@nowhere>")); + assertThat(email.getHeaderValue("Subject"), is("[SONAR] Test Message from Sonar")); + assertThat(email.getBody(), is("This is a test message from Sonar.")); + } + + @Test(expected = EmailException.class) + public void shouldThrowAnExceptionWhenUnableToSendTestEmail() throws Exception { + configure(); + server.stop(); + + channel.sendTestEmail("user@nowhere", "Test Message from Sonar", "This is a test message from Sonar."); + } + + @Test + public void shouldNotSendEmailWhenHostnameNotConfigured() throws Exception { + EmailMessage emailMessage = new EmailMessage() + .setTo("user@nowhere") + .setSubject("Foo") + .setMessage("Bar"); + channel.deliver(emailMessage); + assertThat(server.getReceivedEmailSize(), is(0)); + } + + @Test + public void shouldSendThreadedEmail() throws Exception { + configure(); + EmailMessage emailMessage = new EmailMessage() + .setMessageId("reviews/view/1") + .setFrom("Full Username") + .setTo("user@nowhere") + .setSubject("Review #3") + .setMessage("I'll take care of this violation."); + channel.deliver(emailMessage); + + assertThat(server.getReceivedEmailSize(), is(1)); + SmtpMessage email = (SmtpMessage) server.getReceivedEmail().next(); + + assertThat(email.getHeaderValue("In-Reply-To"), is("<reviews/view/1@nemo.sonarsource.org>")); + assertThat(email.getHeaderValue("References"), is("<reviews/view/1@nemo.sonarsource.org>")); + + assertThat(email.getHeaderValue("List-ID"), is("Sonar <sonar.nemo.sonarsource.org>")); + assertThat(email.getHeaderValue("List-Archive"), is("http://nemo.sonarsource.org")); + + assertThat(email.getHeaderValue("From"), is("Full Username <server@nowhere>")); + assertThat(email.getHeaderValue("To"), is("<user@nowhere>")); + assertThat(email.getHeaderValue("Subject"), is("[SONAR] Review #3")); + assertThat(email.getBody(), is("I'll take care of this violation.")); + } + + @Test + public void shouldSendNonThreadedEmail() throws Exception { + configure(); + EmailMessage emailMessage = new EmailMessage() + .setTo("user@nowhere") + .setSubject("Foo") + .setMessage("Bar"); + channel.deliver(emailMessage); + + assertThat(server.getReceivedEmailSize(), is(1)); + SmtpMessage email = (SmtpMessage) server.getReceivedEmail().next(); + + assertThat(email.getHeaderValue("In-Reply-To"), nullValue()); + assertThat(email.getHeaderValue("References"), nullValue()); + + assertThat(email.getHeaderValue("List-ID"), is("Sonar <sonar.nemo.sonarsource.org>")); + assertThat(email.getHeaderValue("List-Archive"), is("http://nemo.sonarsource.org")); + + assertThat(email.getHeaderValue("From"), is("Sonar <server@nowhere>")); + assertThat(email.getHeaderValue("To"), is("<user@nowhere>")); + assertThat(email.getHeaderValue("Subject"), is("[SONAR] Foo")); + assertThat(email.getBody(), is("Bar")); + } + + @Test + public void shouldNotThrowAnExceptionWhenUnableToSendEmail() throws Exception { + configure(); + server.stop(); + + EmailMessage emailMessage = new EmailMessage() + .setTo("user@nowhere") + .setSubject("Foo") + .setMessage("Bar"); + channel.deliver(emailMessage); + } + + private void configure() { + when(configuration.getSmtpHost()).thenReturn("localhost"); + when(configuration.getSmtpPort()).thenReturn(Integer.toString(port)); + when(configuration.getFrom()).thenReturn("server@nowhere"); + when(configuration.getPrefix()).thenReturn("[SONAR]"); + when(configuration.getServerBaseURL()).thenReturn("http://nemo.sonarsource.org"); + } + +} diff --git a/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/EmailNotificationsPluginTest.java b/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/EmailNotificationsPluginTest.java new file mode 100644 index 00000000000..b6deef32eb8 --- /dev/null +++ b/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/EmailNotificationsPluginTest.java @@ -0,0 +1,34 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.emailnotifications; + +import static org.hamcrest.Matchers.greaterThan; +import static org.junit.Assert.assertThat; + +import org.junit.Test; + +public class EmailNotificationsPluginTest { + + @Test + public void testGetExtensions() { + assertThat(new EmailNotificationsPlugin().getExtensions().size(), greaterThan(1)); + } + +} diff --git a/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/reviews/ChangesInReviewAssignedToMeTest.java b/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/reviews/ChangesInReviewAssignedToMeTest.java new file mode 100644 index 00000000000..e9b169c6363 --- /dev/null +++ b/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/reviews/ChangesInReviewAssignedToMeTest.java @@ -0,0 +1,78 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.emailnotifications.reviews; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.notifications.Notification; +import org.sonar.api.notifications.NotificationDispatcher; + +public class ChangesInReviewAssignedToMeTest { + + private NotificationDispatcher.Context context; + private ChangesInReviewAssignedToMe dispatcher; + + @Before + public void setUp() { + context = mock(NotificationDispatcher.Context.class); + dispatcher = new ChangesInReviewAssignedToMe(); + } + + @Test + public void dispatchToOldAndNewAssignee() { + Notification notification = new Notification("review-assignee-changed") + .setFieldValue("author", "freddy") + .setFieldValue("old.assignee", "godin") + .setFieldValue("assignee", "simon"); + + dispatcher.dispatch(notification, context); + + verify(context).addUser("godin"); + verify(context).addUser("simon"); + verifyNoMoreInteractions(context); + } + + @Test + public void doNotDispatchToAuthorOfChanges() { + Notification notification = new Notification("review-assignee-changed") + .setFieldValue("author", "simon") + .setFieldValue("old.assignee", "simon") + .setFieldValue("assignee", "godin"); + + dispatcher.dispatch(notification, context); + + verify(context).addUser("godin"); + verifyNoMoreInteractions(context); + } + + @Test + public void shouldNotDispatch() { + Notification notification = new Notification("other"); + + dispatcher.dispatch(notification, context); + + verifyNoMoreInteractions(context); + } + +} diff --git a/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/reviews/ChangesInReviewCreatedByMeTest.java b/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/reviews/ChangesInReviewCreatedByMeTest.java new file mode 100644 index 00000000000..3f3142ccced --- /dev/null +++ b/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/reviews/ChangesInReviewCreatedByMeTest.java @@ -0,0 +1,74 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.emailnotifications.reviews; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.notifications.Notification; +import org.sonar.api.notifications.NotificationDispatcher; + +public class ChangesInReviewCreatedByMeTest { + + private NotificationDispatcher.Context context; + private ChangesInReviewCreatedByMe dispatcher; + + @Before + public void setUp() { + context = mock(NotificationDispatcher.Context.class); + dispatcher = new ChangesInReviewCreatedByMe(); + } + + @Test + public void dispatchToCreator() { + Notification notification = new Notification("review-comment-added") + .setFieldValue("author", "godin") + .setFieldValue("creator", "simon"); + + dispatcher.dispatch(notification, context); + + verify(context).addUser("simon"); + verifyNoMoreInteractions(context); + } + + @Test + public void doNotDispatchToAuthorOfChanges() { + Notification notification = new Notification("review-comment-added") + .setFieldValue("author", "simon") + .setFieldValue("creator", "simon"); + + dispatcher.dispatch(notification, context); + + verifyNoMoreInteractions(context); + } + + @Test + public void shouldNotDispatch() { + Notification notification = new Notification("other"); + + dispatcher.dispatch(notification, context); + + verifyNoMoreInteractions(context); + } + +} diff --git a/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/reviews/ReviewEmailTemplateTest.java b/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/reviews/ReviewEmailTemplateTest.java new file mode 100644 index 00000000000..70fca60f6b8 --- /dev/null +++ b/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/reviews/ReviewEmailTemplateTest.java @@ -0,0 +1,330 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.emailnotifications.reviews; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.database.model.User; +import org.sonar.api.notifications.Notification; +import org.sonar.api.security.UserFinder; +import org.sonar.plugins.emailnotifications.EmailConfiguration; +import org.sonar.plugins.emailnotifications.api.EmailMessage; + +public class ReviewEmailTemplateTest { + + private ReviewEmailTemplate template; + + @Before + public void setUp() { + EmailConfiguration configuration = mock(EmailConfiguration.class); + when(configuration.getServerBaseURL()).thenReturn("http://nemo.sonarsource.org"); + UserFinder userFinder = mock(UserFinder.class); + when(userFinder.findByLogin(eq("freddy.mallet"))).thenReturn(new User().setName("Freddy Mallet")); + when(userFinder.findByLogin(eq("simon.brandhof"))).thenReturn(new User().setName("Simon Brandhof")); + when(userFinder.findByLogin(eq("evgeny.mandrikov"))).thenReturn(new User().setName("Evgeny Mandrikov")); + template = new ReviewEmailTemplate(configuration, userFinder); + } + + /** + * <pre> + * Subject: Review #1 + * From: Freddy Mallet + * + * Comment: + * This is my first comment + * + * -- + * See it in Sonar: http://nemo.sonarsource.org/review/view/1 + * </pre> + */ + @Test + public void shouldFormatCommentAdded() { + Notification notification = new Notification("review-changed") + .setFieldValue("reviewId", "1") + .setFieldValue("author", "freddy.mallet") + .setFieldValue("old.comment", null) + .setFieldValue("new.comment", "This is my first comment"); + EmailMessage message = template.format(notification); + assertThat(message.getMessageId(), is("review/1")); + assertThat(message.getSubject(), is("Review #1")); + assertThat(message.getFrom(), is("Freddy Mallet")); + assertThat(message.getMessage(), is("Comment:\n This is my first comment\n\n--\nSee it in Sonar: http://nemo.sonarsource.org/review/view/1\n")); + } + + /** + * <pre> + * Subject: Review #1 + * From: Freddy Mallet + * + * Comment: + * This is another comment + * Was: + * This is my first comment + * + * -- + * See it in Sonar: http://nemo.sonarsource.org/review/view/1 + * </pre> + */ + @Test + public void shouldFormatCommentEdited() { + Notification notification = new Notification("review-changed") + .setFieldValue("reviewId", "1") + .setFieldValue("author", "freddy.mallet") + .setFieldValue("old.comment", "This is my first comment") + .setFieldValue("new.comment", "This is another comment"); + EmailMessage message = template.format(notification); + assertThat(message.getMessageId(), is("review/1")); + assertThat(message.getSubject(), is("Review #1")); + assertThat(message.getFrom(), is("Freddy Mallet")); + assertThat(message.getMessage(), is("Comment:\n This is another comment\nWas:\n This is my first comment\n\n--\nSee it in Sonar: http://nemo.sonarsource.org/review/view/1\n")); + } + + /** + * <pre> + * Subject: Review #1 + * From: Freddy Mallet + * + * Comment deleted, was: + * This is deleted comment + * + * -- + * See it in Sonar: http://nemo.sonarsource.org/review/view/1 + * </pre> + */ + @Test + public void shouldFormatCommentDeleted() { + Notification notification = new Notification("review-changed") + .setFieldValue("reviewId", "1") + .setFieldValue("old.comment", "This is deleted comment") + .setFieldValue("new.comment", null) + .setFieldValue("author", "freddy.mallet"); + EmailMessage message = template.format(notification); + assertThat(message.getMessageId(), is("review/1")); + assertThat(message.getSubject(), is("Review #1")); + assertThat(message.getFrom(), is("Freddy Mallet")); + assertThat(message.getMessage(), is("Comment deleted, was:\n This is deleted comment\n\n--\nSee it in Sonar: http://nemo.sonarsource.org/review/view/1\n")); + } + + /** + * <pre> + * Subject: Review #1 + * From: Freddy Mallet + * + * Assignee: Evgeny Mandrikov + * + * -- + * See it in Sonar: http://nemo.sonarsource.org/review/view/1 + * </pre> + */ + @Test + public void shouldFormatAssigneed() { + Notification notification = new Notification("review-changed") + .setFieldValue("reviewId", "1") + .setFieldValue("author", "freddy.mallet") + .setFieldValue("old.assignee", null) + .setFieldValue("new.assignee", "evgeny.mandrikov"); + EmailMessage message = template.format(notification); + assertThat(message.getMessageId(), is("review/1")); + assertThat(message.getSubject(), is("Review #1")); + assertThat(message.getFrom(), is("Freddy Mallet")); + assertThat(message.getMessage(), is("Assignee: Evgeny Mandrikov\n\n--\nSee it in Sonar: http://nemo.sonarsource.org/review/view/1\n")); + } + + /** + * <pre> + * Subject: Review #1 + * From: Freddy Mallet + * + * Assignee: Simon Brandhof (was Evgeny Mandrikov) + * + * -- + * See it in Sonar: http://nemo.sonarsource.org/review/view/1 + * </pre> + */ + @Test + public void shouldFormatAssigneedToAnotherPerson() { + Notification notification = new Notification("review-changed") + .setFieldValue("reviewId", "1") + .setFieldValue("author", "freddy.mallet") + .setFieldValue("old.assignee", "evgeny.mandrikov") + .setFieldValue("new.assignee", "simon.brandhof"); + EmailMessage message = template.format(notification); + assertThat(message.getMessageId(), is("review/1")); + assertThat(message.getSubject(), is("Review #1")); + assertThat(message.getFrom(), is("Freddy Mallet")); + assertThat(message.getMessage(), is("Assignee: Simon Brandhof (was Evgeny Mandrikov)\n\n--\nSee it in Sonar: http://nemo.sonarsource.org/review/view/1\n")); + } + + /** + * <pre> + * Subject: Review #1 + * From: Freddy Mallet + * + * Assignee: (was Simon Brandhof) + * + * -- + * See it in Sonar: http://nemo.sonarsource.org/review/view/1 + * </pre> + */ + @Test + public void shouldFormatUnassigned() { + Notification notification = new Notification("review-changed") + .setFieldValue("reviewId", "1") + .setFieldValue("author", "freddy.mallet") + .setFieldValue("old.assignee", "simon.brandhof") + .setFieldValue("new.assignee", null); + EmailMessage message = template.format(notification); + assertThat(message.getMessageId(), is("review/1")); + assertThat(message.getSubject(), is("Review #1")); + assertThat(message.getFrom(), is("Freddy Mallet")); + assertThat(message.getMessage(), is("Assignee: (was Simon Brandhof)\n\n--\nSee it in Sonar: http://nemo.sonarsource.org/review/view/1\n")); + } + + /** + * <pre> + * Subject: Review #1 + * From: Sonar + * + * Status: CLOSED (was OPEN) + * + * -- + * See it in Sonar: http://nemo.sonarsource.org/review/view/1 + * </pre> + */ + @Test + public void shouldFormatClosed() { + Notification notification = new Notification("review-changed") + .setFieldValue("reviewId", "1") + .setFieldValue("old.status", "OPEN") + .setFieldValue("new.status", "CLOSED"); + EmailMessage message = template.format(notification); + assertThat(message.getMessageId(), is("review/1")); + assertThat(message.getSubject(), is("Review #1")); + assertThat(message.getFrom(), nullValue()); + assertThat(message.getMessage(), is("Status: CLOSED (was OPEN)\n\n--\nSee it in Sonar: http://nemo.sonarsource.org/review/view/1\n")); + } + + /** + * <pre> + * Subject: Review #1 + * From: Simon Brandhof + * + * Status: REOPENED (was RESOLVED) + * Resolution: (was FIXED) + * + * -- + * See it in Sonar: http://nemo.sonarsource.org/review/view/1 + * </pre> + */ + @Test + public void shouldFormatReopened() { + Notification notification = new Notification("review-changed") + .setFieldValue("reviewId", "1") + .setFieldValue("old.resolution", "FIXED") + .setFieldValue("new.resolution", null) + .setFieldValue("old.status", "RESOLVED") + .setFieldValue("new.status", "REOPENED"); + EmailMessage message = template.format(notification); + assertThat(message.getMessageId(), is("review/1")); + assertThat(message.getSubject(), is("Review #1")); + assertThat(message.getFrom(), nullValue()); + assertThat(message.getMessage(), is("Status: REOPENED (was RESOLVED)\nResolution: (was FIXED)\n\n--\nSee it in Sonar: http://nemo.sonarsource.org/review/view/1\n")); + } + + /** + * <pre> + * Subject: Review #1 + * From: Simon Brandhof + * + * Status: RESOLVED (was OPEN) + * Resolution: FIXED + * + * -- + * See it in Sonar: http://nemo.sonarsource.org/review/view/1 + * </pre> + */ + @Test + public void shouldFormatResolvedAsFixed() { + Notification notification = new Notification("review-changed") + .setFieldValue("reviewId", "1") + .setFieldValue("author", "simon.brandhof") + .setFieldValue("old.status", "OPEN") + .setFieldValue("old.resolution", null) + .setFieldValue("new.status", "RESOLVED") + .setFieldValue("new.resolution", "FIXED"); + EmailMessage message = template.format(notification); + assertThat(message.getMessageId(), is("review/1")); + assertThat(message.getSubject(), is("Review #1")); + assertThat(message.getFrom(), is("Simon Brandhof")); + assertThat(message.getMessage(), is("Status: RESOLVED (was OPEN)\nResolution: FIXED\n\n--\nSee it in Sonar: http://nemo.sonarsource.org/review/view/1\n")); + } + + /** + * <pre> + * Subject: Review #1 + * From: Simon Brandhof + * + * Status: RESOLVED (was REOPENED) + * Resolution: FALSE-POSITIVE + * Comment: + * Because! + * + * -- + * See it in Sonar: http://nemo.sonarsource.org/review/view/1 + * </pre> + */ + @Test + public void shouldFormatResolvedAsFalsePositive() { + Notification notification = new Notification("review-changed") + .setFieldValue("reviewId", "1") + .setFieldValue("author", "freddy.mallet") + .setFieldValue("old.status", "REOPENED") + .setFieldValue("old.resolution", null) + .setFieldValue("new.status", "RESOLVED") + .setFieldValue("new.resolution", "FALSE-POSITIVE") + .setFieldValue("new.comment", "Because!"); + EmailMessage message = template.format(notification); + assertThat(message.getMessageId(), is("review/1")); + assertThat(message.getSubject(), is("Review #1")); + assertThat(message.getFrom(), is("Freddy Mallet")); + assertThat(message.getMessage(), is("Status: RESOLVED (was REOPENED)\nResolution: FALSE-POSITIVE\nComment:\n Because!\n\n--\nSee it in Sonar: http://nemo.sonarsource.org/review/view/1\n")); + } + + @Test + public void shouldNotFormat() { + Notification notification = new Notification("other"); + EmailMessage message = template.format(notification); + assertThat(message, nullValue()); + } + + @Test + public void shouldReturnFullNameOrLogin() { + assertThat(template.getUserFullName("freddy.mallet"), is("Freddy Mallet")); + assertThat(template.getUserFullName("deleted"), is("deleted")); + } + +} |