package nl.enovation.commons.monitor;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import nl.enovation.commons.IdGenerator;
import nl.enovation.ems.domain.MailSender;
import org.apache.commons.lang.math.RandomUtils;
import org.hamcrest.Description;
import org.hamcrest.Factory;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.jmock.Expectations;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import static nl.enovation.commons.monitor.HasProperty.property;
import static nl.enovation.commons.monitor.HasStringCollectionValues.stringCollectionValues;
import static nl.enovation.commons.monitor.HasContent.contentValue;
import static org.junit.Assert.fail;
public class MailLoopMonitor_check_Test {
private MailLoopMonitor mailLoopMonitor;
protected JUnit4Mockery context = new JUnit4Mockery() {
{
setImposteriser(ClassImposteriser.INSTANCE);
}
};
private MailSender mailSender;
private String generatedId;
private MailChecker mailChecker;
@Before
public void setUp() {
mailLoopMonitor = new MailLoopMonitor();
// mailSender = context.mock(MailSender.class);
// mailChecker = context.mock(MailChecker.class);
}
@Test
public void shouldSendMailWithTheConfiguredSender() throws MessagingException, IOException {
mailSender = context.mock(MailSender.class);
final String sender = createRandomEmailAddress();
mailLoopMonitor.setSender(sender);
mailLoopMonitor.setIdGenerator(createAnIdGenerator());
mailLoopMonitor.setMailSender(mailSender);
mailLoopMonitor.setMailChecker(createMailChecker(true));
mailLoopMonitor.setMessage(createRandomString());
mailLoopMonitor.setInitialWaitTime(1);
mailLoopMonitor.setIntervalTime(1);
mailLoopMonitor.setCheckTimes(1);
mailLoopMonitor.setRecipient(createRandomEmailAddress());
context.checking(new Expectations() {
{
one(mailSender).sendMessage(with(any(MimeMessage.class)), with(equal(sender)),
with(any(Collection.class)));
}
});
mailLoopMonitor.check("test");
// verify
context.assertIsSatisfied();
}
@Test
public void shouldSendMailWithTheConfiguredRecipient() throws MessagingException, IOException {
mailSender = context.mock(MailSender.class);
final String recipient = createRandomEmailAddress();
final Collection<String> recipients = new ArrayList<String>();
recipients.add(recipient);
mailLoopMonitor.setSender(createRandomEmailAddress());
mailLoopMonitor.setIdGenerator(createAnIdGenerator());
mailLoopMonitor.setMailSender(mailSender);
mailLoopMonitor.setMailChecker(createMailChecker(true));
mailLoopMonitor.setMessage(createRandomString());
mailLoopMonitor.setInitialWaitTime(1);
mailLoopMonitor.setIntervalTime(1);
mailLoopMonitor.setCheckTimes(1);
mailLoopMonitor.setRecipient(recipient);
context.checking(new Expectations() {
{
one(mailSender).sendMessage(with(any(MimeMessage.class)), with(any(String.class)),
with(stringCollectionValues(recipients)));
}
});
mailLoopMonitor.check("test");
// verify
context.assertIsSatisfied();
}
@Test
public void shouldSendMailWithTheConfiguredContent() throws MessagingException, IOException {
mailSender = context.mock(MailSender.class);
final String messageContent = createRandomString();
mailLoopMonitor.setSender(createRandomEmailAddress());
mailLoopMonitor.setIdGenerator(createAnIdGenerator());
mailLoopMonitor.setMailSender(mailSender);
mailLoopMonitor.setMailChecker(createMailChecker(true));
mailLoopMonitor.setMessage(messageContent);
mailLoopMonitor.setInitialWaitTime(1);
mailLoopMonitor.setIntervalTime(1);
mailLoopMonitor.setCheckTimes(1);
mailLoopMonitor.setRecipient(createRandomEmailAddress());
context.checking(new Expectations() {
{
one(mailSender).sendMessage(with(contentValue(messageContent)), with(any(String.class)),
with(any(Collection.class)));
}
});
mailLoopMonitor.check("test");
// verify
context.assertIsSatisfied();
}
@Test
@Ignore("specification not implemented yet")
public void shouldSendMailWithUniqueIds() throws MessagingException, IOException {
fail("not implemented yet");
}
@Test
public void shouldObtainTheUniqueIdsFromTheConfiguredIdGenerator() throws MessagingException, IOException {
mailSender = context.mock(MailSender.class);
mailLoopMonitor.setSender(createRandomEmailAddress());
mailLoopMonitor.setIdGenerator(createAnIdGenerator());
mailLoopMonitor.setMailSender(mailSender);
mailLoopMonitor.setMailChecker(createMailChecker(true));
mailLoopMonitor.setMessage(createRandomString());
mailLoopMonitor.setInitialWaitTime(1);
mailLoopMonitor.setIntervalTime(1);
mailLoopMonitor.setCheckTimes(1);
mailLoopMonitor.setRecipient(createRandomEmailAddress());
context.checking(new Expectations() {
{
one(mailSender).sendMessage(with(property("Subject", generatedId)), with(any(String.class)),
with(any(Collection.class)));
}
});
mailLoopMonitor.check("test");
// verify
context.assertIsSatisfied();
}
@Test
public void shouldSendMailWithTheConfiguredMailSender() throws MessagingException, IOException {
mailSender = context.mock(MailSender.class);
mailLoopMonitor.setSender(createRandomEmailAddress());
mailLoopMonitor.setIdGenerator(createAnIdGenerator());
mailLoopMonitor.setMailSender(mailSender);
mailLoopMonitor.setMailChecker(createMailChecker(true));
mailLoopMonitor.setMessage(createRandomString());
mailLoopMonitor.setInitialWaitTime(1);
mailLoopMonitor.setIntervalTime(1);
mailLoopMonitor.setCheckTimes(1);
mailLoopMonitor.setRecipient(createRandomEmailAddress());
context.checking(new Expectations() {
{
exactly(2).of(mailSender).sendMessage(with(any(MimeMessage.class)), with(any(String.class)),
with(any(Collection.class)));
}
});
mailLoopMonitor.check("test");
mailLoopMonitor.check("test");
// verify
context.assertIsSatisfied();
}
@Test
public void shouldCheckMailWithTheConfiguredMailChecker() throws MessagingException, IOException {
mailChecker = context.mock(MailChecker.class);
mailLoopMonitor.setSender(createRandomEmailAddress());
mailLoopMonitor.setIdGenerator(createAnIdGenerator());
mailLoopMonitor.setMailSender(createMailSender());
mailLoopMonitor.setMailChecker(mailChecker);
mailLoopMonitor.setMessage(createRandomString());
mailLoopMonitor.setInitialWaitTime(1);
mailLoopMonitor.setIntervalTime(1);
mailLoopMonitor.setCheckTimes(1);
mailLoopMonitor.setRecipient(createRandomEmailAddress());
context.checking(new Expectations() {
{
exactly(2).of(mailChecker).check(with(any(String.class)));
will(returnValue(true));
}
});
mailLoopMonitor.check("test");
mailLoopMonitor.check("test");
// verify
context.assertIsSatisfied();
}
@Test
public void shouldReturnStatusCriticalIfSendingMailFails() throws MessagingException, IOException {
// status.message should contain "failed to send message"
// status.name should equal the name parameter passed to the check()
// method
// status.cause should equal the exception that caused the failure
mailSender = context.mock(MailSender.class);
mailLoopMonitor.setSender(createRandomEmailAddress());
mailLoopMonitor.setIdGenerator(createAnIdGenerator());
mailLoopMonitor.setMailSender(mailSender);
mailLoopMonitor.setMailChecker(createMailChecker(true));
mailLoopMonitor.setMessage(createRandomString());
mailLoopMonitor.setInitialWaitTime(1);
mailLoopMonitor.setIntervalTime(1);
mailLoopMonitor.setCheckTimes(1);
mailLoopMonitor.setRecipient(createRandomEmailAddress());
final Exception exception = new MessagingException("sending message failure.");
context.checking(new Expectations() {
{
one(mailSender).sendMessage(with(any(MimeMessage.class)), with(any(String.class)),
with(any(Collection.class)));
will(throwException(exception));
}
});
Status status = mailLoopMonitor.check("test");
Assert.assertEquals(Status.Code.CRITICAL, status.getCode());
Assert.assertEquals("failed to send message", status.getMessage());
Assert.assertEquals(exception, status.getCause());
// verify
context.assertIsSatisfied();
}
@Test
@Ignore("specification not implemented yet")
public void shouldWaitInitialWaitTimeAfterSendingMailBeforeCheckingMail() {
fail("not implemented yet");
}
@Test
public void shouldReturnStatusOKIfCheckingMailSucceeds() throws MessagingException, IOException {
// status.message should contain "matched message ID " + the unique id
// of the sent Mail
// status.name should equal the name parameter passed to the check()
// method
// status.cause should be null
mailLoopMonitor.setSender(createRandomEmailAddress());
mailLoopMonitor.setIdGenerator(createAnIdGenerator());
mailLoopMonitor.setMailSender(createMailSender());
mailLoopMonitor.setMailChecker(createMailChecker(true));
mailLoopMonitor.setMessage(createRandomString());
mailLoopMonitor.setInitialWaitTime(1);
mailLoopMonitor.setIntervalTime(1);
mailLoopMonitor.setCheckTimes(1);
mailLoopMonitor.setRecipient(createRandomEmailAddress());
Status status = mailLoopMonitor.check("test");
Assert.assertEquals(Status.Code.OK, status.getCode());
Assert.assertEquals("matched message ID " + generatedId, status.getMessage());
Assert.assertEquals("test", status.getServiceName());
Assert.assertNull(status.getCause());
// verify
context.assertIsSatisfied();
}
@Test
@Ignore("specification not implemented yet")
public void shouldRetryAfterConfiguredIntervalTimeIfCheckingMailFailsAndNotYetDoneMaximumTries() {
fail("not implemented yet");
}
@Test
public void shouldReturnStatusCriticalIfCheckingMailFailsAndDoneMaximumTries() throws MessagingException,
IOException {
// status.message should contain "message ID " + the unique id of the
// sent Mail + " not matched"
// status.name should equal the name parameter passed to the check()
// method
// status.cause should equal the exception that caused the failure
final int checkTimes = 3;
mailLoopMonitor.setSender(createRandomEmailAddress());
mailLoopMonitor.setIdGenerator(createAnIdGenerator());
mailLoopMonitor.setMailSender(createMailSender());
mailLoopMonitor.setMailChecker(createMailCheckerWithExactCheckTimes(false,checkTimes));
mailLoopMonitor.setMessage(createRandomString());
mailLoopMonitor.setInitialWaitTime(1);
mailLoopMonitor.setIntervalTime(1);
mailLoopMonitor.setCheckTimes(checkTimes);
mailLoopMonitor.setRecipient(createRandomEmailAddress());
Status status = mailLoopMonitor.check("test");
Assert.assertEquals(Status.Code.CRITICAL, status.getCode());
Assert.assertEquals("message ID " + generatedId + " not matched", status.getMessage());
Assert.assertNull(status.getCause());
// verify
context.assertIsSatisfied();
}
/* new specs, add only after the specs above have been implemented */
@Test
public void shouldSendMailWithUniqueIdInSubjectHeaderIfSoConfigured() throws MessagingException, IOException {
mailSender = context.mock(MailSender.class);
mailLoopMonitor.setSender(createRandomEmailAddress());
mailLoopMonitor.setIdGenerator(createAnIdGenerator());
mailLoopMonitor.setMailSender(mailSender);
mailLoopMonitor.setMailChecker(createMailChecker(true));
mailLoopMonitor.setMessage(createRandomString());
mailLoopMonitor.setInitialWaitTime(1);
mailLoopMonitor.setIntervalTime(1);
mailLoopMonitor.setCheckTimes(1);
mailLoopMonitor.setRecipient(createRandomEmailAddress());
context.checking(new Expectations() {
{
one(mailSender).sendMessage(with(property("Subject", generatedId)), with(any(String.class)),
with(any(Collection.class)));
}
});
mailLoopMonitor.check("test");
// verify
context.assertIsSatisfied();
}
@Test
@Ignore("specification not implemented yet")
public void shouldSendMailWithUniqueIdInMessageIdHeaderIfSoConfigured() throws MessagingException, IOException {
mailSender = context.mock(MailSender.class);
mailLoopMonitor.setSender(createRandomEmailAddress());
mailLoopMonitor.setIdGenerator(createAnIdGenerator());
mailLoopMonitor.setMailSender(mailSender);
mailLoopMonitor.setMailChecker(createMailChecker(true));
mailLoopMonitor.setMessage(createRandomString());
mailLoopMonitor.setInitialWaitTime(1);
mailLoopMonitor.setIntervalTime(1);
mailLoopMonitor.setCheckTimes(1);
mailLoopMonitor.setRecipient(createRandomEmailAddress());
context.checking(new Expectations() {
{
one(mailSender).sendMessage(with(property("Message-ID", "<"+generatedId+">")), with(any(String.class)),
with(any(Collection.class)));
}
});
mailLoopMonitor.check("test");
// verify
context.assertIsSatisfied();
fail("not implemented yet");
}
private String createRandomEmailAddress() {
return "user" + RandomUtils.nextInt() + "@domain" + RandomUtils.nextInt() + ".example.com";
}
private IdGenerator<String> createAnIdGenerator() {
final IdGenerator<String> idGenerator = context.mock(IdGenerator.class);
generatedId = createRandomString();
context.checking(new Expectations() {
{
allowing(idGenerator).getNextId();
will(returnValue(generatedId));
}
});
return idGenerator;
}
private String createRandomString() {
return String.valueOf(RandomUtils.nextInt());
}
private MailChecker createMailChecker(boolean result) {
final MailChecker mailChecker;
mailChecker = context.mock(MailChecker.class);
if (result) {
context.checking(new Expectations() {
{
allowing(mailChecker).check(with(any(String.class)));
will(returnValue(true));
}
});
} else {
context.checking(new Expectations() {
{
allowing(mailChecker).check(with(any(String.class)));
will(returnValue(false));
}
});
}
return mailChecker;
}
private MailChecker createMailCheckerWithExactCheckTimes(boolean result, final int i) {
final MailChecker mailChecker;
mailChecker = context.mock(MailChecker.class);
if (result) {
context.checking(new Expectations() {
{
exactly(i).of(mailChecker).check(with(any(String.class)));
will(returnValue(true));
}
});
} else {
context.checking(new Expectations() {
{
exactly(i).of(mailChecker).check(with(any(String.class)));
will(returnValue(false));
}
});
}
return mailChecker;
}
private MailSender createMailSender() throws MessagingException, IOException {
final MailSender mailSender;
mailSender = context.mock(MailSender.class);
context.checking(new Expectations() {
{
allowing(mailSender).sendMessage(with(any(MimeMessage.class)), with(any(String.class)),
with(any(Collection.class)));
}
});
return mailSender;
}
}
// TODO:
class HasProperty extends TypeSafeMatcher<MimeMessage> {
private String name;
private String value;
public HasProperty(String name, String value) {
this.name = name;
this.value = value;
}
public void describeTo(Description description) {
}
@Override
public boolean matchesSafely(MimeMessage item) {
try {
String[] headers = item.getHeader(name);
if (value == null) {
return (headers == null || headers.length == 0);
}
if (headers == null)
return false;
for (String header : headers) {
if (header.equals(value))
return true;
}
return false;
} catch (MessagingException e) {
return false;
}
}
@Factory
static <T> Matcher<MimeMessage> property(String name, String value) {
return new HasProperty(name, value);
}
}
class HasContent extends TypeSafeMatcher<MimeMessage> {
private String value;
public HasContent(String value) {
this.value = value;
}
public void describeTo(Description description) {
}
@Override
public boolean matchesSafely(MimeMessage item) {
try {
String content = (String) item.getContent();
if (value == null) {
return false;
}
if (value.equals(content)) {
return true;
}
} catch (IOException e) {
return false;
} catch (MessagingException e) {
return false;
}
return false;
}
@Factory
static <T> Matcher<MimeMessage> contentValue(String value) {
return new HasContent(value);
}
}
class HasStringValue extends TypeSafeMatcher<String> {
private String value;
public HasStringValue(String value) {
this.value = value;
}
public void describeTo(Description description) {
}
@Override
public boolean matchesSafely(String value) {
return this.value.equals(value);
}
@Factory
static <T> Matcher<String> stringValue(String value) {
return new HasStringValue(value);
}
}
class HasStringCollectionValues extends TypeSafeMatcher<Collection<String>> {
private Collection<String> values;
public HasStringCollectionValues(String value) {
values = new ArrayList<String>(Arrays.asList(value.split(",")));
}
public HasStringCollectionValues(Collection<String> values) {
this.values = values;
}
public void describeTo(Description description) {
}
@Override
public boolean matchesSafely(Collection<String> values) {
return this.values.containsAll(values);
}
@Factory
static <T> Matcher<Collection<String>> stringCollectionValues(String values) {
return new HasStringCollectionValues(values);
}
@Factory
static <T> Matcher<Collection<String>> stringCollectionValues(Collection<String> values) {
return new HasStringCollectionValues(values);
}
}
class HasIntValue extends TypeSafeMatcher<Integer> {
private Integer value;
public HasIntValue(Integer value) {
this.value = value;
}
public void describeTo(Description description) {
}
@Override
public boolean matchesSafely(Integer value) {
return this.value.equals(value);
}
@Factory
static <T> Matcher<Integer> intValue(Integer value) {
return new HasIntValue(value);
}
}
class HasSubject extends TypeSafeMatcher<MimeMessage> {
private String subject;
public HasSubject(String subject) {
this.subject = subject;
}
public void describeTo(Description description) {
}
@Override
public boolean matchesSafely(MimeMessage item) {
try {
return item.getSubject().equals(subject);
} catch (MessagingException e) {
return false;
}
}
@Factory
static <T> Matcher<MimeMessage> subject(String subject) {
return new HasSubject(subject);
}
}
class HasMessageId extends TypeSafeMatcher<MimeMessage> {
private String messageId;
public HasMessageId(String messageId) {
this.messageId = messageId;
}
public void describeTo(Description description) {
}
@Override
public boolean matchesSafely(MimeMessage item) {
try {
return item.getMessageID().equals(messageId);
} catch (MessagingException e) {
return false;
}
}
@Factory
static <T> Matcher<MimeMessage> messageId(String messageId) {
return new HasMessageId(messageId);
}
}
class HasFileName extends TypeSafeMatcher<MimeMessage> {
private String fileName;
public HasFileName(String fileName) {
this.fileName = fileName;
}
public void describeTo(Description description) {
}
@Override
public boolean matchesSafely(MimeMessage item) {
try {
return item.getFileName().equals(fileName);
} catch (MessagingException e) {
return false;
}
}
@Factory
static <T> Matcher<MimeMessage> fileName(String fileName) {
return new HasFileName(fileName);
}
}