001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.mail; 018 019 import java.io.BufferedOutputStream; 020 import java.io.ByteArrayOutputStream; 021 import java.io.File; 022 import java.io.FileWriter; 023 import java.io.IOException; 024 import java.util.Date; 025 import java.util.Enumeration; 026 import java.util.List; 027 028 import javax.activation.DataHandler; 029 import javax.mail.Header; 030 import javax.mail.MessagingException; 031 import javax.mail.Multipart; 032 import javax.mail.internet.InternetAddress; 033 import javax.mail.internet.MimeMessage; 034 035 import junit.framework.TestCase; 036 037 import org.apache.commons.mail.settings.EmailConfiguration; 038 import org.subethamail.wiser.Wiser; 039 import org.subethamail.wiser.WiserMessage; 040 041 042 043 /** 044 * Base test case for Email test classes 045 * 046 * @since 1.0 047 * @author <a href="mailto:corey.scott@gmail.com">Corey Scott</a> 048 * @author <a href="mailto:epugh@opensourceconnections.com">Eric Pugh</a> 049 * @version $Id: BaseEmailTestCase.java 544629 2007-06-05 20:55:13Z bspeakmon $ 050 */ 051 052 public class BaseEmailTestCase extends TestCase 053 { 054 /** Padding at end of body added by wiser/send */ 055 public static final int BODY_END_PAD = 3; 056 /** Padding at start of body added by wiser/send */ 057 public static final int BODY_START_PAD = 2; 058 059 /** Line separator in email messages */ 060 private static final String LINE_SEPARATOR = "\r\n"; 061 062 /** default port */ 063 private static int mailServerPort = EmailConfiguration.MAIL_SERVER_PORT; 064 065 /** The fake Wiser email server */ 066 protected Wiser fakeMailServer; 067 068 /** Mail server used for testing */ 069 protected String strTestMailServer = EmailConfiguration.MAIL_SERVER; 070 /** From address for the test email */ 071 protected String strTestMailFrom = EmailConfiguration.TEST_FROM; 072 /** Destination address for the test email */ 073 protected String strTestMailTo = EmailConfiguration.TEST_TO; 074 /** Mailserver username (set if needed) */ 075 protected String strTestUser = EmailConfiguration.TEST_USER; 076 /** Mailserver strTestPasswd (set if needed) */ 077 protected String strTestPasswd = EmailConfiguration.TEST_PASSWD; 078 /** URL to used to test URL attachmetns (Must be valid) */ 079 protected String strTestURL = EmailConfiguration.TEST_URL; 080 081 /** Test characters acceptable to email */ 082 protected String[] testCharsValid = 083 { 084 " ", 085 "a", 086 "A", 087 "\uc5ec", 088 "0123456789", 089 "012345678901234567890", 090 "\n" 091 }; 092 093 /** Array of test strings */ 094 protected String[] testCharsNotValid = {"", null}; 095 096 /** Where to save email output **/ 097 private File emailOutputDir; 098 099 /** 100 * @param name name 101 */ 102 public BaseEmailTestCase(String name) 103 { 104 super(name); 105 emailOutputDir = new File("target/test-emails"); 106 if (!emailOutputDir.exists()) 107 { 108 emailOutputDir.mkdirs(); 109 } 110 } 111 112 /** */ 113 protected void tearDown() 114 { 115 //stop the fake email server (if started) 116 if (this.fakeMailServer != null && !isMailServerStopped(fakeMailServer)) 117 { 118 this.fakeMailServer.stop(); 119 assertTrue("Mail server didn't stop", isMailServerStopped(fakeMailServer)); 120 } 121 122 this.fakeMailServer = null; 123 } 124 125 /** 126 * Gets the mail server port. 127 * @return the port the server is running on. 128 */ 129 protected int getMailServerPort() 130 { 131 return mailServerPort; 132 } 133 134 /** 135 * 136 * @param email email 137 * @throws IOException Exception 138 */ 139 protected void saveEmailToFile(WiserMessage email) throws IOException 140 { 141 File emailFile = 142 new File(emailOutputDir, "email" + new Date().getTime() + ".txt"); 143 FileWriter fw = new FileWriter(emailFile); 144 fw.write(email.toString()); 145 fw.close(); 146 } 147 148 /** 149 * @param intMsgNo the message to retrieve 150 * @return message as string 151 */ 152 public String getMessageAsString(int intMsgNo) 153 { 154 List receivedMessages = fakeMailServer.getMessages(); 155 assertTrue("mail server didn't get enough messages", receivedMessages.size() >= intMsgNo); 156 157 WiserMessage emailMessage = (WiserMessage) receivedMessages.get(intMsgNo); 158 159 if (emailMessage != null) 160 { 161 try 162 { 163 return serializeEmailMessage(emailMessage); 164 } 165 catch (Exception e) 166 { 167 // ignore, since the test will fail on an empty string return 168 } 169 } 170 fail("Message not found"); 171 return ""; 172 } 173 174 /** 175 * Initializes the stub mail server. Fails if the server cannot be proven 176 * to have started. If the server is already started, this method returns 177 * without changing the state of the server. 178 */ 179 public void getMailServer() 180 { 181 if (this.fakeMailServer == null || isMailServerStopped(fakeMailServer)) 182 { 183 mailServerPort++; 184 185 this.fakeMailServer = new Wiser(); 186 this.fakeMailServer.setPort(getMailServerPort()); 187 this.fakeMailServer.start(); 188 189 assertFalse("fake mail server didn't start", isMailServerStopped(fakeMailServer)); 190 191 Date dtStartWait = new Date(); 192 while (isMailServerStopped(fakeMailServer)) 193 { 194 // test for connected 195 if (this.fakeMailServer != null 196 && !isMailServerStopped(fakeMailServer)) 197 { 198 break; 199 } 200 201 // test for timeout 202 if ((dtStartWait.getTime() + EmailConfiguration.TIME_OUT) 203 <= new Date().getTime()) 204 { 205 fail("Mail server failed to start"); 206 } 207 } 208 } 209 } 210 211 /** 212 * Validate the message was sent properly 213 * @param mailServer reference to the fake mail server 214 * @param strSubject expected subject 215 * @param fromAdd expected from address 216 * @param toAdd list of expected to addresses 217 * @param ccAdd list of expected cc addresses 218 * @param bccAdd list of expected bcc addresses 219 * @param boolSaveToFile true will output to file, false doesnt 220 * @return WiserMessage email to check 221 * @throws IOException Exception 222 */ 223 protected WiserMessage validateSend( 224 Wiser mailServer, 225 String strSubject, 226 InternetAddress fromAdd, 227 List toAdd, 228 List ccAdd, 229 List bccAdd, 230 boolean boolSaveToFile) 231 throws IOException 232 { 233 assertTrue("mail server doesn't contain expected message", 234 mailServer.getMessages().size() == 1); 235 WiserMessage emailMessage = (WiserMessage) mailServer.getMessages().get(0); 236 237 if (boolSaveToFile) 238 { 239 this.saveEmailToFile(emailMessage); 240 } 241 242 try 243 { 244 // get the MimeMessage 245 MimeMessage mimeMessage = emailMessage.getMimeMessage(); 246 247 // test subject 248 assertEquals("got wrong subject from mail", 249 strSubject, mimeMessage.getHeader("Subject", null)); 250 251 //test from address 252 assertEquals("got wrong From: address from mail", 253 fromAdd.toString(), mimeMessage.getHeader("From", null)); 254 255 //test to address 256 assertTrue("got wrong To: address from mail", 257 toAdd.toString().indexOf(mimeMessage.getHeader("To", null)) != -1); 258 259 //test cc address 260 if (ccAdd.size() > 0) 261 { 262 assertTrue("got wrong Cc: address from mail", 263 ccAdd.toString().indexOf(mimeMessage.getHeader("Cc", null)) 264 != -1); 265 } 266 267 //test bcc address 268 if (bccAdd.size() > 0) 269 { 270 assertTrue("got wrong Bcc: address from mail", 271 bccAdd.toString().indexOf(mimeMessage.getHeader("Bcc", null)) 272 != -1); 273 } 274 } 275 catch (MessagingException me) 276 { 277 IllegalStateException ise = 278 new IllegalStateException("caught MessagingException in validateSend()"); 279 ise.initCause(me); 280 throw ise; 281 } 282 283 return emailMessage; 284 } 285 286 /** 287 * Validate the message was sent properly 288 * @param mailServer reference to the fake mail server 289 * @param strSubject expected subject 290 * @param content the expected message content 291 * @param fromAdd expected from address 292 * @param toAdd list of expected to addresses 293 * @param ccAdd list of expected cc addresses 294 * @param bccAdd list of expected bcc addresses 295 * @param boolSaveToFile true will output to file, false doesnt 296 * @throws IOException Exception 297 */ 298 protected void validateSend( 299 Wiser mailServer, 300 String strSubject, 301 Multipart content, 302 InternetAddress fromAdd, 303 List toAdd, 304 List ccAdd, 305 List bccAdd, 306 boolean boolSaveToFile) 307 throws IOException 308 { 309 // test other properties 310 WiserMessage emailMessage = this.validateSend( 311 mailServer, 312 strSubject, 313 fromAdd, 314 toAdd, 315 ccAdd, 316 bccAdd, 317 boolSaveToFile); 318 319 // test message content 320 321 // get sent email content 322 String strSentContent = 323 content.getContentType(); 324 // get received email content (chop off the auto-added \n 325 // and -- (front and end) 326 String emailMessageBody = getMessageBody(emailMessage); 327 String strMessageBody = 328 emailMessageBody.substring(BaseEmailTestCase.BODY_START_PAD, 329 emailMessageBody.length() 330 - BaseEmailTestCase.BODY_END_PAD); 331 assertTrue("didn't find expected content type in message body", 332 strMessageBody.indexOf(strSentContent) != -1); 333 } 334 335 /** 336 * Validate the message was sent properly 337 * @param mailServer reference to the fake mail server 338 * @param strSubject expected subject 339 * @param strMessage the expected message as a string 340 * @param fromAdd expected from address 341 * @param toAdd list of expected to addresses 342 * @param ccAdd list of expected cc addresses 343 * @param bccAdd list of expected bcc addresses 344 * @param boolSaveToFile true will output to file, false doesnt 345 * @throws IOException Exception 346 */ 347 protected void validateSend( 348 Wiser mailServer, 349 String strSubject, 350 String strMessage, 351 InternetAddress fromAdd, 352 List toAdd, 353 List ccAdd, 354 List bccAdd, 355 boolean boolSaveToFile) 356 throws IOException 357 { 358 // test other properties 359 WiserMessage emailMessage = this.validateSend( 360 mailServer, 361 strSubject, 362 fromAdd, 363 toAdd, 364 ccAdd, 365 bccAdd, 366 true); 367 368 // test message content 369 assertTrue("didn't find expected message content in message body", 370 getMessageBody(emailMessage).indexOf(strMessage) != -1); 371 } 372 373 /** 374 * Serializes the {@link MimeMessage} from the <code>WiserMessage</code> 375 * passed in. The headers are serialized first followed by the message 376 * body. 377 * 378 * @param email The <code>WiserMessage</code> to serialize. 379 * @return The string format of the message. 380 * @throws MessagingException 381 * @throws IOException 382 * Thrown while serializing the body from 383 * {@link DataHandler#writeTo(java.io.OutputStream)}. 384 * @throws MessagingException 385 * Thrown while getting the body content from 386 * {@link MimeMessage#getDataHandler()} 387 * @since 1.1 388 */ 389 private String serializeEmailMessage(WiserMessage wiserMessage) 390 throws MessagingException, IOException 391 { 392 if (wiserMessage == null) 393 { 394 return ""; 395 } 396 397 StringBuffer serializedEmail = new StringBuffer(); 398 MimeMessage message = wiserMessage.getMimeMessage(); 399 400 // Serialize the headers 401 for (Enumeration headers = message.getAllHeaders(); headers 402 .hasMoreElements();) 403 { 404 Header header = (Header) headers.nextElement(); 405 serializedEmail.append(header.getName()); 406 serializedEmail.append(": "); 407 serializedEmail.append(header.getValue()); 408 serializedEmail.append(LINE_SEPARATOR); 409 } 410 411 // Serialize the body 412 byte[] messageBody = getMessageBodyBytes(message); 413 414 serializedEmail.append(LINE_SEPARATOR); 415 serializedEmail.append(messageBody); 416 serializedEmail.append(LINE_SEPARATOR); 417 418 return serializedEmail.toString(); 419 } 420 421 /** 422 * Returns a string representation of the message body. If the message body 423 * cannot be read, an empty string is returned. 424 * 425 * @param wiserMessage The wiser message from which to extract the message body 426 * @return The string representation of the message body 427 * @throws IOException 428 * Thrown while serializing the body from 429 * {@link DataHandler#writeTo(java.io.OutputStream)}. 430 * @since 1.1 431 */ 432 private String getMessageBody(WiserMessage wiserMessage) 433 throws IOException 434 { 435 if (wiserMessage == null) 436 { 437 return ""; 438 } 439 440 byte[] messageBody = null; 441 442 try 443 { 444 MimeMessage message = wiserMessage.getMimeMessage(); 445 messageBody = getMessageBodyBytes(message); 446 } 447 catch (MessagingException me) 448 { 449 // Thrown while getting the body content from 450 // {@link MimeMessage#getDataHandler()} 451 IllegalStateException ise = 452 new IllegalStateException("couldn't process MimeMessage from WiserMessage in getMessageBody()"); 453 ise.initCause(me); 454 throw ise; 455 } 456 457 return (messageBody != null) ? (new String(messageBody).intern()) : ""; 458 } 459 460 /** 461 * Gets the byte making up the body of the message. 462 * 463 * @param mimeMessage 464 * The mime message from which to extract the body. 465 * @return A byte array representing the message body 466 * @throws IOException 467 * Thrown while serializing the body from 468 * {@link DataHandler#writeTo(java.io.OutputStream)}. 469 * @throws MessagingException 470 * Thrown while getting the body content from 471 * {@link MimeMessage#getDataHandler()} 472 * @since 1.1 473 */ 474 private byte[] getMessageBodyBytes(MimeMessage mimeMessage) 475 throws IOException, MessagingException 476 { 477 DataHandler dataHandler = mimeMessage.getDataHandler(); 478 ByteArrayOutputStream byteArrayOutStream = new ByteArrayOutputStream(); 479 BufferedOutputStream buffOs = new BufferedOutputStream( 480 byteArrayOutStream); 481 dataHandler.writeTo(buffOs); 482 buffOs.flush(); 483 484 return byteArrayOutStream.toByteArray(); 485 } 486 487 /** 488 * Checks if an email server is running at the address stored in the 489 * <code>fakeMailServer</code>. 490 * 491 * @param fakeMailServer 492 * The server from which the address is picked up. 493 * @return <code>true</code> if the server claims to be running 494 * @since 1.1 495 */ 496 protected boolean isMailServerStopped(Wiser fakeMailServer) { 497 return !fakeMailServer.getServer().isRunning(); 498 } 499 }