mirror of
https://github.com/google/nomulus.git
synced 2025-06-29 07:43:37 +02:00
Refactor common email sending utility
The main thrust of this is to create a common POJO that contains email content in a simple way, then have one class that converts that to an email and sends it. Any class that uses email should only have to deal with creating that POJO. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=237883643
This commit is contained in:
parent
9823ee7fcf
commit
50e0a9b532
35 changed files with 773 additions and 614 deletions
|
@ -15,10 +15,8 @@
|
|||
package google.registry.reporting.spec11;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static google.registry.reporting.spec11.Spec11RegistrarThreatMatchesParserTest.sampleThreatMatches;
|
||||
import static google.registry.testing.JUnitBackports.assertThrows;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
|
@ -26,63 +24,47 @@ import static org.mockito.Mockito.verify;
|
|||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.reporting.spec11.soy.Spec11EmailSoyInfo;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeSleeper;
|
||||
import google.registry.util.Retrier;
|
||||
import google.registry.util.EmailMessage;
|
||||
import google.registry.util.SendEmailService;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.Message.RecipientType;
|
||||
import java.util.Optional;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
/** Unit tests for {@link Spec11EmailUtils}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class Spec11EmailUtilsTest {
|
||||
|
||||
private static final int RETRY_COUNT = 2;
|
||||
private static final ImmutableList<String> FAKE_RESOURCES = ImmutableList.of("foo");
|
||||
|
||||
private SendEmailService emailService;
|
||||
private Spec11EmailUtils emailUtils;
|
||||
private Spec11RegistrarThreatMatchesParser parser;
|
||||
private ArgumentCaptor<Message> gotMessage;
|
||||
private ArgumentCaptor<EmailMessage> contentCaptor;
|
||||
private final LocalDate date = new LocalDate(2018, 7, 15);
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
emailService = mock(SendEmailService.class);
|
||||
when(emailService.createMessage())
|
||||
.thenAnswer((args) -> new MimeMessage(Session.getInstance(new Properties(), null)));
|
||||
|
||||
parser = mock(Spec11RegistrarThreatMatchesParser.class);
|
||||
when(parser.getRegistrarThreatMatches(date)).thenReturn(sampleThreatMatches());
|
||||
|
||||
gotMessage = ArgumentCaptor.forClass(Message.class);
|
||||
|
||||
contentCaptor = ArgumentCaptor.forClass(EmailMessage.class);
|
||||
emailUtils =
|
||||
new Spec11EmailUtils(
|
||||
emailService,
|
||||
"my-sender@test.com",
|
||||
"my-receiver@test.com",
|
||||
"my-reply-to@test.com",
|
||||
new InternetAddress("my-sender@test.com"),
|
||||
new InternetAddress("my-receiver@test.com"),
|
||||
new InternetAddress("my-reply-to@test.com"),
|
||||
FAKE_RESOURCES,
|
||||
"Super Cool Registry",
|
||||
new Retrier(new FakeSleeper(new FakeClock()), RETRY_COUNT));
|
||||
"Super Cool Registry");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -93,8 +75,8 @@ public class Spec11EmailUtilsTest {
|
|||
"Super Cool Registry Monthly Threat Detector [2018-07-15]",
|
||||
sampleThreatMatches());
|
||||
// We inspect individual parameters because Message doesn't implement equals().
|
||||
verify(emailService, times(3)).sendMessage(gotMessage.capture());
|
||||
List<Message> capturedMessages = gotMessage.getAllValues();
|
||||
verify(emailService, times(3)).sendEmail(contentCaptor.capture());
|
||||
List<EmailMessage> capturedContents = contentCaptor.getAllValues();
|
||||
String emailFormat =
|
||||
"Dear registrar partner,<p>Super Cool Registry previously notified you when the following "
|
||||
+ "domains managed by your registrar were flagged for potential security concerns."
|
||||
|
@ -113,31 +95,31 @@ public class Spec11EmailUtilsTest {
|
|||
+ "uestions regarding this notice, please contact my-reply-to@test.com.</p>";
|
||||
|
||||
validateMessage(
|
||||
capturedMessages.get(0),
|
||||
capturedContents.get(0),
|
||||
"my-sender@test.com",
|
||||
"a@fake.com",
|
||||
"my-reply-to@test.com",
|
||||
Optional.of("my-reply-to@test.com"),
|
||||
"Super Cool Registry Monthly Threat Detector [2018-07-15]",
|
||||
String.format(emailFormat, "<tr><td>a.com</td><td>MALWARE</td></tr>"),
|
||||
"text/html");
|
||||
Optional.of(MediaType.HTML_UTF_8));
|
||||
validateMessage(
|
||||
capturedMessages.get(1),
|
||||
capturedContents.get(1),
|
||||
"my-sender@test.com",
|
||||
"b@fake.com",
|
||||
"my-reply-to@test.com",
|
||||
Optional.of("my-reply-to@test.com"),
|
||||
"Super Cool Registry Monthly Threat Detector [2018-07-15]",
|
||||
String.format(
|
||||
emailFormat,
|
||||
"<tr><td>b.com</td><td>MALWARE</td></tr><tr><td>c.com</td><td>MALWARE</td></tr>"),
|
||||
"text/html");
|
||||
Optional.of(MediaType.HTML_UTF_8));
|
||||
validateMessage(
|
||||
capturedMessages.get(2),
|
||||
capturedContents.get(2),
|
||||
"my-sender@test.com",
|
||||
"my-receiver@test.com",
|
||||
null,
|
||||
Optional.empty(),
|
||||
"Spec11 Pipeline Success 2018-07-15",
|
||||
"Spec11 reporting completed successfully.",
|
||||
"text/plain");
|
||||
Optional.empty());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -148,8 +130,8 @@ public class Spec11EmailUtilsTest {
|
|||
"Super Cool Registry Daily Threat Detector [2018-07-15]",
|
||||
sampleThreatMatches());
|
||||
// We inspect individual parameters because Message doesn't implement equals().
|
||||
verify(emailService, times(3)).sendMessage(gotMessage.capture());
|
||||
List<Message> capturedMessages = gotMessage.getAllValues();
|
||||
verify(emailService, times(3)).sendEmail(contentCaptor.capture());
|
||||
List<EmailMessage> capturedMessages = contentCaptor.getAllValues();
|
||||
String emailFormat =
|
||||
"Dear registrar partner,<p>"
|
||||
+ "Super Cool Registry conducts a daily analysis of all domains registered in its TLDs "
|
||||
|
@ -172,54 +154,36 @@ public class Spec11EmailUtilsTest {
|
|||
capturedMessages.get(0),
|
||||
"my-sender@test.com",
|
||||
"a@fake.com",
|
||||
"my-reply-to@test.com",
|
||||
Optional.of("my-reply-to@test.com"),
|
||||
"Super Cool Registry Daily Threat Detector [2018-07-15]",
|
||||
String.format(emailFormat, "<tr><td>a.com</td><td>MALWARE</td></tr>"),
|
||||
"text/html");
|
||||
Optional.of(MediaType.HTML_UTF_8));
|
||||
validateMessage(
|
||||
capturedMessages.get(1),
|
||||
"my-sender@test.com",
|
||||
"b@fake.com",
|
||||
"my-reply-to@test.com",
|
||||
Optional.of("my-reply-to@test.com"),
|
||||
"Super Cool Registry Daily Threat Detector [2018-07-15]",
|
||||
String.format(
|
||||
emailFormat,
|
||||
"<tr><td>b.com</td><td>MALWARE</td></tr><tr><td>c.com</td><td>MALWARE</td></tr>"),
|
||||
"text/html");
|
||||
Optional.of(MediaType.HTML_UTF_8));
|
||||
validateMessage(
|
||||
capturedMessages.get(2),
|
||||
"my-sender@test.com",
|
||||
"my-receiver@test.com",
|
||||
null,
|
||||
Optional.empty(),
|
||||
"Spec11 Pipeline Success 2018-07-15",
|
||||
"Spec11 reporting completed successfully.",
|
||||
"text/plain");
|
||||
Optional.empty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_tooManyRetries_emailsAlert() throws MessagingException, IOException {
|
||||
Message throwingMessage = mock(Message.class);
|
||||
doThrow(new MessagingException("expected")).when(throwingMessage).setSubject(any(String.class));
|
||||
// Only return the throwingMessage enough times to force failure. The last invocation will
|
||||
// be for the alert e-mail we're looking to verify.
|
||||
when(emailService.createMessage())
|
||||
.thenAnswer(
|
||||
new Answer<Message>() {
|
||||
private int count = 0;
|
||||
|
||||
@Override
|
||||
public Message answer(InvocationOnMock invocation) {
|
||||
if (count < RETRY_COUNT) {
|
||||
count++;
|
||||
return throwingMessage;
|
||||
} else if (count == RETRY_COUNT) {
|
||||
return new MimeMessage(Session.getDefaultInstance(new Properties(), null));
|
||||
} else {
|
||||
assertWithMessage("Attempted to generate too many messages!").fail();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
public void testFailure_emailsAlert() throws MessagingException {
|
||||
doThrow(new RuntimeException(new MessagingException("expected")))
|
||||
.doNothing()
|
||||
.when(emailService)
|
||||
.sendEmail(contentCaptor.capture());
|
||||
RuntimeException thrown =
|
||||
assertThrows(
|
||||
RuntimeException.class,
|
||||
|
@ -231,57 +195,52 @@ public class Spec11EmailUtilsTest {
|
|||
.hasCauseThat()
|
||||
.hasMessageThat()
|
||||
.isEqualTo("javax.mail.MessagingException: expected");
|
||||
// We should have created RETRY_COUNT failing messages and one final alert message
|
||||
verify(emailService, times(RETRY_COUNT + 1)).createMessage();
|
||||
// Verify we sent an e-mail alert
|
||||
verify(emailService).sendMessage(gotMessage.capture());
|
||||
verify(emailService, times(2)).sendEmail(contentCaptor.capture());
|
||||
validateMessage(
|
||||
gotMessage.getValue(),
|
||||
contentCaptor.getValue(),
|
||||
"my-sender@test.com",
|
||||
"my-receiver@test.com",
|
||||
null,
|
||||
Optional.empty(),
|
||||
"Spec11 Emailing Failure 2018-07-15",
|
||||
"Emailing spec11 reports failed due to expected",
|
||||
"text/plain");
|
||||
Optional.empty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_sendAlertEmail() throws MessagingException, IOException {
|
||||
public void testSuccess_sendAlertEmail() throws MessagingException {
|
||||
emailUtils.sendAlertEmail("Spec11 Pipeline Alert: 2018-07", "Alert!");
|
||||
verify(emailService).sendMessage(gotMessage.capture());
|
||||
verify(emailService).sendEmail(contentCaptor.capture());
|
||||
validateMessage(
|
||||
gotMessage.getValue(),
|
||||
contentCaptor.getValue(),
|
||||
"my-sender@test.com",
|
||||
"my-receiver@test.com",
|
||||
null,
|
||||
Optional.empty(),
|
||||
"Spec11 Pipeline Alert: 2018-07",
|
||||
"Alert!",
|
||||
"text/plain");
|
||||
Optional.empty());
|
||||
}
|
||||
|
||||
private void validateMessage(
|
||||
Message message,
|
||||
EmailMessage message,
|
||||
String from,
|
||||
String recipient,
|
||||
@Nullable String replyTo,
|
||||
Optional<String> replyTo,
|
||||
String subject,
|
||||
String body,
|
||||
String contentType)
|
||||
throws MessagingException, IOException {
|
||||
assertThat(message.getFrom()).asList().containsExactly(new InternetAddress(from));
|
||||
assertThat(message.getRecipients(RecipientType.TO))
|
||||
.asList()
|
||||
.containsExactly(new InternetAddress(recipient));
|
||||
if (replyTo == null) {
|
||||
assertThat(message.getRecipients(RecipientType.BCC)).isNull();
|
||||
} else {
|
||||
assertThat(message.getRecipients(RecipientType.BCC))
|
||||
.asList()
|
||||
.containsExactly(new InternetAddress(replyTo));
|
||||
Optional<MediaType> contentType)
|
||||
throws MessagingException {
|
||||
EmailMessage.Builder expectedContentBuilder =
|
||||
EmailMessage.newBuilder()
|
||||
.setFrom(new InternetAddress(from))
|
||||
.addRecipient(new InternetAddress(recipient))
|
||||
.setSubject(subject)
|
||||
.setBody(body);
|
||||
|
||||
if (replyTo.isPresent()) {
|
||||
expectedContentBuilder.setBcc(new InternetAddress(replyTo.get()));
|
||||
}
|
||||
assertThat(message.getRecipients(RecipientType.CC)).isNull();
|
||||
assertThat(message.getSubject()).isEqualTo(subject);
|
||||
assertThat(message.getContentType()).isEqualTo(contentType);
|
||||
assertThat(message.getContent()).isEqualTo(body);
|
||||
contentType.ifPresent(expectedContentBuilder::setContentType);
|
||||
assertThat(message).isEqualTo(expectedContentBuilder.build());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue