/* * Copyright (C) 2009 eXo Platform SAS. * * 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.exoplatform.services.mail.test; import junit.framework.TestCase; import org.exoplatform.container.PortalContainer; import org.exoplatform.services.mail.Attachment; import org.exoplatform.services.mail.MailService; import org.exoplatform.services.mail.Message; import org.subethamail.wiser.Wiser; import org.subethamail.wiser.WiserMessage; import java.io.ByteArrayInputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.Properties; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; import javax.mail.Flags; import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; /** * Created by The eXo Platform SAS Author : Phung Hai Nam phunghainam@gmail.com * Dec 23, 2005 */ public class TestMailService extends TestCase { /** * Test email subject used throughout the test cases */ static private String MAIL_SUBJECT = "eXo Test Subject"; /** * Test email contents used throughout the test cases */ static private String MAIL_CONTENTS = "eXo Mail Service Test Content"; /** * Test email attachment used throughout the test cases */ static private String ATTACHMENT = "eXo Mail Service Test Attachment"; /** * Mime-type corresponding to plain text documents */ static private String TEXT_PLAIN = "text/plain"; /** * Mime-type corresponding to html documents */ static private String TEXT_HTML = "text/html"; /** * Time we assume to be enough to wait for server to receive sent emails */ static private long ONE_SECOND = 1000l; /** * SMTP server prot, used for mail session * and {@link SimpleSmtpServer} configuration * Though the default port is 25, to run server * with default port you must have root privilegies */ static private int SMTP_PORT = 2525; /** * Thread number for asynchronous message send tests */ static private int THREAD_NUMBER = 4; /** * SMTP mail server instance, to emulate basic SMTP mail server functions */ protected Wiser mailServer; private MailService service; public TestMailService(String name) { super(name); } public void setUp() throws Exception { PortalContainer pcontainer = PortalContainer.getInstance(); service = (MailService)pcontainer.getComponentInstanceOfType(MailService.class); // starting dummy SMTP Server mailServer = new Wiser(); mailServer.setPort(SMTP_PORT); mailServer.start(); } public void tearDown() throws Exception { mailServer.stop(); } public void testSendMimeMessage() throws Exception { MimeMessage message = new MimeMessage(service.getMailSession()); message.setFrom(new InternetAddress(generateRandomEmailSender())); message.setRecipients(javax.mail.Message.RecipientType.TO, generateRandomEmailRecipient()); message.setSubject(MAIL_SUBJECT); message.setContent(MAIL_CONTENTS, TEXT_PLAIN); Flags flags = new Flags(); flags.add(Flags.Flag.RECENT); message.setFlags(flags, true); assertEquals("SMTP server should be now empty", 0, mailServer.getMessages().size()); assertFalse(isEmailMessageSent(MAIL_SUBJECT)); service.sendMessage(message); Thread.sleep(ONE_SECOND); assertEquals("SMTP server should have one message", 1, mailServer.getMessages().size()); assertTrue(isEmailMessageSent(MAIL_SUBJECT)); } public void testSendMessage() throws Exception { Message message = new Message(); message.setFrom(generateRandomEmailSender()); message.setTo(generateRandomEmailRecipient()); message.setCC(generateRandomEmailRecipient() + "," + generateRandomEmailRecipient()); message.setBCC(generateRandomEmailRecipient() + "," + generateRandomEmailRecipient()); message.setSubject(MAIL_SUBJECT); message.setBody(MAIL_CONTENTS); message.setMimeType(TEXT_HTML); Attachment attachment = new Attachment(); attachment.setInputStream(new ByteArrayInputStream(ATTACHMENT.getBytes())); attachment.setMimeType(TEXT_PLAIN); message.addAttachment(attachment); assertEquals("SMTP server should be now empty", 0, mailServer.getMessages().size()); assertFalse(isEmailMessageSent(MAIL_SUBJECT)); service.sendMessage(message); Thread.sleep(ONE_SECOND); assertEquals("SMTP server should have one message", 5, mailServer.getMessages().size()); assertTrue(isEmailMessageSent(MAIL_SUBJECT)); } public void testSendSimplMessage() throws Exception { assertEquals("SMTP server should be now empty", 0, mailServer.getMessages().size()); assertFalse(isEmailMessageSent(MAIL_SUBJECT)); service.sendMessage(generateRandomEmailSender(), generateRandomEmailRecipient(), MAIL_SUBJECT, MAIL_CONTENTS); Thread.sleep(ONE_SECOND); assertEquals("SMTP server should have one message", 1, mailServer.getMessages().size()); assertTrue(isEmailMessageSent(MAIL_SUBJECT)); } /** * Here we test asynchronous email sending explicitly defined by sender, * recipient, subject and content parameters. * We check if we can get real cause of exception, if that occurs during * message sending process. */ public void testSendSimpleMessageAsynchExceptionCause() throws Exception { Future<Boolean> future = service.sendMessageInFuture("!@#$%^&*()", generateRandomEmailSender(), MAIL_SUBJECT, MAIL_CONTENTS); try { future.get(); fail(); } catch (ExecutionException ee) { assertEquals("We tried to send mail with malformed sender field," + " so we expect an AdressException to be the real cause of ExecutionException", ee.getCause().getClass(), AddressException.class); } } /** * Here we test asynchronous email sending explicitly defined by sender, * recipient, subject and content parameters. * We check concurrent execution of {@link FutureTask} */ public void testSendSimpleMessageAsynch() throws Exception { @SuppressWarnings("unchecked") Future<Boolean>[] futures = new Future[THREAD_NUMBER]; assertEquals("SMTP server should be now empty", 0, mailServer.getMessages().size()); for (int i = 0; i < THREAD_NUMBER; i++) { assertFalse(isEmailMessageSent(MAIL_SUBJECT + i)); futures[i] = service.sendMessageInFuture(generateRandomEmailSender(), generateRandomEmailRecipient(), MAIL_SUBJECT + i, MAIL_CONTENTS + i); } for (int i = 0; i < THREAD_NUMBER; i++) { assertTrue(futures[i].get()); assertTrue(isEmailMessageSent(MAIL_SUBJECT + i)); } //we assume that one thread sends one email assertEquals("SMTP server should have" + THREAD_NUMBER + " message (asynchronously sent)", THREAD_NUMBER, mailServer.getMessages().size()); } /** * Here we test asynchronous email sending of {@link MimeMessage}. * We check if we can get real cause of exception, if that occurs during * message sending process. */ public void testSendMimeMessageAsynchExceptionCause() throws Exception { Flags flags = new Flags(); flags.add(Flags.Flag.RECENT); Properties props = new Properties(System.getProperties()); props.putAll(service.getMailSession().getProperties()); props.put("mail.smtp.port", SMTP_PORT + 1); Session session = Session.getInstance(props); MimeMessage message = new MimeMessage(session); message.setFrom(new InternetAddress(generateRandomEmailSender())); message.setRecipients(javax.mail.Message.RecipientType.TO, generateRandomEmailRecipient()); message.setSubject(MAIL_SUBJECT); message.setContent(MAIL_CONTENTS, TEXT_PLAIN); message.setFlags(flags, true); Future<Boolean> future = service.sendMessageInFuture(message); try { future.get(); fail(); } catch (ExecutionException ee) { assertTrue("We tried to send mail with malformed SMTP port (" + SMTP_PORT + 1 + "), so we expect a MessagingException to be the real cause of ExecutionException", MessagingException.class.isAssignableFrom(ee.getCause().getClass())); } } /** * Here we test asynchronous email sending of {@link MimeMessage}. * We check concurrent execution of {@link FutureTask} */ public void testSendMimeMessageAsynch() throws Exception { @SuppressWarnings("unchecked") Future<Boolean>[] futures = new Future[THREAD_NUMBER]; MimeMessage message; Flags flags = new Flags(Flags.Flag.RECENT); Session session = service.getMailSession(); assertEquals("SMTP server should be now empty", 0, mailServer.getMessages().size()); for (int i = 0; i < THREAD_NUMBER; i++) { assertFalse(isEmailMessageSent(MAIL_SUBJECT + i)); message = new MimeMessage(session); message.setFrom(new InternetAddress(generateRandomEmailSender())); message.setRecipients(javax.mail.Message.RecipientType.TO, generateRandomEmailRecipient()); message.setSubject(MAIL_SUBJECT + i); message.setContent(MAIL_CONTENTS + i, TEXT_PLAIN); message.setFlags(flags, true); futures[i] = service.sendMessageInFuture(message); } for (int i = 0; i < THREAD_NUMBER; i++) { assertTrue(futures[i].get()); assertTrue(isEmailMessageSent(MAIL_SUBJECT + i)); } //we assume that one thread sends one email assertEquals("SMTP server should have" + THREAD_NUMBER + " message (asynchronously sent)", THREAD_NUMBER, mailServer.getMessages().size()); } /** * Here we test asynchronous email sending of {@link Message}. * We check if we can get real cause of exception, if that occurs during * message sending process. */ public void testSendMessageAsynchExceptionCause() throws Exception { Attachment attachment = new Attachment(); attachment.setInputStream(new ByteArrayInputStream(ATTACHMENT.getBytes())); attachment.setMimeType(TEXT_PLAIN); Message message = new Message(); message.setFrom("!@#$%^&*()"); message.setTo(generateRandomEmailRecipient()); message.setCC(generateRandomEmailRecipient() + "," + generateRandomEmailRecipient()); message.setBCC(generateRandomEmailRecipient() + "," + generateRandomEmailRecipient()); message.setSubject(MAIL_SUBJECT); message.setBody(MAIL_CONTENTS); message.setMimeType(TEXT_HTML); message.addAttachment(attachment); Future<Boolean> future = service.sendMessageInFuture(message); try { future.get(); fail(); } catch (ExecutionException ee) { assertEquals("We tried to send mail with malformed sender field," + " so we expect an AdressException to be the real cause of ExecutionException", ee.getCause().getClass(), AddressException.class); } } /** * Here we test asynchronous email sending of {@link Message}. * We check concurrent execution of {@link FutureTask} */ public void testSendMessageInFuture() throws Exception { Message message; Attachment attachment = new Attachment(); attachment.setInputStream(new ByteArrayInputStream(ATTACHMENT.getBytes())); attachment.setMimeType(TEXT_PLAIN); @SuppressWarnings("unchecked") Future<Boolean>[] futures = new Future[THREAD_NUMBER]; assertEquals("SMTP server should be now empty", 0, mailServer.getMessages().size()); for (int i = 0; i < THREAD_NUMBER; i++) { assertFalse(isEmailMessageSent(MAIL_SUBJECT + i)); message = new Message(); message.setFrom(generateRandomEmailSender()); message.setTo(generateRandomEmailRecipient()); message.setCC(generateRandomEmailRecipient() + "," + generateRandomEmailRecipient()); message.setBCC(generateRandomEmailRecipient() + "," + generateRandomEmailRecipient()); message.setSubject(MAIL_SUBJECT + i); message.setBody(MAIL_CONTENTS + i); message.setMimeType(TEXT_HTML); message.addAttachment(attachment); futures[i] = service.sendMessageInFuture(message); } for (int i = 0; i < THREAD_NUMBER; i++) { assertTrue(futures[i].get()); assertTrue(isEmailMessageSent(MAIL_SUBJECT + i)); } //we assume that one thread sends one email assertEquals("SMTP server should have" + (5 * THREAD_NUMBER) + " message (asynchronously sent)", 5 * THREAD_NUMBER, mailServer.getMessages().size()); } /** * Utility method to check if you really sent message * to dummy mail server. Basically it simply checks if * there is an email with defined 'subject' header. * @param subject * @return * @throws MessagingException */ private boolean isEmailMessageSent(String subject) throws MessagingException { if (mailServer.getMessages().size() > 0) { Iterator<WiserMessage> it = new ArrayList<WiserMessage>(mailServer.getMessages()).iterator(); WiserMessage message; while (it.hasNext()) { message = it.next(); if (message.getMimeMessage().getSubject() != null && message.getMimeMessage().getSubject().equals(subject)) { return true; } } } return false; } /** * Utility method to generate random email sender String * @return {@link String} random email sender */ private String generateRandomEmailSender() { return "<exo-sender" + System.currentTimeMillis() + "@localhost>"; } /** * Utility method to generate random email recipient String * @return {@link String} random email recipient */ private String generateRandomEmailRecipient() { return "<exo-recipient" + System.currentTimeMillis() + "@localhost>"; } }