com.haulmont.cuba.core.app.EmailerTest.java Source code

Java tutorial

Introduction

Here is the source code for com.haulmont.cuba.core.app.EmailerTest.java

Source

/*
 * Copyright (c) 2008-2016 Haulmont.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.haulmont.cuba.core.app;

import com.google.common.collect.Lists;
import com.haulmont.cuba.core.entity.SendingAttachment;
import com.haulmont.cuba.core.entity.SendingMessage;
import com.haulmont.cuba.core.global.*;
import com.haulmont.cuba.core.sys.CubaMailSender;
import com.haulmont.cuba.testsupport.TestContainer;
import com.haulmont.cuba.testsupport.TestMailSender;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.time.DateUtils;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;

import javax.mail.Address;
import javax.mail.MessagingException;
import javax.mail.Part;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.*;

import static org.junit.Assert.*;

public class EmailerTest {

    @ClassRule
    public static TestContainer cont = TestContainer.Common.INSTANCE;

    private EmailerAPI emailer;
    private TestMailSender testMailSender;
    private TimeSource timeSource;
    private DataManager dataManager;

    private EmailerConfig emailerConfig;

    @Before
    public void setUp() throws Exception {
        emailer = AppBeans.get(EmailerAPI.NAME);
        testMailSender = AppBeans.get(CubaMailSender.NAME);
        timeSource = AppBeans.get(TimeSource.NAME);
        dataManager = AppBeans.get(DataManager.class);

        emailerConfig = AppBeans.get(Configuration.class).getConfig(EmailerConfig.class);
        emailerConfig.setDelayCallCount(0);

        // send pending emails which might be in the queue
        emailer.processQueuedEmails();
        testMailSender.clearBuffer();
    }

    @Test
    public void testSynchronous() throws Exception {
        doTestSynchronous(false);
    }

    @Test
    public void testSynchronousFS() throws Exception {
        doTestSynchronous(true);
    }

    /*
     * Test single recipient, text body, subject.
     */
    private void doTestSynchronous(boolean useFs) throws Exception {
        emailerConfig.setFileStorageUsed(useFs);
        testMailSender.clearBuffer();

        EmailInfo myInfo = new EmailInfo("testemail@example.com", "Test Email", "Test Body");
        emailer.sendEmail(myInfo);

        assertEquals(1, testMailSender.getBufferSize());
        MimeMessage msg = testMailSender.fetchSentEmail();

        assertEquals(1, msg.getAllRecipients().length);
        assertEquals("testemail@example.com", msg.getAllRecipients()[0].toString());

        assertEquals("Test Email", msg.getSubject());
        assertEquals("Test Body", getBody(msg));
        assertTrue(getBodyContentType(msg).startsWith("text/plain;"));
    }

    /*
     * Test sendEmail() with parameter list.
     */
    @Test
    public void testSimpleParamList() throws Exception {
        testMailSender.clearBuffer();

        emailer.sendEmail("myemail@example.com", "Test Email", "Test Body 2");

        assertEquals(1, testMailSender.getBufferSize());
        MimeMessage msg = testMailSender.fetchSentEmail();

        assertEquals(1, msg.getAllRecipients().length);
        assertEquals("myemail@example.com", msg.getAllRecipients()[0].toString());

        assertEquals("Test Email", msg.getSubject());
        assertEquals("Test Body 2", getBody(msg));
        assertTrue(getBodyContentType(msg).startsWith("text/plain;"));
    }

    @Test
    public void testAsynchronous() throws Exception {
        doTestAsynchronous(false);
    }

    @Test
    public void testAsynchronousFS() throws Exception {
        doTestAsynchronous(true);
    }

    private void doTestAsynchronous(boolean useFs) throws Exception {
        emailerConfig.setFileStorageUsed(useFs);
        testMailSender.clearBuffer();

        String body = "Test Email Body";
        EmailInfo myInfo = new EmailInfo("recipient@example.com", "Test", body);
        List<SendingMessage> messages = emailer.sendEmailAsync(myInfo);
        assertEquals(1, messages.size());

        // not sent yet
        assertTrue(testMailSender.isEmpty());
        SendingMessage sendingMsg = reload(messages.get(0));
        assertEquals(SendingStatus.QUEUE, sendingMsg.getStatus());

        // run scheduler
        emailer.processQueuedEmails();

        // check
        assertEquals(1, testMailSender.getBufferSize());
        MimeMessage msg = testMailSender.fetchSentEmail();

        assertEquals(1, msg.getAllRecipients().length);
        assertEquals("recipient@example.com", msg.getAllRecipients()[0].toString());

        assertEquals("Test", msg.getSubject());
        assertEquals(body, getBody(msg));
        assertTrue(getBodyContentType(msg).startsWith("text/plain;"));

        sendingMsg = reload(messages.get(0));
        assertEquals(SendingStatus.SENT, sendingMsg.getStatus());
    }

    @Test
    public void testHtmlContent() throws Exception {
        testMailSender.clearBuffer();

        String body = "<html><body><b>Hi</b></body></html>";
        EmailInfo myInfo = new EmailInfo("recipient@example.com", "Test", body);
        emailer.sendEmail(myInfo);

        assertEquals(1, testMailSender.getBufferSize());
        MimeMessage msg = testMailSender.fetchSentEmail();

        assertTrue(getBodyContentType(msg).startsWith("text/html;"));
    }

    @Test
    public void testImplicitFromAddress() throws Exception {
        EmailInfo myInfo;

        // synchronous
        emailerConfig.setFromAddress("implicit@example.com");
        myInfo = new EmailInfo("test@example.com", "Test Email", "Test Body");
        emailer.sendEmail(myInfo);
        assertEquals("implicit@example.com", testMailSender.fetchSentEmail().getFrom()[0].toString());

        // asynchronous
        emailerConfig.setFromAddress("implicit2@example.com");
        myInfo = new EmailInfo("test@example.com", "Test Email", "Test Body");
        emailer.sendEmailAsync(myInfo);

        emailer.processQueuedEmails();
        assertEquals("implicit2@example.com", testMailSender.fetchSentEmail().getFrom()[0].toString());
    }

    @Test
    public void testExplicitFromAddress() throws Exception {
        EmailInfo myInfo;
        MimeMessage msg;

        // synchronous
        myInfo = new EmailInfo("test@example.com", "Test Email", "Test Body");
        myInfo.setFrom("explicit@example.com");
        emailer.sendEmail(myInfo);
        msg = testMailSender.fetchSentEmail();
        assertEquals("explicit@example.com", msg.getFrom()[0].toString());

        // asynchronous
        myInfo = new EmailInfo("test@example.com", "Test Email", "Test Body");
        myInfo.setFrom("explicit2@example.com");
        emailer.sendEmailAsync(myInfo);

        emailer.processQueuedEmails();
        msg = testMailSender.fetchSentEmail();
        assertEquals("explicit2@example.com", msg.getFrom()[0].toString());
    }

    @Test
    public void testSynchronousFail() throws Exception {
        testMailSender.clearBuffer();

        testMailSender.failPlease();
        try {
            emailer.sendEmail("myemail@example.com", "Test Email", "Test Body 2");
            fail("Must fail with EmailException");
        } catch (EmailException e) {
            assertEquals(1, e.getFailedAddresses().size());
            assertEquals("myemail@example.com", e.getFailedAddresses().get(0));
            assertTrue(testMailSender.isEmpty());
        } finally {
            testMailSender.workNormallyPlease();
        }
    }

    @Test
    public void testAsynchronousAttemptLimit() throws Exception {
        testMailSender.clearBuffer();

        String body = "Test Email Body";
        EmailInfo myInfo = new EmailInfo("recipient@example.com", "Test", body);
        List<SendingMessage> messages = emailer.sendEmailAsync(myInfo, 2, getDeadlineWhichDoesntMatter());
        assertEquals(1, messages.size());

        // not sent yet
        assertTrue(testMailSender.isEmpty());
        SendingMessage sendingMsg = reload(messages.get(0));
        assertEquals(SendingStatus.QUEUE, sendingMsg.getStatus());

        // will fail
        testMailSender.failPlease();
        try {
            // try once
            emailer.processQueuedEmails();
            sendingMsg = reload(sendingMsg);
            assertEquals(SendingStatus.QUEUE, sendingMsg.getStatus());

            // try second time
            emailer.processQueuedEmails();
            sendingMsg = reload(sendingMsg);
            assertEquals(SendingStatus.QUEUE, sendingMsg.getStatus());

        } finally {
            testMailSender.workNormallyPlease();
        }

        // marks as not-sent in the next tick
        emailer.processQueuedEmails();
        sendingMsg = reload(sendingMsg);
        assertEquals(SendingStatus.NOTSENT, sendingMsg.getStatus());
        assertEquals(2, sendingMsg.getAttemptsCount().intValue());
    }

    @Test
    public void testSentFromSecondAttempt() throws Exception {
        doTestSentFromSecondAttempt(false);
    }

    @Test
    public void testSentFromSecondAttemptFS() throws Exception {
        doTestSentFromSecondAttempt(true);
    }

    private void doTestSentFromSecondAttempt(boolean useFs) {
        emailerConfig.setFileStorageUsed(useFs);
        testMailSender.clearBuffer();

        String body = "Test Email Body";
        EmailInfo myInfo = new EmailInfo("recipient@example.com", "Test", body);
        List<SendingMessage> messages = emailer.sendEmailAsync(myInfo, 2, getDeadlineWhichDoesntMatter());
        assertEquals(1, messages.size());

        // not sent yet
        assertTrue(testMailSender.isEmpty());
        SendingMessage sendingMsg = reload(messages.get(0));
        assertEquals(SendingStatus.QUEUE, sendingMsg.getStatus());

        // will fail
        testMailSender.failPlease();
        try {
            // try once
            emailer.processQueuedEmails();
            sendingMsg = reload(sendingMsg);
            assertEquals(SendingStatus.QUEUE, sendingMsg.getStatus());

        } finally {
            testMailSender.workNormallyPlease();
        }

        // success now
        emailer.processQueuedEmails();
        sendingMsg = reload(sendingMsg);
        assertEquals(SendingStatus.SENT, sendingMsg.getStatus());
        assertEquals(2, sendingMsg.getAttemptsCount().intValue());
    }

    @Test
    public void testSeveralRecipients() throws Exception {
        doTestSeveralRecipients(false);
    }

    @Test
    public void testSeveralRecipientsFS() throws Exception {
        doTestSeveralRecipients(true);
    }

    private void doTestSeveralRecipients(boolean useFs) throws MessagingException {
        emailerConfig.setFileStorageUsed(useFs);
        testMailSender.clearBuffer();

        String body = "Test Email Body";
        String recipients = "misha@example.com,kolya@example.com;tanya@example.com;"; // 3 recipients
        EmailInfo myInfo = new EmailInfo(recipients, "Test", body);
        List<SendingMessage> messages = emailer.sendEmailAsync(myInfo);
        assertEquals(3, messages.size());

        assertTrue(testMailSender.isEmpty());
        emailer.processQueuedEmails();

        Set<String> recipientSet = new HashSet<>();
        // check
        assertEquals(3, testMailSender.getBufferSize());
        for (int i = 0; i < 3; i++) {
            MimeMessage msg = testMailSender.fetchSentEmail();
            Address[] msgRecipients = msg.getAllRecipients();
            assertEquals(1, msgRecipients.length);
            recipientSet.add(msgRecipients[0].toString());
        }

        assertTrue(recipientSet.contains("misha@example.com"));
        assertTrue(recipientSet.contains("kolya@example.com"));
        assertTrue(recipientSet.contains("tanya@example.com"));
    }

    @Test
    public void testSendAllToAdmin() throws Exception {
        emailerConfig.setSendAllToAdmin(true);
        emailerConfig.setAdminAddress("admin@example.com");
        try {
            emailer.sendEmail("michael@example.com", "Test Email 5", "Test Body 5");

            emailer.sendEmailAsync(new EmailInfo("nikolay@example.com", "Test Email 6", "Test Body 6"));
            emailer.processQueuedEmails();

            for (int i = 0; i < 2; i++) {
                MimeMessage msg = testMailSender.fetchSentEmail();
                assertEquals(1, msg.getAllRecipients().length);
                assertEquals("admin@example.com", msg.getAllRecipients()[0].toString());
            }

        } finally {
            emailerConfig.setSendAllToAdmin(false);
        }
    }

    @Test
    public void testEmailTemplate() throws Exception {
        testMailSender.clearBuffer();

        String templateFileName = "/com/haulmont/cuba/core/app/testEmailTemplate.ftl";

        Map<String, Serializable> params = new HashMap<>();
        params.put("userName", "Bob");
        params.put("dateParam", new SimpleDateFormat("dd/MM/yyyy").parse("01/05/2013"));

        EmailInfo info = new EmailInfo("bob@example.com", "Test", null, templateFileName, params);
        emailer.sendEmailAsync(info);
        emailer.processQueuedEmails();

        String body = getBody(testMailSender.fetchSentEmail());
        assertEquals("Greetings, Bob! 01-05-2013", body.trim());
    }

    @Test
    public void testTextAttachment() throws Exception {
        doTestTextAttachment(false);
    }

    @Test
    public void testTextAttachmentFS() throws Exception {
        doTestTextAttachment(true);
    }

    private void doTestTextAttachment(boolean useFs) throws IOException, MessagingException {
        emailerConfig.setFileStorageUsed(useFs);
        testMailSender.clearBuffer();

        String attachmentText = "Test Attachment Text";
        EmailAttachment textAttach = EmailAttachment.createTextAttachment(attachmentText, "ISO-8859-1", "test.txt");

        EmailInfo myInfo = new EmailInfo("test@example.com", "Test", null, "Test", textAttach);
        emailer.sendEmailAsync(myInfo);

        emailer.processQueuedEmails();

        MimeMessage msg = testMailSender.fetchSentEmail();
        MimeBodyPart firstAttachment = getFirstAttachment(msg);

        // check content bytes
        Object content = firstAttachment.getContent();
        assertTrue(content instanceof InputStream);
        byte[] data = IOUtils.toByteArray((InputStream) content);
        assertEquals(attachmentText, new String(data, "ISO-8859-1"));

        // disposition
        assertEquals(Part.ATTACHMENT, firstAttachment.getDisposition());

        // charset header
        String contentType = firstAttachment.getContentType();
        assertTrue(contentType.toLowerCase().contains("charset=iso-8859-1"));
    }

    @Test
    public void testInlineImage() throws Exception {
        doTestInlineImage(false);
    }

    @Test
    public void testInlineImageFS() throws Exception {
        doTestInlineImage(true);
    }

    private void doTestInlineImage(boolean useFs) throws IOException, MessagingException {
        emailerConfig.setFileStorageUsed(useFs);
        testMailSender.clearBuffer();

        byte[] imageBytes = new byte[] { 1, 2, 3, 4, 5 };
        String fileName = "logo.png";
        EmailAttachment imageAttach = new EmailAttachment(imageBytes, fileName, "logo");

        EmailInfo myInfo = new EmailInfo("test@example.com", "Test", null, "Test", imageAttach);
        emailer.sendEmailAsync(myInfo);

        emailer.processQueuedEmails();

        MimeMessage msg = testMailSender.fetchSentEmail();
        MimeBodyPart attachment = getInlineAttachment(msg);

        // check content bytes
        InputStream content = (InputStream) attachment.getContent();
        byte[] data = IOUtils.toByteArray(content);
        assertByteArrayEquals(imageBytes, data);

        // disposition
        assertEquals(Part.INLINE, attachment.getDisposition());

        // mime type
        String contentType = attachment.getContentType();
        assertTrue(contentType.contains("image/png"));
    }

    @Test
    public void testPdfAttachment() throws Exception {
        doTestPdfAttachment(false);
    }

    @Test
    public void testPdfAttachmentFS() throws Exception {
        doTestPdfAttachment(true);
    }

    private void doTestPdfAttachment(boolean useFs) throws IOException, MessagingException {
        emailerConfig.setFileStorageUsed(useFs);
        testMailSender.clearBuffer();

        byte[] pdfBytes = new byte[] { 1, 2, 3, 4, 6 };
        String fileName = "invoice.pdf";
        EmailAttachment pdfAttach = new EmailAttachment(pdfBytes, fileName);

        EmailInfo myInfo = new EmailInfo("test@example.com", "Test", null, "Test", pdfAttach);
        emailer.sendEmailAsync(myInfo);

        emailer.processQueuedEmails();

        MimeMessage msg = testMailSender.fetchSentEmail();
        MimeBodyPart attachment = getFirstAttachment(msg);

        // check content bytes
        InputStream content = (InputStream) attachment.getContent();
        byte[] data = IOUtils.toByteArray(content);
        assertByteArrayEquals(pdfBytes, data);

        // disposition
        assertEquals(Part.ATTACHMENT, attachment.getDisposition());

        // mime type
        String contentType = attachment.getContentType();
        assertTrue(contentType.contains("application/pdf"));
    }

    @Test
    public void testLoadBody() throws Exception {
        doTestLoadBody(false);
    }

    @Test
    public void testLoadBodyFS() throws Exception {
        doTestLoadBody(true);
    }

    private void doTestLoadBody(boolean useFs) throws Exception {
        emailerConfig.setFileStorageUsed(useFs);

        String body = "Hi! This is test email. Bye.";
        EmailInfo emailInfo = new EmailInfo("test@example.com", "Test", body);
        List<SendingMessage> messages = emailer.sendEmailAsync(emailInfo);

        SendingMessage msg = reload(messages.get(0));

        String actualBody = emailer.loadContentText(msg);
        assertEquals(body, actualBody);
    }

    @Test
    public void testMigration() throws Exception {
        emailerConfig.setFileStorageUsed(false);

        byte[] expectedBytes = new byte[] { 1, 2, 3, 4, 6 };
        EmailAttachment fileAttachment = new EmailAttachment(expectedBytes, "invoice.pdf");

        String body = "Hi! This is test email. Bye.";
        EmailInfo emailInfo = new EmailInfo("test@example.com", "Test", body);
        emailInfo.setAttachments(new EmailAttachment[] { fileAttachment });

        List<SendingMessage> messages = emailer.sendEmailAsync(emailInfo);
        SendingMessage msg;
        SendingAttachment attachment;

        // check DB storage
        msg = reload(messages.get(0), "sendingMessage.loadFromQueue");
        attachment = msg.getAttachments().get(0);

        assertNotNull(msg.getContentText());
        assertNull(msg.getContentTextFile());
        assertNotNull(attachment.getContent());
        assertNull(attachment.getContentFile());

        emailer.migrateEmailsToFileStorage(Lists.newArrayList(msg));
        emailer.migrateAttachmentsToFileStorage(Lists.newArrayList(attachment));

        // check file storage
        msg = reload(msg, "sendingMessage.loadFromQueue");
        attachment = msg.getAttachments().get(0);

        assertNull(msg.getContentText());
        assertNotNull(msg.getContentTextFile());
        assertEquals(body, emailer.loadContentText(msg));

        assertNull(attachment.getContent());
        assertNotNull(attachment.getContentFile());
        FileStorageAPI fileStorage = AppBeans.get(FileStorageAPI.NAME);
        byte[] actualBytes = fileStorage.loadFile(attachment.getContentFile());
        assertByteArrayEquals(expectedBytes, actualBytes);
    }

    /* Utility */
    private Date getDeadlineWhichDoesntMatter() {
        return DateUtils.addHours(timeSource.currentTimestamp(), 2);
    }

    private String getBody(MimeMessage msg) throws Exception {
        MimeBodyPart textPart = getTextPart(msg);
        return (String) textPart.getContent();
    }

    private String getBodyContentType(MimeMessage msg) throws Exception {
        MimeBodyPart textPart = getTextPart(msg);
        return textPart.getContentType();
    }

    private MimeBodyPart getTextPart(MimeMessage msg) throws IOException, MessagingException {
        assertTrue(msg.getContent() instanceof MimeMultipart);
        MimeMultipart mimeMultipart = (MimeMultipart) msg.getContent();

        Object content2 = mimeMultipart.getBodyPart(0).getContent();
        assertTrue(content2 instanceof MimeMultipart);
        MimeMultipart textBodyPart = (MimeMultipart) content2;

        return (MimeBodyPart) textBodyPart.getBodyPart(0);
    }

    private MimeBodyPart getFirstAttachment(MimeMessage msg) throws IOException, MessagingException {
        assertTrue(msg.getContent() instanceof MimeMultipart);
        MimeMultipart mimeMultipart = (MimeMultipart) msg.getContent();
        return (MimeBodyPart) mimeMultipart.getBodyPart(1);
    }

    private MimeBodyPart getInlineAttachment(MimeMessage msg) throws IOException, MessagingException {
        assertTrue(msg.getContent() instanceof MimeMultipart);
        MimeMultipart mimeMultipart = (MimeMultipart) msg.getContent();

        Object content2 = mimeMultipart.getBodyPart(0).getContent();
        assertTrue(content2 instanceof MimeMultipart);
        MimeMultipart textBodyPart = (MimeMultipart) content2;

        return (MimeBodyPart) textBodyPart.getBodyPart(1);
    }

    private SendingMessage reload(SendingMessage sendingMessage) {
        return reload(sendingMessage, null);
    }

    private SendingMessage reload(SendingMessage sendingMessage, String viewName) {
        LoadContext<SendingMessage> loadContext = LoadContext.create(SendingMessage.class)
                .setId(sendingMessage.getId());
        if (viewName != null)
            loadContext.setView(viewName);

        return dataManager.load(loadContext);

        //        Transaction tx = cont.persistence().createTransaction();
        //        try {
        //            sendingMessage = cont.persistence().getEntityManager().reload(sendingMessage, viewNames);
        //            tx.commit();
        //        } finally {
        //            tx.end();
        //        }
        //        return sendingMessage;
    }

    private void assertByteArrayEquals(byte[] expected, byte[] actual) {
        assertEquals(expected.length, actual.length);
        for (int i = 0; i < expected.length; i++) {
            assertEquals(expected[i], actual[i]);
        }
    }
}