org.xwiki.mail.integration.ScriptingIntegrationTest.java Source code

Java tutorial

Introduction

Here is the source code for org.xwiki.mail.integration.ScriptingIntegrationTest.java

Source

/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.xwiki.mail.integration;

import java.io.InputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Properties;

import javax.inject.Provider;
import javax.mail.BodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mockito;
import org.xwiki.bridge.event.ApplicationReadyEvent;
import org.xwiki.component.internal.ContextComponentManagerProvider;
import org.xwiki.component.phase.Disposable;
import org.xwiki.component.util.DefaultParameterizedType;
import org.xwiki.context.Execution;
import org.xwiki.context.ExecutionContext;
import org.xwiki.context.ExecutionContextManager;
import org.xwiki.context.internal.DefaultExecution;
import org.xwiki.environment.internal.EnvironmentConfiguration;
import org.xwiki.environment.internal.StandardEnvironment;
import org.xwiki.mail.MailSenderConfiguration;
import org.xwiki.mail.MailState;
import org.xwiki.mail.internal.DefaultMailSender;
import org.xwiki.mail.internal.DefaultSessionFactory;
import org.xwiki.mail.internal.FileSystemMailContentStore;
import org.xwiki.mail.internal.MemoryMailListener;
import org.xwiki.mail.internal.factory.text.TextMimeBodyPartFactory;
import org.xwiki.mail.internal.thread.MailSenderInitializerListener;
import org.xwiki.mail.internal.thread.PrepareMailQueueManager;
import org.xwiki.mail.internal.thread.PrepareMailRunnable;
import org.xwiki.mail.internal.thread.SendMailQueueManager;
import org.xwiki.mail.internal.thread.SendMailRunnable;
import org.xwiki.mail.internal.thread.context.Copier;
import org.xwiki.mail.script.MailSenderScriptService;
import org.xwiki.mail.script.ScriptMailResult;
import org.xwiki.mail.script.ScriptMimeMessage;
import org.xwiki.mail.script.ScriptServicePermissionChecker;
import org.xwiki.model.ModelContext;
import org.xwiki.model.reference.WikiReference;
import org.xwiki.observation.EventListener;
import org.xwiki.properties.ConverterManager;
import org.xwiki.script.service.ScriptService;
import org.xwiki.test.annotation.BeforeComponent;
import org.xwiki.test.annotation.ComponentList;
import org.xwiki.test.mockito.MockitoComponentManagerRule;

import com.icegreen.greenmail.junit.GreenMailRule;
import com.icegreen.greenmail.util.ServerSetupTest;
import com.xpn.xwiki.XWikiContext;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

/**
 * Integration tests to prove that mail sending is working fully end to end with the Scripting API.
 *
 * @version $Id: 73721725a0f08b4a432fc47e9748b6f8c447c524 $
 * @since 6.1M2
 */
// @formatter:off
@ComponentList({ MailSenderInitializerListener.class, MailSenderScriptService.class, StandardEnvironment.class,
        DefaultMailSender.class, DefaultExecution.class, ContextComponentManagerProvider.class,
        TextMimeBodyPartFactory.class, MemoryMailListener.class, DefaultSessionFactory.class,
        SendMailRunnable.class, PrepareMailRunnable.class, PrepareMailQueueManager.class,
        SendMailQueueManager.class, FileSystemMailContentStore.class })
// @formatter:on
public class ScriptingIntegrationTest {
    @Rule
    public GreenMailRule mail = new GreenMailRule(ServerSetupTest.SMTP);

    @Rule
    public MockitoComponentManagerRule componentManager = new MockitoComponentManagerRule();

    private MailSenderScriptService scriptService;

    @BeforeComponent
    public void registerConfiguration() throws Exception {
        MailSenderConfiguration configuration = new TestMailSenderConfiguration(this.mail.getSmtp().getPort(), null,
                null, new Properties());
        this.componentManager.registerComponent(MailSenderConfiguration.class, configuration);

        // Register a test Permission Checker that allows sending mails
        ScriptServicePermissionChecker checker = mock(ScriptServicePermissionChecker.class);
        this.componentManager.registerComponent(ScriptServicePermissionChecker.class, "test", checker);

        // Set the current wiki in the Context
        ModelContext modelContext = this.componentManager.registerMockComponent(ModelContext.class);
        Mockito.when(modelContext.getCurrentEntityReference()).thenReturn(new WikiReference("wiki"));

        Provider<XWikiContext> xwikiContextProvider = this.componentManager
                .registerMockComponent(XWikiContext.TYPE_PROVIDER);
        when(xwikiContextProvider.get()).thenReturn(Mockito.mock(XWikiContext.class));

        this.componentManager.registerMockComponent(ExecutionContextManager.class);
        this.componentManager
                .registerMockComponent(new DefaultParameterizedType(null, Copier.class, ExecutionContext.class));

        EnvironmentConfiguration environmentConfiguration = this.componentManager
                .registerMockComponent(EnvironmentConfiguration.class);
        when(environmentConfiguration.getPermanentDirectoryPath()).thenReturn(System.getProperty("java.io.tmpdir"));

        this.componentManager.registerMockComponent(ConverterManager.class);
    }

    @Before
    public void initialize() throws Exception {
        this.scriptService = this.componentManager.getInstance(ScriptService.class, "mailsender");

        // Set the EC
        Execution execution = this.componentManager.getInstance(Execution.class);
        ExecutionContext executionContext = new ExecutionContext();
        XWikiContext xContext = new XWikiContext();
        xContext.setWikiId("wiki");
        executionContext.setProperty(XWikiContext.EXECUTIONCONTEXT_KEY, xContext);
        execution.setContext(executionContext);

        Copier<ExecutionContext> executionContextCloner = this.componentManager
                .getInstance(new DefaultParameterizedType(null, Copier.class, ExecutionContext.class));
        // Just return the same execution context
        when(executionContextCloner.copy(executionContext)).thenReturn(executionContext);

        // Simulate receiving the Application Ready Event to start the mail threads
        MailSenderInitializerListener listener = this.componentManager.getInstance(EventListener.class,
                MailSenderInitializerListener.LISTENER_NAME);
        listener.onEvent(new ApplicationReadyEvent(), null, null);
    }

    @After
    public void cleanUp() throws Exception {
        // Make sure we stop the Mail Sender thread after each test (since it's started automatically when looking
        // up the MailSender component.
        Disposable listener = this.componentManager.getInstance(EventListener.class,
                MailSenderInitializerListener.LISTENER_NAME);
        listener.dispose();
    }

    @Test
    public void sendTextMail() throws Exception {
        ScriptMimeMessage message1 = this.scriptService.createMessage("john@doe.com", "subject");
        message1.addPart("text/plain", "some text here");
        ScriptMimeMessage message2 = this.scriptService.createMessage("john@doe.com", "subject");
        message2.addPart("text/plain", "some text here");
        ScriptMimeMessage message3 = this.scriptService.createMessage("john@doe.com", "subject");
        message3.addPart("text/plain", "some text here");

        // Send 3 mails (3 times the same mail) to verify we can send several emails at once.
        List<ScriptMimeMessage> messagesList = Arrays.asList(message1, message2, message3);
        ScriptMailResult result = this.scriptService.sendAsynchronously(messagesList, "memory");

        // Verify that there are no errors
        assertNull(this.scriptService.getLastError());

        // Wait for all mails to be sent
        result.getStatusResult().waitTillProcessed(30000L);
        assertTrue(result.getStatusResult().isProcessed());

        // Verify that all mails have been sent properly
        assertFalse("There should not be any failed result!",
                result.getStatusResult().getByState(MailState.SEND_ERROR).hasNext());
        assertFalse("There should not be any failed result!",
                result.getStatusResult().getByState(MailState.PREPARE_ERROR).hasNext());
        assertFalse("There should not be any mails in the ready state!",
                result.getStatusResult().getByState(MailState.PREPARE_SUCCESS).hasNext());

        // Verify that the mails have been received (wait maximum 30 seconds).
        this.mail.waitForIncomingEmail(30000L, 3);
        MimeMessage[] messages = this.mail.getReceivedMessages();

        assertEquals(3, messages.length);
        assertEquals("subject", messages[0].getHeader("Subject", null));
        assertEquals("john@doe.com", messages[0].getHeader("To", null));

        assertEquals(1, ((MimeMultipart) messages[0].getContent()).getCount());

        BodyPart textBodyPart = ((MimeMultipart) messages[0].getContent()).getBodyPart(0);
        assertEquals("text/plain", textBodyPart.getHeader("Content-Type")[0]);
        assertEquals("some text here", textBodyPart.getContent());
    }

    @Test
    public void sendHTMLAndCalendarInvitationMail() throws Exception {
        ScriptMimeMessage message = this.scriptService.createMessage("john@doe.com", "subject");
        message.addPart("text/html", "<font size=\"\\\"2\\\"\">simple meeting invitation</font>");
        // @formatter:off
        String calendarContent = "BEGIN:VCALENDAR\r\n" + "METHOD:REQUEST\r\n" + "PRODID: Meeting\r\n"
                + "VERSION:2.0\r\n" + "BEGIN:VEVENT\r\n" + "DTSTAMP:20140616T164100\r\n"
                + "DTSTART:20140616T164100\r\n" + "DTEND:20140616T194100\r\n" + "SUMMARY:test request\r\n"
                + "UID:324\r\n"
                + "ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE:MAILTO:john@doe.com\r\n"
                + "ORGANIZER:MAILTO:john@doe.com\r\n" + "LOCATION:on the net\r\n"
                + "DESCRIPTION:learn some stuff\r\n" + "SEQUENCE:0\r\n" + "PRIORITY:5\r\n" + "CLASS:PUBLIC\r\n"
                + "STATUS:CONFIRMED\r\n" + "TRANSP:OPAQUE\r\n" + "BEGIN:VALARM\r\n" + "ACTION:DISPLAY\r\n"
                + "DESCRIPTION:REMINDER\r\n" + "TRIGGER;RELATED=START:-PT00H15M00S\r\n" + "END:VALARM\r\n"
                + "END:VEVENT\r\n" + "END:VCALENDAR";
        // @formatter:on
        message.addPart("text/calendar;method=CANCEL", calendarContent, Collections.<String, Object>singletonMap(
                "headers", Collections.singletonMap("Content-Class", "urn:content-classes:calendarmessage")));

        ScriptMailResult result = this.scriptService.send(Arrays.asList(message));

        // Verify that there are no errors and that 1 mail was sent
        assertNull(this.scriptService.getLastError());
        assertTrue(result.getStatusResult().isProcessed());
        assertEquals(1, result.getStatusResult().getProcessedMailCount());

        // Verify that all mails have been sent properly
        assertFalse("There should not be any failed result!",
                result.getStatusResult().getByState(MailState.SEND_ERROR).hasNext());
        assertFalse("There should not be any failed result!",
                result.getStatusResult().getByState(MailState.PREPARE_ERROR).hasNext());
        assertFalse("There should not be any mails in the ready state!",
                result.getStatusResult().getByState(MailState.PREPARE_SUCCESS).hasNext());

        // Verify that the mail has been received (wait maximum 30 seconds).
        this.mail.waitForIncomingEmail(30000L, 1);
        MimeMessage[] messages = this.mail.getReceivedMessages();

        assertEquals(1, messages.length);
        assertEquals("subject", messages[0].getHeader("Subject", null));
        assertEquals("john@doe.com", messages[0].getHeader("To", null));

        assertEquals(2, ((MimeMultipart) messages[0].getContent()).getCount());

        BodyPart htmlBodyPart = ((MimeMultipart) messages[0].getContent()).getBodyPart(0);
        assertEquals("text/html", htmlBodyPart.getHeader("Content-Type")[0]);
        assertEquals("<font size=\"\\\"2\\\"\">simple meeting invitation</font>", htmlBodyPart.getContent());

        BodyPart calendarBodyPart = ((MimeMultipart) messages[0].getContent()).getBodyPart(1);
        assertEquals("text/calendar;method=CANCEL", calendarBodyPart.getHeader("Content-Type")[0]);
        InputStream is = (InputStream) calendarBodyPart.getContent();
        assertEquals(calendarContent, IOUtils.toString(is));
    }
}