/* * Created on 28/08/2006 22:58:20 */ package net.jforum.api.integration.mail.pop; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.Date; import java.util.List; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.Message.RecipientType; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import junit.framework.TestCase; import net.jforum.ConfigLoader; import net.jforum.ForumStartup; import net.jforum.JForumExecutionContext; import net.jforum.TestCaseUtils; import net.jforum.dao.DataAccessDriver; import net.jforum.dao.PostDAO; import net.jforum.dao.TopicDAO; import net.jforum.entities.Post; import net.jforum.entities.Topic; import net.jforum.entities.User; import net.jforum.repository.RankingRepository; import net.jforum.repository.SmiliesRepository; import net.jforum.util.DbUtils; import net.jforum.util.preferences.ConfigKeys; import net.jforum.util.preferences.SystemGlobals; /** * @author Rafael Steil * @version $Id: POPListenerTestCase.java,v 1.14 2007/09/04 14:57:25 andowson Exp $ */ public class POPListenerTestCase extends TestCase { private static boolean started; /** * A single and simple message */ public void testSimple() throws Exception { int beforeTopicId = this.maxTopicId(); String sender = "ze@zinho.com"; String subject = "Mail Message " + new Date(); String forumAddress = "forum_test@jforum.testcase"; String contents = "Mail message contents " + new Date(); this.sendMessage(sender, subject, forumAddress, contents, null); int afterTopicId = this.maxTopicId(); assertTrue("The message was not inserted", afterTopicId > beforeTopicId); try { this.assertPost(afterTopicId, sender, subject, contents); } finally { this.deleteTopic(afterTopicId); } } /** * Sends an invalid In-Reply-To header, which should cause the system * to create a new topic, instead of adding the message as a reply * to something else. */ public void testInReplyToIncorrectShouldCreateNewTopic() throws Exception { int beforeTopicId = this.maxTopicId(); String sender = "ze@zinho.com"; String subject = "Mail Message " + new Date(); String forumAddress = "forum_test@jforum.testcase"; String contents = "Mail message contents " + new Date(); this.sendMessage(sender, subject, forumAddress, contents, MessageId.buildMessageId(7777, 999999, 888888)); int afterTopicId = this.maxTopicId(); assertTrue("The message was not inserted", afterTopicId > beforeTopicId); try { this.assertPost(afterTopicId, sender, subject, contents); } finally { this.deleteTopic(afterTopicId); } } /** * Create a new topic, then send a message with the In-Reply-To header, * which should create an answer to the previously created topic * @throws Exception */ public void testInReplyToCreateNewTopicThenReply() throws Exception { int beforeTopicId = this.maxTopicId(); String sender = "ze@zinho.com"; String subject = "Mail Message " + new Date(); String forumAddress = "forum_test@jforum.testcase"; String contents = "Mail message contents " + new Date(); this.sendMessage(sender, subject, forumAddress, contents, null); int afterTopicId = this.maxTopicId(); assertTrue("The message was not inserted", afterTopicId > beforeTopicId); try { this.assertPost(afterTopicId, sender, subject, contents); // Ok, now send a new message, replying to the previously topic subject = "Reply subject for topic " + afterTopicId; contents = "Changed contents, replying tpoic " + afterTopicId; this.sendMessage(sender, subject, forumAddress, contents, MessageId.buildMessageId(7777, afterTopicId, 999999)); assertTrue("A new message was created, instead of a reply", afterTopicId == maxTopicId()); PostDAO postDAO = DataAccessDriver.getInstance().newPostDAO(); List posts = postDAO.selectAllByTopic(afterTopicId); assertTrue("There should be two posts", posts.size() == 2); // The first message was already validated Post p = (Post)posts.get(1); User user = DataAccessDriver.getInstance().newUserDAO().selectById(p.getUserId()); assertNotNull("User should not be null", user); assertEquals("sender", sender, user.getEmail()); assertEquals("subject", subject, p.getSubject()); assertEquals("text", contents, p.getText()); } finally { this.deleteTopic(afterTopicId); } } /** * Emulates the action of sending an email. * * @param sender The sender's email. Should exist in the database * @param subject the subject * @param forumAddress the address of the target forum. There should be a matching * record in jforum_mail_integration * @param contents the message itself * @param inReplyTo the In-Reply-To header, as built by {@link MessageId}. Can be null * @throws Exception */ private void sendMessage(String sender, String subject, String forumAddress, String contents, String inReplyTo) throws Exception { POPListener listener = new POPListenerMock(); MimeMessageMock message = this.newMessageMock(sender, subject, forumAddress, contents); if (inReplyTo != null) { message.addHeader("In-Reply-To", inReplyTo); } ((POPConnectorMock)listener.getConnector()).setMessages(new Message[] { message }); listener.execute(null); } /** * Asserts the post instance, after execution some part of the testcase * @param topicId the topic's id of the new message * @param sender the matching sender email * @param subject the matching subject * @param contents the matching message contents */ private void assertPost(int topicId, String sender, String subject, String contents) { PostDAO postDAO = DataAccessDriver.getInstance().newPostDAO(); List posts = postDAO.selectAllByTopic(topicId); assertTrue("There should be exactly one post", posts.size() == 1); Post p = (Post)posts.get(0); User user = DataAccessDriver.getInstance().newUserDAO().selectById(p.getUserId()); assertNotNull("User should not be null", user); assertEquals("sender", sender, user.getEmail()); assertEquals("subject", subject, p.getSubject()); assertEquals("text", contents, p.getText()); } /** * Gets the latest topic id existent * @return the topic id, or -1 if something went wrong * @throws Exception */ private int maxTopicId() throws Exception { int topicId = -1; PreparedStatement p = null; ResultSet rs = null; try { p = JForumExecutionContext.getConnection().prepareStatement("select max(topic_id) from jforum_topics"); rs = p.executeQuery(); if (rs.next()) { topicId = rs.getInt(1); } } finally { DbUtils.close(rs, p); } return topicId; } /** * Deletes a topic * @param topicId the topic's id to delete */ private void deleteTopic(int topicId) { try { TopicDAO dao = DataAccessDriver.getInstance().newTopicDAO(); Topic t = new Topic(topicId); t.setForumId(2); dao.delete(t, false); JForumExecutionContext.finish(); } catch (Exception e) { e.printStackTrace(); } } private MimeMessageMock newMessageMock(String sender, String subject, String listEmail, String text) throws Exception { MimeMessageMock m = new MimeMessageMock(null, new ByteArrayInputStream(text.getBytes())); m.setFrom(new InternetAddress(sender)); m.setRecipient(RecipientType.TO, new InternetAddress(listEmail)); m.setSubject(subject); return m; } /** * @see junit.framework.TestCase#setUp() */ protected void setUp() throws Exception { if (!started) { TestCaseUtils.loadEnvironment(); TestCaseUtils.initDatabaseImplementation(); ConfigLoader.startCacheEngine(); ForumStartup.startForumRepository(); RankingRepository.loadRanks(); SmiliesRepository.loadSmilies(); SystemGlobals.setValue(ConfigKeys.SEARCH_INDEXING_ENABLED, "false"); started = true; } } private static class MimeMessageMock extends MimeMessage { private InputStream is; private String messageId; public MimeMessageMock(Session session, InputStream is) throws MessagingException { super(session, is); this.is = is; } public InputStream getInputStream() throws IOException, MessagingException { return this.is; } protected void updateMessageID() throws MessagingException { if (this.messageId != null) { this.setMessageId(this.messageId); } else { super.updateMessageID(); } } public void setMessageId(String messageId) throws MessagingException { this.addHeader("Message-ID", messageId); this.messageId = messageId; } public String getContentType() throws MessagingException { return "text/plain"; } } }