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: */
018:
019: package org.apache.tools.mail;
020:
021: import java.io.BufferedReader;
022: import java.io.BufferedWriter;
023: import java.io.ByteArrayOutputStream;
024: import java.io.IOException;
025: import java.io.InputStreamReader;
026: import java.io.OutputStreamWriter;
027: import java.io.PrintStream;
028: import java.net.InetAddress;
029: import java.net.Socket;
030: import java.net.ServerSocket;
031: import java.util.Enumeration;
032: import java.util.Vector;
033:
034: import org.apache.tools.mail.MailMessage;
035:
036: import junit.framework.TestCase;
037:
038: /**
039: * JUnit 3 testcases for org.apache.tools.mail.MailMessage.
040: *
041: * @since Ant 1.6
042: */
043: public class MailMessageTest extends TestCase {
044:
045: // 27224 = magic (a random port which is unlikely to be in use)
046: private static int TEST_PORT = 27224;
047:
048: private String local = null;
049:
050: public MailMessageTest(String name) {
051: super (name);
052: }
053:
054: public void setUp() {
055: try {
056: local = InetAddress.getLocalHost().getHostName();
057: } catch (java.net.UnknownHostException uhe) {
058: // ignore
059: }
060: }
061:
062: /**
063: * Test an example that is similar to the one given in the API
064: * If this testcase takes >90s to complete, it is very likely that
065: * the two threads are blocked waiting for each other and Thread.join()
066: * timed out.
067: */
068: public void testAPIExample() {
069:
070: ServerThread testMailServer = new ServerThread();
071: Thread server = new Thread(testMailServer);
072: server.start();
073:
074: ClientThread testMailClient = new ClientThread();
075:
076: testMailClient
077: .from("Mail Message <EmailTaskTest@ant.apache.org>");
078: testMailClient.to("to@you.com");
079: testMailClient.cc("cc1@you.com");
080: testMailClient.cc("cc2@you.com");
081: testMailClient.bcc("bcc@you.com");
082: testMailClient.setSubject("Test subject");
083: testMailClient.setMessage("test line 1\n" + "test line 2");
084:
085: Thread client = new Thread(testMailClient);
086: client.start();
087:
088: try {
089: server.join(60 * 1000); // 60s
090: client.join(30 * 1000); // a further 30s
091: } catch (InterruptedException ie) {
092: fail("InterruptedException: " + ie);
093: }
094:
095: String result = testMailServer.getResult();
096: String expectedResult = "220 test SMTP EmailTaskTest\r\n"
097: + "HELO "
098: + local
099: + "\r\n"
100: + "250 "
101: + local
102: + " Hello "
103: + local
104: + " [127.0.0.1], pleased to meet you\r\n"
105: + "MAIL FROM: <EmailTaskTest@ant.apache.org>\r\n"
106: + "250\r\n"
107: + "RCPT TO: <to@you.com>\r\n"
108: + "250\r\n"
109: + "RCPT TO: <cc1@you.com>\r\n"
110: + "250\r\n"
111: + "RCPT TO: <cc2@you.com>\r\n"
112: + "250\r\n"
113: + "RCPT TO: <bcc@you.com>\r\n"
114: + "250\r\n"
115: + "DATA\r\n"
116: + "354\r\n"
117: + "Subject: Test subject\r\n"
118: + "From: Mail Message <EmailTaskTest@ant.apache.org>\r\n"
119: + "To: to@you.com\r\n"
120: + "Cc: cc1@you.com, cc2@you.com\r\n"
121: + "X-Mailer: org.apache.tools.mail.MailMessage (ant.apache.org)\r\n"
122: + "\r\n"
123: + "test line 1\r\n"
124: + "test line 2\r\n"
125: + "\r\n" + ".\r\n" + "250\r\n" + "QUIT\r\n" + "221\r\n";
126: for (int icounter = 0; icounter < expectedResult.length(); icounter++) {
127: if (icounter < result.length()) {
128: if (expectedResult.charAt(icounter) != result
129: .charAt(icounter)) {
130: System.out.println("posit " + icounter
131: + " expected "
132: + expectedResult.charAt(icounter)
133: + " result " + result.charAt(icounter));
134: }
135: }
136: }
137: if (expectedResult.length() > result.length()) {
138: System.out.println("excedent of expected result "
139: + expectedResult.substring(result.length()));
140: }
141: if (expectedResult.length() < result.length()) {
142: System.out.println("excedent of result "
143: + result.substring(expectedResult.length()));
144: }
145: assertEquals(expectedResult.length(), result.length());
146: assertEquals(expectedResult, result); // order of headers cannot be guaranteed
147: if (testMailClient.isFailed()) {
148: fail(testMailClient.getFailMessage());
149: }
150: }
151:
152: /**
153: * Test a MailMessage with no cc or bcc lines
154: */
155: public void testToOnly() {
156: ServerThread testMailServer = new ServerThread();
157: Thread server = new Thread(testMailServer);
158: server.start();
159:
160: ClientThread testMailClient = new ClientThread();
161:
162: testMailClient
163: .from("Mail Message <EmailTaskTest@ant.apache.org>");
164: testMailClient.to("to@you.com");
165: testMailClient.setSubject("Test subject");
166: testMailClient.setMessage("test line 1\n" + "test line 2");
167:
168: Thread client = new Thread(testMailClient);
169: client.start();
170:
171: try {
172: server.join(60 * 1000); // 60s
173: client.join(30 * 1000); // a further 30s
174: } catch (InterruptedException ie) {
175: fail("InterruptedException: " + ie);
176: }
177:
178: String result = testMailServer.getResult();
179: String expectedResult = "220 test SMTP EmailTaskTest\r\n"
180: + "HELO "
181: + local
182: + "\r\n"
183: + "250 "
184: + local
185: + " Hello "
186: + local
187: + " [127.0.0.1], pleased to meet you\r\n"
188: + "MAIL FROM: <EmailTaskTest@ant.apache.org>\r\n"
189: + "250\r\n"
190: + "RCPT TO: <to@you.com>\r\n"
191: + "250\r\n"
192: + "DATA\r\n"
193: + "354\r\n"
194: + "Subject: Test subject\r\n"
195: + "From: Mail Message <EmailTaskTest@ant.apache.org>\r\n"
196: + "To: to@you.com\r\n"
197: + "X-Mailer: org.apache.tools.mail.MailMessage (ant.apache.org)\r\n"
198: + "\r\n"
199: + "test line 1\r\n"
200: + "test line 2\r\n"
201: + "\r\n" + ".\r\n" + "250\r\n" + "QUIT\r\n" + "221\r\n";
202: assertEquals(expectedResult.length(), result.length());
203: assertEquals(expectedResult, result); // order of headers cannot be guaranteed
204: if (testMailClient.isFailed()) {
205: fail(testMailClient.getFailMessage());
206: }
207: }
208:
209: /**
210: * Test a MailMessage with no to or bcc lines
211: */
212: public void testCcOnly() {
213: ServerThread testMailServer = new ServerThread();
214: Thread server = new Thread(testMailServer);
215: server.start();
216:
217: ClientThread testMailClient = new ClientThread();
218:
219: testMailClient
220: .from("Mail Message <EmailTaskTest@ant.apache.org>");
221: testMailClient.cc("cc@you.com");
222: testMailClient.setSubject("Test subject");
223: testMailClient.setMessage("test line 1\n" + "test line 2");
224:
225: Thread client = new Thread(testMailClient);
226: client.start();
227:
228: try {
229: server.join(60 * 1000); // 60s
230: client.join(30 * 1000); // a further 30s
231: } catch (InterruptedException ie) {
232: fail("InterruptedException: " + ie);
233: }
234:
235: String result = testMailServer.getResult();
236: String expectedResult = "220 test SMTP EmailTaskTest\r\n"
237: + "HELO "
238: + local
239: + "\r\n"
240: + "250 "
241: + local
242: + " Hello "
243: + local
244: + " [127.0.0.1], pleased to meet you\r\n"
245: + "MAIL FROM: <EmailTaskTest@ant.apache.org>\r\n"
246: + "250\r\n"
247: + "RCPT TO: <cc@you.com>\r\n"
248: + "250\r\n"
249: + "DATA\r\n"
250: + "354\r\n"
251: + "Subject: Test subject\r\n"
252: + "From: Mail Message <EmailTaskTest@ant.apache.org>\r\n"
253: + "Cc: cc@you.com\r\n"
254: + "X-Mailer: org.apache.tools.mail.MailMessage (ant.apache.org)\r\n"
255: + "\r\n"
256: + "test line 1\r\n"
257: + "test line 2\r\n"
258: + "\r\n" + ".\r\n" + "250\r\n" + "QUIT\r\n" + "221\r\n";
259: assertEquals(expectedResult.length(), result.length());
260: assertEquals(expectedResult, result);
261: if (testMailClient.isFailed()) {
262: fail(testMailClient.getFailMessage());
263: }
264: }
265:
266: /**
267: * Test a MailMessage with no to or cc lines
268: */
269: public void testBccOnly() {
270: ServerThread testMailServer = new ServerThread();
271: Thread server = new Thread(testMailServer);
272: server.start();
273:
274: ClientThread testMailClient = new ClientThread();
275:
276: testMailClient
277: .from("Mail Message <EmailTaskTest@ant.apache.org>");
278: testMailClient.bcc("bcc@you.com");
279: testMailClient.setSubject("Test subject");
280: testMailClient.setMessage("test line 1\n" + "test line 2");
281:
282: Thread client = new Thread(testMailClient);
283: client.start();
284:
285: try {
286: server.join(60 * 1000); // 60s
287: client.join(30 * 1000); // a further 30s
288: } catch (InterruptedException ie) {
289: fail("InterruptedException: " + ie);
290: }
291:
292: String result = testMailServer.getResult();
293: String expectedResult = "220 test SMTP EmailTaskTest\r\n"
294: + "HELO "
295: + local
296: + "\r\n"
297: + "250 "
298: + local
299: + " Hello "
300: + local
301: + " [127.0.0.1], pleased to meet you\r\n"
302: + "MAIL FROM: <EmailTaskTest@ant.apache.org>\r\n"
303: + "250\r\n"
304: + "RCPT TO: <bcc@you.com>\r\n"
305: + "250\r\n"
306: + "DATA\r\n"
307: + "354\r\n"
308: + "Subject: Test subject\r\n"
309: + "From: Mail Message <EmailTaskTest@ant.apache.org>\r\n"
310: + "X-Mailer: org.apache.tools.mail.MailMessage (ant.apache.org)\r\n"
311: + "\r\n"
312: + "test line 1\r\n"
313: + "test line 2\r\n"
314: + "\r\n" + ".\r\n" + "250\r\n" + "QUIT\r\n" + "221\r\n";
315: assertEquals(expectedResult.length(), result.length());
316: assertEquals(expectedResult, result);
317: if (testMailClient.isFailed()) {
318: fail(testMailClient.getFailMessage());
319: }
320: }
321:
322: /**
323: * Test a MailMessage with no subject line
324: * Subject is an optional field (RFC 822 s4.1)
325: */
326: public void testNoSubject() {
327: ServerThread testMailServer = new ServerThread();
328: Thread server = new Thread(testMailServer);
329: server.start();
330:
331: ClientThread testMailClient = new ClientThread();
332:
333: testMailClient
334: .from("Mail Message <EmailTaskTest@ant.apache.org>");
335: testMailClient.to("to@you.com");
336: testMailClient.setMessage("test line 1\n" + "test line 2");
337:
338: Thread client = new Thread(testMailClient);
339: client.start();
340:
341: try {
342: server.join(60 * 1000); // 60s
343: client.join(30 * 1000); // a further 30s
344: } catch (InterruptedException ie) {
345: fail("InterruptedException: " + ie);
346: }
347:
348: String result = testMailServer.getResult();
349: String expectedResult = "220 test SMTP EmailTaskTest\r\n"
350: + "HELO "
351: + local
352: + "\r\n"
353: + "250 "
354: + local
355: + " Hello "
356: + local
357: + " [127.0.0.1], pleased to meet you\r\n"
358: + "MAIL FROM: <EmailTaskTest@ant.apache.org>\r\n"
359: + "250\r\n"
360: + "RCPT TO: <to@you.com>\r\n"
361: + "250\r\n"
362: + "DATA\r\n"
363: + "354\r\n"
364: + "From: Mail Message <EmailTaskTest@ant.apache.org>\r\n"
365: + "To: to@you.com\r\n"
366: + "X-Mailer: org.apache.tools.mail.MailMessage (ant.apache.org)\r\n"
367: + "\r\n"
368: + "test line 1\r\n"
369: + "test line 2\r\n"
370: + "\r\n" + ".\r\n" + "250\r\n" + "QUIT\r\n" + "221\r\n";
371: assertEquals(expectedResult.length(), result.length());
372: assertEquals(expectedResult, result);
373: if (testMailClient.isFailed()) {
374: fail(testMailClient.getFailMessage());
375: }
376: }
377:
378: /**
379: * Test a MailMessage with empty body message
380: */
381: public void testEmptyBody() {
382: ServerThread testMailServer = new ServerThread();
383: Thread server = new Thread(testMailServer);
384: server.start();
385:
386: ClientThread testMailClient = new ClientThread();
387:
388: testMailClient
389: .from("Mail Message <EmailTaskTest@ant.apache.org>");
390: testMailClient.to("to@you.com");
391: testMailClient.setSubject("Test subject");
392: testMailClient.setMessage("");
393:
394: Thread client = new Thread(testMailClient);
395: client.start();
396:
397: try {
398: server.join(60 * 1000); // 60s
399: client.join(30 * 1000); // a further 30s
400: } catch (InterruptedException ie) {
401: fail("InterruptedException: " + ie);
402: }
403:
404: String result = testMailServer.getResult();
405: String expectedResult = "220 test SMTP EmailTaskTest\r\n"
406: + "HELO "
407: + local
408: + "\r\n"
409: + "250 "
410: + local
411: + " Hello "
412: + local
413: + " [127.0.0.1], pleased to meet you\r\n"
414: + "MAIL FROM: <EmailTaskTest@ant.apache.org>\r\n"
415: + "250\r\n"
416: + "RCPT TO: <to@you.com>\r\n"
417: + "250\r\n"
418: + "DATA\r\n"
419: + "354\r\n"
420: + "Subject: Test subject\r\n"
421: + "From: Mail Message <EmailTaskTest@ant.apache.org>\r\n"
422: + "To: to@you.com\r\n"
423: + "X-Mailer: org.apache.tools.mail.MailMessage (ant.apache.org)\r\n"
424: + "\r\n"
425: + "\r\n"
426: + "\r\n"
427: + ".\r\n"
428: + "250\r\n"
429: + "QUIT\r\n" + "221\r\n";
430: assertEquals(expectedResult.length(), result.length());
431: assertEquals(expectedResult, result);
432: if (testMailClient.isFailed()) {
433: fail(testMailClient.getFailMessage());
434: }
435: }
436:
437: /**
438: * Test a MailMessage with US-ASCII character set
439: * The next four testcase can be kinda hard to debug as Ant will often
440: * print the junit failure in US-ASCII.
441: */
442: public void testAsciiCharset() {
443:
444: ServerThread testMailServer = new ServerThread();
445: Thread server = new Thread(testMailServer);
446: server.start();
447:
448: ClientThread testMailClient = new ClientThread();
449:
450: testMailClient
451: .from("Mail Message <EmailTaskTest@ant.apache.org>");
452: testMailClient
453: .to("Ceki G\u00fclc\u00fc <abuse@mail-abuse.org>");
454: testMailClient.setSubject("Test subject");
455: testMailClient.setMessage("");
456:
457: Thread client = new Thread(testMailClient);
458: client.start();
459:
460: try {
461: server.join(60 * 1000); // 60s
462: client.join(30 * 1000); // a further 30s
463: } catch (InterruptedException ie) {
464: fail("InterruptedException: " + ie);
465: }
466:
467: String result = testMailServer.getResult();
468: String expectedResult = "220 test SMTP EmailTaskTest\r\n"
469: + "HELO "
470: + local
471: + "\r\n"
472: + "250 "
473: + local
474: + " Hello "
475: + local
476: + " [127.0.0.1], pleased to meet you\r\n"
477: + "MAIL FROM: <EmailTaskTest@ant.apache.org>\r\n"
478: + "250\r\n"
479: + "RCPT TO: <abuse@mail-abuse.org>\r\n"
480: + "250\r\n"
481: + "DATA\r\n"
482: + "354\r\n"
483: + "Subject: Test subject\r\n"
484: + "From: Mail Message <EmailTaskTest@ant.apache.org>\r\n"
485: + "To: Ceki G\u00fclc\u00fc <abuse@mail-abuse.org>\r\n"
486: + "X-Mailer: org.apache.tools.mail.MailMessage (ant.apache.org)\r\n"
487: + "\r\n"
488: + "\r\n"
489: + "\r\n"
490: + ".\r\n"
491: + "250\r\n"
492: + "QUIT\r\n" + "221\r\n";
493: ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
494: ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
495: PrintStream bos1 = new PrintStream(baos1, true);
496: PrintStream bos2 = new PrintStream(baos2, true);
497:
498: bos1.print(expectedResult);
499: bos2.print(result);
500:
501: assertEquals(
502: "expected message length != actual message length "
503: + "in testAsciiCharset()", expectedResult
504: .length(), result.length());
505: assertEquals(
506: "baos1 and baos2 should be the same in testAsciiCharset()",
507: baos1.toString(), baos2.toString()); // order of headers cannot be guaranteed
508: if (testMailClient.isFailed()) {
509: fail(testMailClient.getFailMessage());
510: }
511: }
512:
513: /**
514: * A private test class that pretends to be a mail transfer agent
515: */
516: private class ServerThread implements Runnable {
517:
518: private StringBuffer sb = null;
519: private boolean loop = false;
520: ServerSocket ssock = null;
521: Socket sock = null;
522: BufferedWriter out = null;
523: BufferedReader in = null;
524: private boolean data = false; // state engine: false=envelope, true=message
525:
526: public void run() {
527:
528: try {
529: ssock = new ServerSocket(TEST_PORT);
530: sock = ssock.accept(); // wait for connection
531: in = new BufferedReader(new InputStreamReader(sock
532: .getInputStream()));
533: out = new BufferedWriter(new OutputStreamWriter(sock
534: .getOutputStream()));
535: sb = new StringBuffer();
536: send("220 test SMTP EmailTaskTest\r\n");
537: loop = true;
538: while (loop) {
539: String response = in.readLine();
540: if (response == null) {
541: loop = false;
542: break;
543: }
544: sb.append(response + "\r\n");
545:
546: if (!data && response.startsWith("HELO")) {
547: send("250 "
548: + local
549: + " Hello "
550: + local
551: + " "
552: + "[127.0.0.1], pleased to meet you\r\n");
553: } else if (!data && response.startsWith("MAIL")) {
554: send("250\r\n");
555: } else if (!data && response.startsWith("RCPT")) {
556: send("250\r\n");
557: } else if (!data && response.startsWith("DATA")) {
558: send("354\r\n");
559: data = true;
560: } else if (data && response.equals(".")) {
561: send("250\r\n");
562: data = false;
563: } else if (!data && response.startsWith("QUIT")) {
564: send("221\r\n");
565: loop = false;
566: } else if (!data) {
567: //throw new IllegalStateException("Command unrecognized: "
568: // + response);
569: send("500 5.5.1 Command unrecognized: \""
570: + response + "\"\r\n");
571: loop = false;
572: } else {
573: // sb.append( response + "\r\n" );
574: }
575:
576: } // while
577: } catch (IOException ioe) {
578: fail();
579: } finally {
580: disconnect();
581: }
582: }
583:
584: private void send(String retmsg) throws IOException {
585: out.write(retmsg);
586: out.flush();
587: sb.append(retmsg);
588: }
589:
590: private void disconnect() {
591: if (out != null) {
592: try {
593: out.flush();
594: out.close();
595: out = null;
596: } catch (IOException e) {
597: // ignore
598: }
599: }
600: if (in != null) {
601: try {
602: in.close();
603: in = null;
604: } catch (IOException e) {
605: // ignore
606: }
607: }
608: if (sock != null) {
609: try {
610: sock.close();
611: sock = null;
612: } catch (IOException e) {
613: // ignore
614: }
615: }
616: if (ssock != null) {
617: try {
618: ssock.close();
619: ssock = null;
620: } catch (IOException e) {
621: // ignore
622: }
623: }
624: }
625:
626: public synchronized String getResult() {
627: loop = false;
628: return sb.toString();
629: }
630:
631: }
632:
633: /**
634: * A private test class that wraps MailMessage
635: */
636: private class ClientThread implements Runnable {
637:
638: private MailMessage msg;
639: private boolean fail = false;
640: private String failMessage = null;
641:
642: protected String from = null;
643: protected String subject = null;
644: protected String message = null;
645:
646: protected Vector replyToList = new Vector();
647: protected Vector toList = new Vector();
648: protected Vector ccList = new Vector();
649: protected Vector bccList = new Vector();
650:
651: public void run() {
652: for (int i = 9; i > 0; i--) {
653: try {
654: msg = new MailMessage("localhost", TEST_PORT);
655: } catch (java.net.ConnectException ce) {
656: try {
657: Thread.sleep(10 * 1000);
658: } catch (InterruptedException ie) {
659: // ignore
660: }
661: } catch (IOException ioe) {
662: fail = true;
663: failMessage = "IOException: " + ioe;
664: return;
665: }
666: if (msg != null) {
667: break;
668: }
669: }
670:
671: if (msg == null) {
672: fail = true;
673: failMessage = "java.net.ConnectException: Connection refused";
674: return;
675: }
676:
677: try {
678: msg.from(from);
679:
680: Enumeration e;
681:
682: e = replyToList.elements();
683: while (e.hasMoreElements()) {
684: msg.replyto(e.nextElement().toString());
685: }
686:
687: e = toList.elements();
688: while (e.hasMoreElements()) {
689: msg.to(e.nextElement().toString());
690: }
691:
692: e = ccList.elements();
693: while (e.hasMoreElements()) {
694: msg.cc(e.nextElement().toString());
695: }
696:
697: e = bccList.elements();
698: while (e.hasMoreElements()) {
699: msg.bcc(e.nextElement().toString());
700: }
701:
702: if (subject != null) {
703: msg.setSubject(subject);
704: }
705:
706: if (message != null) {
707: PrintStream out = msg.getPrintStream();
708: out.println(message);
709: }
710:
711: msg.sendAndClose();
712: } catch (IOException ioe) {
713: fail = true;
714: failMessage = "IOException: " + ioe;
715: return;
716: }
717: }
718:
719: public boolean isFailed() {
720: return fail;
721: }
722:
723: public String getFailMessage() {
724: return failMessage;
725: }
726:
727: public void replyTo(String replyTo) {
728: replyToList.add(replyTo);
729: }
730:
731: public void to(String to) {
732: toList.add(to);
733: }
734:
735: public void cc(String cc) {
736: ccList.add(cc);
737: }
738:
739: public void bcc(String bcc) {
740: bccList.add(bcc);
741: }
742:
743: public void setSubject(String subject) {
744: this .subject = subject;
745: }
746:
747: public void from(String from) {
748: this .from = from;
749: }
750:
751: public void setMessage(String message) {
752: this.message = message;
753: }
754:
755: }
756:
757: }
|