/* * ProActive Parallel Suite(TM): * The Open Source library for parallel and distributed * Workflows & Scheduling, Orchestration, Cloud Automation * and Big Data Analysis on Enterprise Grids & Clouds. * * Copyright (c) 2007 - 2017 ActiveEon * Contact: contact@activeeon.com * * This library is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License * as published by the Free Software Foundation: version 3 of * the License. * * 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * If needed, contact us to obtain a release under GPL Version 2 or 3 * or a different license than the AGPL. */ package org.ow2.proactive.scheduler.core; import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.*; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.contains; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import java.io.Serializable; import java.security.KeyException; import java.util.Map; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.ow2.proactive.scheduler.common.NotificationData; import org.ow2.proactive.scheduler.common.SchedulerEvent; import org.ow2.proactive.scheduler.common.job.JobInfo; import org.ow2.proactive.scheduler.common.job.JobState; import org.ow2.proactive.scheduler.common.job.JobStatus; import org.ow2.proactive.scheduler.common.job.TaskFlowJob; import org.ow2.proactive.scheduler.common.task.JavaTask; import org.ow2.proactive.scheduler.common.task.TaskResult; import org.ow2.proactive.scheduler.common.task.executable.JavaExecutable; import org.ow2.proactive.scheduler.core.properties.PASchedulerProperties; import org.ow2.proactive.scheduler.job.InternalJob; import org.ow2.proactive.scheduler.job.InternalJobFactory; import org.ow2.proactive.scheduler.job.JobIdImpl; import org.ow2.proactive.scheduler.job.JobInfoImpl; import org.ow2.proactive.scheduler.util.SendMail; import org.ow2.tests.ProActiveTest; public class JobEmailNotificationTest extends ProActiveTest { public static class TestJavaTask extends JavaExecutable { @Override public Serializable execute(TaskResult... results) throws Throwable { System.out.println("OK"); return "OK"; } } private static final String ADMIN_EMAIL = "admin@example.com"; private static final String DEFAULT_USER_NAME = "admin"; private static final String INCOMPLETE_EMAIL = "foo"; private static final String JOB_NAME = "job name"; private static final String MALFORMED_EMAIL = "$@"; private static final String TASK_NAME = "task name"; private static final String USER_EMAIL = "user@example.com"; private static void disableEmailNotifications() { PASchedulerProperties.EMAIL_NOTIFICATIONS_ENABLED.updateProperty("false"); } private static void enableEmailNotifications() { PASchedulerProperties.EMAIL_NOTIFICATIONS_ENABLED.updateProperty("true"); } private static NotificationData<JobInfo> getNotification(JobState js, SchedulerEvent event) { JobInfo jobInfo = new JobInfoImpl((JobInfoImpl) js.getJobInfo()); return new NotificationData<>(event, jobInfo); } private static void setSenderAddress(String address) { PASchedulerProperties.EMAIL_NOTIFICATIONS_SENDER_ADDRESS.updateProperty(address); } private SendMail sender; private SendMail stubbedSender; private InternalJob createJob(String userEmail) throws Exception { TaskFlowJob job = new TaskFlowJob(); job.setName(JOB_NAME); if (userEmail != null) { job.addGenericInformation(JobEmailNotification.GENERIC_INFORMATION_KEY_EMAIL, userEmail); } JavaTask javaTask = new JavaTask(); javaTask.setExecutableClassName(TestJavaTask.class.getName()); javaTask.setName(TASK_NAME); job.addTask(javaTask); InternalJob internalJob = InternalJobFactory.createJob(job, null); internalJob.setOwner(DEFAULT_USER_NAME); return internalJob; } private static boolean sendNotification(JobState jobState, SchedulerEvent event, SendMail sender) throws JobEmailNotificationException { NotificationData<JobInfo> notification = getNotification(jobState, event); JobEmailNotification emailNotification = new JobEmailNotification(jobState, notification, sender); return emailNotification.doCheckAndSend(); } @Before public void setUp() throws KeyException { enableEmailNotifications(); setSenderAddress(ADMIN_EMAIL); stubbedSender = mock(SendMail.class); sender = new SendMail(); } @Test(expected = JobEmailNotificationException.class) public void testIncompleteFrom() throws Exception { setSenderAddress(INCOMPLETE_EMAIL); InternalJob job = createJob(USER_EMAIL); Map<String, String> genericInfo = job.getGenericInformation(); genericInfo.put("NOTIFICATION_EVENTS", "Job running to finished"); job.setGenericInformation(genericInfo); try { sendNotification(job, SchedulerEvent.JOB_RUNNING_TO_FINISHED, sender); } catch (JobEmailNotificationException e) { Assert.assertThat("Wrong exception message", e.getMessage(), containsString("Error sending email")); throw e; } } @Test(expected = JobEmailNotificationException.class) public void testIncompleteTo() throws Exception { InternalJob job = createJob(INCOMPLETE_EMAIL); Map<String, String> genericInfo = job.getGenericInformation(); genericInfo.put("NOTIFICATION_EVENTS", "Job running to finished"); job.setGenericInformation(genericInfo); try { sendNotification(job, SchedulerEvent.JOB_RUNNING_TO_FINISHED, sender); } catch (JobEmailNotificationException e) { Assert.assertThat("Wrong exception message", e.getMessage(), containsString("Error sending email")); throw e; } } @Test(expected = JobEmailNotificationException.class) public void testMalformedFrom() throws Exception { setSenderAddress(MALFORMED_EMAIL); InternalJob job = createJob(USER_EMAIL); Map<String, String> genericInfo = job.getGenericInformation(); genericInfo.put("NOTIFICATION_EVENTS", "Job running to finished"); job.setGenericInformation(genericInfo); try { sendNotification(job, SchedulerEvent.JOB_RUNNING_TO_FINISHED, sender); } catch (JobEmailNotificationException e) { Assert.assertThat("Wrong exception message", e.getMessage(), containsString("Error sending email")); throw e; } } @Test(expected = JobEmailNotificationException.class) public void testMalformedTo() throws Exception { InternalJob job = createJob(MALFORMED_EMAIL); Map<String, String> genericInfo = job.getGenericInformation(); genericInfo.put("NOTIFICATION_EVENTS", "Job running to finished"); job.setGenericInformation(genericInfo); try { sendNotification(job, SchedulerEvent.JOB_RUNNING_TO_FINISHED, sender); } catch (JobEmailNotificationException e) { Assert.assertThat("Wrong exception message", e.getMessage(), containsString("Error sending email")); throw e; } } @Test(expected = JobEmailNotificationException.class) public void testNoTo() throws Exception { InternalJob job = createJob(null); Map<String, String> genericInfo = job.getGenericInformation(); genericInfo.put("NOTIFICATION_EVENTS", "Job running to finished"); job.setGenericInformation(genericInfo); try { sendNotification(job, SchedulerEvent.JOB_RUNNING_TO_FINISHED, sender); } catch (JobEmailNotificationException e) { Assert.assertThat("Wrong exception message", e.getMessage(), containsString("Recipient address is not set in generic information")); throw e; } } @Test public void testDisabled() throws Exception { disableEmailNotifications(); InternalJob job = createJob(USER_EMAIL); boolean sent = sendNotification(job, SchedulerEvent.JOB_RUNNING_TO_FINISHED, stubbedSender); assertFalse(sent); verifyNoMoreInteractions(stubbedSender); } @Test public void testWrongEvent() throws Exception { InternalJob job = createJob(USER_EMAIL); assertFalse(sendNotification(job, SchedulerEvent.FROZEN, stubbedSender)); assertFalse(sendNotification(job, SchedulerEvent.RESUMED, stubbedSender)); assertFalse(sendNotification(job, SchedulerEvent.SHUTDOWN, stubbedSender)); assertFalse(sendNotification(job, SchedulerEvent.SHUTTING_DOWN, stubbedSender)); assertFalse(sendNotification(job, SchedulerEvent.STARTED, stubbedSender)); assertFalse(sendNotification(job, SchedulerEvent.STOPPED, stubbedSender)); assertFalse(sendNotification(job, SchedulerEvent.KILLED, stubbedSender)); assertFalse(sendNotification(job, SchedulerEvent.JOB_REMOVE_FINISHED, stubbedSender)); assertFalse(sendNotification(job, SchedulerEvent.TASK_PENDING_TO_RUNNING, stubbedSender)); assertFalse(sendNotification(job, SchedulerEvent.TASK_RUNNING_TO_FINISHED, stubbedSender)); assertFalse(sendNotification(job, SchedulerEvent.TASK_WAITING_FOR_RESTART, stubbedSender)); assertFalse(sendNotification(job, SchedulerEvent.PAUSED, stubbedSender)); assertFalse(sendNotification(job, SchedulerEvent.RM_DOWN, stubbedSender)); assertFalse(sendNotification(job, SchedulerEvent.RM_UP, stubbedSender)); assertFalse(sendNotification(job, SchedulerEvent.USERS_UPDATE, stubbedSender)); assertFalse(sendNotification(job, SchedulerEvent.POLICY_CHANGED, stubbedSender)); assertFalse(sendNotification(job, SchedulerEvent.TASK_REPLICATED, stubbedSender)); assertFalse(sendNotification(job, SchedulerEvent.TASK_SKIPPED, stubbedSender)); assertFalse(sendNotification(job, SchedulerEvent.TASK_PROGRESS, stubbedSender)); assertFalse(sendNotification(job, SchedulerEvent.DB_DOWN, stubbedSender)); verifyNoMoreInteractions(stubbedSender); } @Test public void testSimple() throws Exception { InternalJob job = createJob(USER_EMAIL); Map<String, String> genericInfo = job.getGenericInformation(); genericInfo.put("NOTIFICATION_EVENTS", "Job running to finished"); job.setGenericInformation(genericInfo); boolean sent = sendNotification(job, SchedulerEvent.JOB_RUNNING_TO_FINISHED, stubbedSender); assertTrue(sent); verify(stubbedSender).sender(eq(USER_EMAIL), anyString(), anyString()); verifyNoMoreInteractions(stubbedSender); } @Test public void testFinished() throws Exception { InternalJob job = createJob(USER_EMAIL); job.setId(new JobIdImpl(123890, job.getName())); job.setStatus(JobStatus.FINISHED); Map<String, String> genericInfo = job.getGenericInformation(); genericInfo.put("NOTIFICATION_EVENTS", "Job running to finished"); job.setGenericInformation(genericInfo); boolean sent = sendNotification(job, SchedulerEvent.JOB_RUNNING_TO_FINISHED, stubbedSender); assertTrue(sent); verify(stubbedSender).sender(eq(USER_EMAIL), contains("ProActive Job 123890 : Job running to finished"), contains("Status: Finished")); verifyNoMoreInteractions(stubbedSender); } @Test public void testKilled() throws Exception { InternalJob job = createJob(USER_EMAIL); job.setId(new JobIdImpl(123890, job.getName())); job.setStatus(JobStatus.KILLED); Map<String, String> genericInfo = job.getGenericInformation(); genericInfo.put("NOTIFICATION_EVENTS", "Job running to finished"); job.setGenericInformation(genericInfo); boolean sent = sendNotification(job, SchedulerEvent.JOB_RUNNING_TO_FINISHED, stubbedSender); assertTrue(sent); verify(stubbedSender).sender(eq(USER_EMAIL), contains("ProActive Job 123890 : Job running to finished"), contains("Status: Killed")); verifyNoMoreInteractions(stubbedSender); } @Test public void testPendingToFinished() throws Exception { InternalJob job = createJob(USER_EMAIL); job.setId(new JobIdImpl(123890, job.getName())); job.setStatus(JobStatus.FINISHED); Map<String, String> genericInfo = job.getGenericInformation(); genericInfo.put("NOTIFICATION_EVENTS", "Job pending to finished"); job.setGenericInformation(genericInfo); boolean sent = sendNotification(job, SchedulerEvent.JOB_PENDING_TO_FINISHED, stubbedSender); assertTrue(sent); verify(stubbedSender).sender(eq(USER_EMAIL), contains("ProActive Job 123890 : Job pending to finished"), contains("Status: Finished")); verifyNoMoreInteractions(stubbedSender); } @Test public void testPaused() throws Exception { InternalJob job = createJob(USER_EMAIL); job.setId(new JobIdImpl(123890, job.getName())); job.setStatus(JobStatus.PAUSED); Map<String, String> genericInfo = job.getGenericInformation(); genericInfo.put("NOTIFICATION_EVENTS", "Job paused"); job.setGenericInformation(genericInfo); boolean sent = sendNotification(job, SchedulerEvent.JOB_PAUSED, stubbedSender); assertTrue(sent); verify(stubbedSender).sender(eq(USER_EMAIL), contains("ProActive Job 123890 : Job paused"), contains("Status: Paused")); verifyNoMoreInteractions(stubbedSender); } @Test public void testResumed() throws Exception { InternalJob job = createJob(USER_EMAIL); job.setId(new JobIdImpl(123890, job.getName())); job.setStatus(JobStatus.PENDING); Map<String, String> genericInfo = job.getGenericInformation(); genericInfo.put("NOTIFICATION_EVENTS", "Job resumed"); job.setGenericInformation(genericInfo); boolean sent = sendNotification(job, SchedulerEvent.JOB_RESUMED, stubbedSender); assertTrue(sent); verify(stubbedSender).sender(eq(USER_EMAIL), contains("ProActive Job 123890 : Job resumed"), contains("Status: Pending")); verifyNoMoreInteractions(stubbedSender); } @Test public void testJobInError() throws Exception { InternalJob job = createJob(USER_EMAIL); job.setId(new JobIdImpl(123890, job.getName())); job.setStatus(JobStatus.IN_ERROR); Map<String, String> genericInfo = job.getGenericInformation(); genericInfo.put("NOTIFICATION_EVENTS", "Job In-Error"); job.setGenericInformation(genericInfo); boolean sent = sendNotification(job, SchedulerEvent.JOB_IN_ERROR, stubbedSender); assertTrue(sent); verify(stubbedSender).sender(eq(USER_EMAIL), contains("ProActive Job 123890 : Job In-Error"), contains("Status: In-Error")); verifyNoMoreInteractions(stubbedSender); } @Test public void testJobSubmitted() throws Exception { InternalJob job = createJob(USER_EMAIL); job.setId(new JobIdImpl(123890, job.getName())); job.setStatus(JobStatus.PENDING); Map<String, String> genericInfo = job.getGenericInformation(); genericInfo.put("NOTIFICATION_EVENTS", "Job submitted"); job.setGenericInformation(genericInfo); boolean sent = sendNotification(job, SchedulerEvent.JOB_SUBMITTED, stubbedSender); assertTrue(sent); verify(stubbedSender).sender(eq(USER_EMAIL), contains("ProActive Job 123890 : Job submitted"), contains("Status: Pending")); verifyNoMoreInteractions(stubbedSender); } @Test public void testJobPendingToRun() throws Exception { InternalJob job = createJob(USER_EMAIL); job.setId(new JobIdImpl(123890, job.getName())); job.setStatus(JobStatus.PENDING); Map<String, String> genericInfo = job.getGenericInformation(); genericInfo.put("NOTIFICATION_EVENTS", "Job pending to running"); job.setGenericInformation(genericInfo); boolean sent = sendNotification(job, SchedulerEvent.JOB_PENDING_TO_RUNNING, stubbedSender); assertTrue(sent); verify(stubbedSender).sender(eq(USER_EMAIL), contains("ProActive Job 123890 : Job pending to running"), contains("Status: Pending")); verifyNoMoreInteractions(stubbedSender); } @Test public void testJobChangePriority() throws Exception { InternalJob job = createJob(USER_EMAIL); job.setId(new JobIdImpl(123890, job.getName())); job.setStatus(JobStatus.STALLED); Map<String, String> genericInfo = job.getGenericInformation(); genericInfo.put("NOTIFICATION_EVENTS", "Job change priority"); job.setGenericInformation(genericInfo); boolean sent = sendNotification(job, SchedulerEvent.JOB_CHANGE_PRIORITY, stubbedSender); assertTrue(sent); verify(stubbedSender).sender(eq(USER_EMAIL), contains("ProActive Job 123890 : Job change priority"), contains("Status: Stalled")); verifyNoMoreInteractions(stubbedSender); } @Test public void testJobRestartedFromError() throws Exception { InternalJob job = createJob(USER_EMAIL); job.setId(new JobIdImpl(123890, job.getName())); job.setStatus(JobStatus.RUNNING); Map<String, String> genericInfo = job.getGenericInformation(); genericInfo.put("NOTIFICATION_EVENTS", "Job restarted from error"); job.setGenericInformation(genericInfo); boolean sent = sendNotification(job, SchedulerEvent.JOB_RESTARTED_FROM_ERROR, stubbedSender); assertTrue(sent); verify(stubbedSender).sender(eq(USER_EMAIL), contains("ProActive Job 123890 : Job restarted from error"), contains("Status: Running")); verifyNoMoreInteractions(stubbedSender); } }