diff --git a/java/google/registry/reporting/spec11/PublishSpec11ReportAction.java b/java/google/registry/reporting/spec11/PublishSpec11ReportAction.java
index 82e2ee64b..7a7870062 100644
--- a/java/google/registry/reporting/spec11/PublishSpec11ReportAction.java
+++ b/java/google/registry/reporting/spec11/PublishSpec11ReportAction.java
@@ -22,6 +22,7 @@ import static javax.servlet.http.HttpServletResponse.SC_OK;
import com.google.api.services.dataflow.Dataflow;
import com.google.api.services.dataflow.model.Job;
+import com.google.common.collect.ImmutableList;
import com.google.common.flogger.FluentLogger;
import com.google.common.net.MediaType;
import google.registry.config.RegistryConfig.Config;
@@ -31,15 +32,17 @@ import google.registry.request.Parameter;
import google.registry.request.Response;
import google.registry.request.auth.Auth;
import java.io.IOException;
+import java.util.List;
import javax.inject.Inject;
import org.joda.time.LocalDate;
+import org.json.JSONException;
/**
* Retries until a {@code Dataflow} job with a given {@code jobId} completes, continuing the Spec11
* pipeline accordingly.
*
- *
This calls {@link Spec11EmailUtils#emailSpec11Reports()} on success or {@link
- * Spec11EmailUtils#sendAlertEmail(String, String)} on failure.
+ *
This calls {@link Spec11EmailUtils#emailSpec11Reports(String, String, List)} ()} on success or
+ * {@link Spec11EmailUtils#sendAlertEmail(String, String)} on failure.
*/
@Action(path = PublishSpec11ReportAction.PATH, method = POST, auth = Auth.AUTH_INTERNAL_OR_ADMIN)
public class PublishSpec11ReportAction implements Runnable {
@@ -51,8 +54,10 @@ public class PublishSpec11ReportAction implements Runnable {
private static final String JOB_FAILED = "JOB_STATE_FAILED";
private final String projectId;
+ private final String spec11EmailBodyTemplate;
private final String jobId;
private final Spec11EmailUtils emailUtils;
+ private final Spec11RegistrarThreatMatchesParser spec11RegistrarThreatMatchesParser;
private final Dataflow dataflow;
private final Response response;
private final LocalDate date;
@@ -60,14 +65,18 @@ public class PublishSpec11ReportAction implements Runnable {
@Inject
PublishSpec11ReportAction(
@Config("projectId") String projectId,
+ @Config("spec11EmailBodyTemplate") String spec11EmailBodyTemplate,
@Parameter(ReportingModule.PARAM_JOB_ID) String jobId,
Spec11EmailUtils emailUtils,
+ Spec11RegistrarThreatMatchesParser spec11RegistrarThreatMatchesParser,
Dataflow dataflow,
Response response,
LocalDate date) {
this.projectId = projectId;
+ this.spec11EmailBodyTemplate = spec11EmailBodyTemplate;
this.jobId = jobId;
this.emailUtils = emailUtils;
+ this.spec11RegistrarThreatMatchesParser = spec11RegistrarThreatMatchesParser;
this.dataflow = dataflow;
this.response = response;
this.date = date;
@@ -85,7 +94,10 @@ public class PublishSpec11ReportAction implements Runnable {
"Dataflow job %s finished successfully, publishing results if appropriate.", jobId);
response.setStatus(SC_OK);
if (shouldSendSpec11Email()) {
- emailUtils.emailSpec11Reports();
+ ImmutableList matchesList =
+ spec11RegistrarThreatMatchesParser.getRegistrarThreatMatches();
+ String subject = String.format("Google Registry Monthly Threat Detector [%s]", date);
+ emailUtils.emailSpec11Reports(spec11EmailBodyTemplate, subject, matchesList);
}
break;
case JOB_FAILED:
@@ -100,7 +112,7 @@ public class PublishSpec11ReportAction implements Runnable {
response.setStatus(SC_NOT_MODIFIED);
break;
}
- } catch (IOException e) {
+ } catch (IOException | JSONException e) {
logger.atSevere().withCause(e).log("Failed to publish Spec11 reports.");
emailUtils.sendAlertEmail(
String.format("Spec11 Publish Failure %s", date),
diff --git a/java/google/registry/reporting/spec11/Spec11EmailUtils.java b/java/google/registry/reporting/spec11/Spec11EmailUtils.java
index 1661efc93..7b54068e3 100644
--- a/java/google/registry/reporting/spec11/Spec11EmailUtils.java
+++ b/java/google/registry/reporting/spec11/Spec11EmailUtils.java
@@ -16,63 +16,58 @@ package google.registry.reporting.spec11;
import static com.google.common.base.Throwables.getRootCause;
-import com.google.common.collect.ImmutableList;
import google.registry.beam.spec11.ThreatMatch;
import google.registry.config.RegistryConfig.Config;
import google.registry.util.Retrier;
import google.registry.util.SendEmailService;
import java.io.IOException;
+import java.util.List;
import javax.inject.Inject;
import javax.mail.Message;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.internet.InternetAddress;
-import org.joda.time.YearMonth;
+import org.joda.time.LocalDate;
/** Provides e-mail functionality for Spec11 tasks, such as sending Spec11 reports to registrars. */
public class Spec11EmailUtils {
private final SendEmailService emailService;
- private final YearMonth yearMonth;
+ private final LocalDate date;
private final String outgoingEmailAddress;
private final String alertRecipientAddress;
private final String spec11ReplyToAddress;
- private final String spec11EmailBodyTemplate;
- private final Spec11RegistrarThreatMatchesParser spec11RegistrarThreatMatchesParser;
private final Retrier retrier;
@Inject
Spec11EmailUtils(
SendEmailService emailService,
- YearMonth yearMonth,
+ LocalDate date,
@Config("gSuiteOutgoingEmailAddress") String outgoingEmailAddress,
@Config("alertRecipientEmailAddress") String alertRecipientAddress,
@Config("spec11ReplyToEmailAddress") String spec11ReplyToAddress,
- @Config("spec11EmailBodyTemplate") String spec11EmailBodyTemplate,
- Spec11RegistrarThreatMatchesParser spec11RegistrarThreatMatchesParser,
Retrier retrier) {
this.emailService = emailService;
- this.yearMonth = yearMonth;
+ this.date = date;
this.outgoingEmailAddress = outgoingEmailAddress;
this.alertRecipientAddress = alertRecipientAddress;
this.spec11ReplyToAddress = spec11ReplyToAddress;
- this.spec11RegistrarThreatMatchesParser = spec11RegistrarThreatMatchesParser;
- this.spec11EmailBodyTemplate = spec11EmailBodyTemplate;
this.retrier = retrier;
}
/**
- * Processes a Spec11 report on GCS for a given month and e-mails registrars based on the
- * contents.
+ * Processes a list of registrar/list-of-threat pairings and sends a notification email to the
+ * appropriate address.
*/
- void emailSpec11Reports() {
+ void emailSpec11Reports(
+ String spec11EmailBodyTemplate,
+ String subject,
+ List registrarThreatMatchesList) {
try {
retrier.callWithRetry(
() -> {
- ImmutableList registrarThreatMatchesList =
- spec11RegistrarThreatMatchesParser.getRegistrarThreatMatches();
for (RegistrarThreatMatches registrarThreatMatches : registrarThreatMatchesList) {
- emailRegistrar(registrarThreatMatches);
+ emailRegistrar(spec11EmailBodyTemplate, subject, registrarThreatMatches);
}
},
IOException.class,
@@ -80,16 +75,17 @@ public class Spec11EmailUtils {
} catch (Throwable e) {
// Send an alert with the root cause, unwrapping the retrier's RuntimeException
sendAlertEmail(
- String.format("Spec11 Emailing Failure %s", yearMonth.toString()),
+ String.format("Spec11 Emailing Failure %s", date),
String.format("Emailing spec11 reports failed due to %s", getRootCause(e).getMessage()));
throw new RuntimeException("Emailing spec11 report failed", e);
}
sendAlertEmail(
- String.format("Spec11 Pipeline Success %s", yearMonth.toString()),
+ String.format("Spec11 Pipeline Success %s", date),
"Spec11 reporting completed successfully.");
}
- private void emailRegistrar(RegistrarThreatMatches registrarThreatMatches)
+ private void emailRegistrar(
+ String spec11EmailBodyTemplate, String subject, RegistrarThreatMatches registrarThreatMatches)
throws MessagingException {
String registrarEmail = registrarThreatMatches.registrarEmailAddress();
StringBuilder threatList = new StringBuilder();
@@ -103,8 +99,7 @@ public class Spec11EmailUtils {
.replace("{REPLY_TO_EMAIL}", spec11ReplyToAddress)
.replace("{LIST_OF_THREATS}", threatList.toString());
Message msg = emailService.createMessage();
- msg.setSubject(
- String.format("Google Registry Monthly Threat Detector [%s]", yearMonth.toString()));
+ msg.setSubject(subject);
msg.setText(body);
msg.setFrom(new InternetAddress(outgoingEmailAddress));
msg.addRecipient(RecipientType.TO, new InternetAddress(registrarEmail));
diff --git a/javatests/google/registry/reporting/spec11/PublishSpec11ReportActionTest.java b/javatests/google/registry/reporting/spec11/PublishSpec11ReportActionTest.java
index b2a7ba5ad..3a60f3b6e 100644
--- a/javatests/google/registry/reporting/spec11/PublishSpec11ReportActionTest.java
+++ b/javatests/google/registry/reporting/spec11/PublishSpec11ReportActionTest.java
@@ -15,6 +15,7 @@
package google.registry.reporting.spec11;
import static com.google.common.truth.Truth.assertThat;
+import static google.registry.reporting.spec11.Spec11RegistrarThreatMatchesParserTest.sampleThreatMatches;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import static javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED;
import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
@@ -42,18 +43,22 @@ import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class PublishSpec11ReportActionTest {
+ private final String spec11BodyTemplate = "{LIST_OF_THREATS}\n{REPLY_TO_EMAIL}";
+ private final LocalDate date = new LocalDate(2018, 6, 5);
+
private Dataflow dataflow;
private Projects projects;
private Jobs jobs;
private Get get;
private Spec11EmailUtils emailUtils;
+ private Spec11RegistrarThreatMatchesParser parser;
private Job expectedJob;
private FakeResponse response;
private PublishSpec11ReportAction publishAction;
@Before
- public void setUp() throws IOException {
+ public void setUp() throws Exception {
dataflow = mock(Dataflow.class);
projects = mock(Projects.class);
jobs = mock(Jobs.class);
@@ -65,20 +70,40 @@ public class PublishSpec11ReportActionTest {
when(get.execute()).thenReturn(expectedJob);
emailUtils = mock(Spec11EmailUtils.class);
response = new FakeResponse();
+ parser = mock(Spec11RegistrarThreatMatchesParser.class);
+ when(parser.getRegistrarThreatMatches()).thenReturn(sampleThreatMatches());
publishAction =
new PublishSpec11ReportAction(
- "test-project", "12345", emailUtils, dataflow, response, new LocalDate(2018, 6, 5));
+ "test-project",
+ spec11BodyTemplate,
+ "12345",
+ emailUtils,
+ mock(Spec11RegistrarThreatMatchesParser.class),
+ dataflow,
+ response,
+ date);
}
@Test
- public void testJobDone_emailsResultsOnSecondOfMonth() {
+ public void testJobDone_emailsResultsOnSecondOfMonth() throws Exception {
expectedJob.setCurrentState("JOB_STATE_DONE");
publishAction =
new PublishSpec11ReportAction(
- "test-project", "12345", emailUtils, dataflow, response, new LocalDate(2018, 6, 2));
+ "test-project",
+ spec11BodyTemplate,
+ "12345",
+ emailUtils,
+ parser,
+ dataflow,
+ response,
+ date.withDayOfMonth(2));
publishAction.run();
assertThat(response.getStatus()).isEqualTo(SC_OK);
- verify(emailUtils).emailSpec11Reports();
+ verify(emailUtils)
+ .emailSpec11Reports(
+ spec11BodyTemplate,
+ "Google Registry Monthly Threat Detector [2018-06-02]",
+ sampleThreatMatches());
}
@Test
diff --git a/javatests/google/registry/reporting/spec11/Spec11EmailUtilsTest.java b/javatests/google/registry/reporting/spec11/Spec11EmailUtilsTest.java
index 01d09c5e8..c170e0c54 100644
--- a/javatests/google/registry/reporting/spec11/Spec11EmailUtilsTest.java
+++ b/javatests/google/registry/reporting/spec11/Spec11EmailUtilsTest.java
@@ -39,7 +39,7 @@ import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
-import org.joda.time.YearMonth;
+import org.joda.time.LocalDate;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -73,18 +73,19 @@ public class Spec11EmailUtilsTest {
emailUtils =
new Spec11EmailUtils(
emailService,
- new YearMonth(2018, 7),
+ new LocalDate(2018, 7, 15),
"my-sender@test.com",
"my-receiver@test.com",
"my-reply-to@test.com",
- "{LIST_OF_THREATS}\n{REPLY_TO_EMAIL}",
- parser,
new Retrier(new FakeSleeper(new FakeClock()), RETRY_COUNT));
}
@Test
- public void testSuccess_emailSpec11Reports() throws MessagingException, IOException {
- emailUtils.emailSpec11Reports();
+ public void testSuccess_emailSpec11Reports() throws Exception {
+ emailUtils.emailSpec11Reports(
+ "{LIST_OF_THREATS}\n{REPLY_TO_EMAIL}",
+ "Google 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 capturedMessages = gotMessage.getAllValues();
@@ -93,21 +94,21 @@ public class Spec11EmailUtilsTest {
"my-sender@test.com",
"a@fake.com",
"my-reply-to@test.com",
- "Google Registry Monthly Threat Detector [2018-07]",
+ "Google Registry Monthly Threat Detector [2018-07-15]",
"a.com - MALWARE\n\nmy-reply-to@test.com");
validateMessage(
capturedMessages.get(1),
"my-sender@test.com",
"b@fake.com",
"my-reply-to@test.com",
- "Google Registry Monthly Threat Detector [2018-07]",
+ "Google Registry Monthly Threat Detector [2018-07-15]",
"b.com - MALWARE\nc.com - MALWARE\n\nmy-reply-to@test.com");
validateMessage(
capturedMessages.get(2),
"my-sender@test.com",
"my-receiver@test.com",
null,
- "Spec11 Pipeline Success 2018-07",
+ "Spec11 Pipeline Success 2018-07-15",
"Spec11 reporting completed successfully.");
}
@@ -136,7 +137,9 @@ public class Spec11EmailUtilsTest {
}
});
RuntimeException thrown =
- assertThrows(RuntimeException.class, () -> emailUtils.emailSpec11Reports());
+ assertThrows(
+ RuntimeException.class,
+ () -> emailUtils.emailSpec11Reports("foo", "bar", sampleThreatMatches()));
assertThat(thrown).hasMessageThat().isEqualTo("Emailing spec11 report failed");
assertThat(thrown)
.hasCauseThat()
@@ -151,7 +154,7 @@ public class Spec11EmailUtilsTest {
"my-sender@test.com",
"my-receiver@test.com",
null,
- "Spec11 Emailing Failure 2018-07",
+ "Spec11 Emailing Failure 2018-07-15",
"Emailing spec11 reports failed due to expected");
}