diff --git a/src/etc/testcases/taskdefs/email/mail.xml b/src/etc/testcases/taskdefs/email/mail.xml index c56fd4037..5144b7a0e 100644 --- a/src/etc/testcases/taskdefs/email/mail.xml +++ b/src/etc/testcases/taskdefs/email/mail.xml @@ -20,7 +20,7 @@ - + Hi Laura, how are you doing ? @@ -28,7 +28,7 @@ - + Hi Laura, how are you doing ? @@ -36,5 +36,9 @@ - + + + + + diff --git a/src/tests/junit/org/apache/tools/ant/DummyMailServer.java b/src/tests/junit/org/apache/tools/ant/DummyMailServer.java new file mode 100644 index 000000000..160528eba --- /dev/null +++ b/src/tests/junit/org/apache/tools/ant/DummyMailServer.java @@ -0,0 +1,201 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.tools.ant; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.concurrent.Callable; + +/** + * A utility class that pretends to be a mail transfer agent. This + * has minimal functionality and is meant to be used only in tests + */ +public class DummyMailServer implements Runnable, Callable { + + private final String host; + private final int port; + + + private StringBuilder sb = null; + private volatile boolean stop = false; + + ServerSocket ssock = null; + Socket sock = null; + BufferedWriter out = null; + BufferedReader in = null; + private boolean data = false; // state engine: false=envelope, true=message + + public DummyMailServer(int port) { + this("localhost", port); + } + + public DummyMailServer(final String host, final int port) { + this.host = host; + this.port = port; + } + + public int getPort() { + return this.port; + } + + public String getHost() { + return this.host; + } + + @Override + public void run() { + call(); + } + + @Override + public Void call() { + + try { + ssock = new ServerSocket(port); + sock = ssock.accept(); // wait for connection + in = new BufferedReader(new InputStreamReader( + sock.getInputStream())); + out = new BufferedWriter(new OutputStreamWriter( + sock.getOutputStream())); + sb = new StringBuilder(); + send("220 test SMTP EmailTaskTest\r\n"); + while (!stop) { + String response = in.readLine(); + if (response == null) { + stop = true; + break; + } + sb.append(response).append("\r\n"); + + if (!data && response.startsWith("EHLO")) { + // reject Extended HLO semantics, since we don't support it + send("500 EHLO unsupported\r\n"); + } else if (!data && response.startsWith("HELO")) { + send("250 " + host + " Hello " + host + " " + + "[127.0.0.1], pleased to meet you\r\n"); + } else if (!data && response.startsWith("MAIL")) { + send("250\r\n"); + } else if (!data && response.startsWith("RCPT")) { + send("250\r\n"); + } else if (!data && response.startsWith("DATA")) { + send("354\r\n"); + data = true; + } else if (data && response.equals(".")) { + send("250\r\n"); + data = false; + } else if (!data && response.startsWith("QUIT")) { + send("221\r\n"); + stop = true; + } else if (!data) { + send("500 5.5.1 Command unrecognized: \"" + + response + "\"\r\n"); + stop = true; + } else { + // sb.append(response + "\r\n"); + } + } // while + } catch (IOException ioe) { + if (stop) { + // asked to stop, so ignore the exception and move on + return null; + } + throw new BuildException(ioe); + } finally { + disconnect(); + } + return null; + } + + private void send(String retmsg) throws IOException { + out.write(retmsg); + out.flush(); + sb.append(retmsg); + } + + public void disconnect() { + this.stop = true; + if (out != null) { + try { + out.flush(); + out.close(); + out = null; + } catch (IOException e) { + // ignore + } + } + if (in != null) { + try { + in.close(); + in = null; + } catch (IOException e) { + // ignore + } + } + if (sock != null) { + try { + sock.close(); + sock = null; + } catch (IOException e) { + // ignore + } + } + if (ssock != null) { + try { + ssock.close(); + ssock = null; + } catch (IOException e) { + // ignore + } + } + } + + public synchronized String getResult() { + this.stop = true; + return sb.toString(); + } + + /** + * Starts and returns a new dummy mail server to be used in tests + * + * @return + */ + public static DummyMailServer startMailServer() { + return startMailServer("localhost"); + } + + /** + * Starts and returns a new dummy mail server to be used in tests + * + * @param host The host on which the mail server will open a server socket to listen on + * @return + */ + public static DummyMailServer startMailServer(final String host) { + final int port = TestHelper.getMaybeAvailablePort(); + final DummyMailServer mailServer = new DummyMailServer(host, port); + final Thread thread = new Thread(mailServer); + thread.setDaemon(true); + thread.start(); + return mailServer; + } +} diff --git a/src/tests/junit/org/apache/tools/ant/TestHelper.java b/src/tests/junit/org/apache/tools/ant/TestHelper.java new file mode 100644 index 000000000..f36dd4693 --- /dev/null +++ b/src/tests/junit/org/apache/tools/ant/TestHelper.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.tools.ant; + +import java.io.IOException; +import java.net.ServerSocket; + +/** + * As the name suggests, utility class used in tests + */ +public class TestHelper { + + /** + * Find a TCP/IP port which may continue to be available. + *
+ * The returned port is available since a socket has successfully bind to it, but this availability is not ensured + * after this method since the associated socket is released and some other process can now use it. + */ + public static int getMaybeAvailablePort() { + final ServerSocket s; + try { + s = new ServerSocket(0); + s.setReuseAddress(true); + int port = s.getLocalPort(); + try { + s.close(); + } catch (IOException e) { + // ignore + } + return port; + } catch (IOException e) { + // ignore + } finally { + + } + throw new IllegalStateException("No TCP/IP port available"); + } +} diff --git a/src/tests/junit/org/apache/tools/ant/taskdefs/email/EmailTaskTest.java b/src/tests/junit/org/apache/tools/ant/taskdefs/email/EmailTaskTest.java index 6363f90d0..a77fc92db 100644 --- a/src/tests/junit/org/apache/tools/ant/taskdefs/email/EmailTaskTest.java +++ b/src/tests/junit/org/apache/tools/ant/taskdefs/email/EmailTaskTest.java @@ -20,12 +20,12 @@ package org.apache.tools.ant.taskdefs.email; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.BuildFileRule; +import org.apache.tools.ant.DummyMailServer; +import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import static org.junit.Assert.fail; - /** * TODO : develop these testcases - the email task needs to have attributes allowing * to simulate sending mail and to catch the output in text files or streams @@ -40,24 +40,51 @@ public class EmailTaskTest { buildRule.configureProject("src/etc/testcases/taskdefs/email/mail.xml"); } + /** + * Expected failure attempting SMTP auth without MIME + */ @Test public void test1() { try { buildRule.executeTarget("test1"); - fail("Build exception expected: SMTP auth only possibly with MIME mail"); - } catch(BuildException ex) { - //TODO assert exception message + } catch (BuildException e) { + // assert it's the expected one + if (!e.getMessage().equals("SMTP auth only possible with MIME mail")) { + throw e; + } } } + /** + * Expected failure attempting SSL without MIME + */ @Test public void test2() { try { buildRule.executeTarget("test2"); - fail("Build exception expected: SSL only possibly with MIME mail"); - } catch(BuildException ex) { - //TODO assert exception message + } catch (BuildException e) { + // assert it's the expected one + if (!e.getMessage().equals("SSL and STARTTLS only possible with MIME mail")) { + throw e; + } } } + /** + * Tests that a basic email sending works + */ + @Test + public void test3() { + final DummyMailServer mailServer = DummyMailServer.startMailServer(); + try { + buildRule.getProject().setProperty("EmailTaskTest.test3.port", String.valueOf(mailServer.getPort())); + buildRule.executeTarget("test3"); + } finally { + mailServer.disconnect(); + } + final String smtpInteraction = mailServer.getResult(); + Assert.assertNotNull("No mail received by mail server", smtpInteraction); + // just a basic check + Assert.assertTrue("Unexpected recipients on the sent mail", smtpInteraction.contains("RCPT TO:")); + } } diff --git a/src/tests/junit/org/apache/tools/mail/MailMessageTest.java b/src/tests/junit/org/apache/tools/mail/MailMessageTest.java index f61e6b4e8..ee7a05cc4 100644 --- a/src/tests/junit/org/apache/tools/mail/MailMessageTest.java +++ b/src/tests/junit/org/apache/tools/mail/MailMessageTest.java @@ -18,24 +18,18 @@ package org.apache.tools.mail; -import java.io.BufferedReader; -import java.io.BufferedWriter; +import org.apache.tools.ant.DummyMailServer; +import org.junit.AssumptionViolatedException; +import org.junit.Before; +import org.junit.Test; + import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; import java.io.PrintStream; import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; import java.util.Enumeration; import java.util.Vector; -import org.apache.tools.ant.BuildException; -import org.junit.Before; -import org.junit.Test; -import org.junit.internal.AssumptionViolatedException; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -46,9 +40,6 @@ import static org.junit.Assert.assertFalse; */ public class MailMessageTest { - // 27224 = magic (a random port which is unlikely to be in use) - private static int TEST_PORT = 27224; - private String local = null; @Before @@ -69,28 +60,27 @@ public class MailMessageTest { */ @Test public void testAPIExample() throws InterruptedException { - final int port = TEST_PORT + 1; - ServerThread testMailServer = new ServerThread(port); - Thread server = new Thread(testMailServer); - server.start(); - - ClientThread testMailClient = new ClientThread(port); - - testMailClient.from("Mail Message "); - testMailClient.to("to@you.com"); - testMailClient.cc("cc1@you.com"); - testMailClient.cc("cc2@you.com"); - testMailClient.bcc("bcc@you.com"); - testMailClient.setSubject("Test subject"); - testMailClient.setMessage("test line 1\n" - + "test line 2"); - - Thread client = new Thread(testMailClient); - client.start(); - - server.join(60 * 1000); // 60s - client.join(30 * 1000); // a further 30s - + final DummyMailServer testMailServer = DummyMailServer.startMailServer(this.local); + final ClientThread testMailClient; + try { + testMailClient = new ClientThread(testMailServer.getPort()); + + testMailClient.from("Mail Message "); + testMailClient.to("to@you.com"); + testMailClient.cc("cc1@you.com"); + testMailClient.cc("cc2@you.com"); + testMailClient.bcc("bcc@you.com"); + testMailClient.setSubject("Test subject"); + testMailClient.setMessage("test line 1\n" + + "test line 2"); + + Thread client = new Thread(testMailClient); + client.start(); + client.join(30 * 1000); // a further 30s + + } finally { + testMailServer.disconnect(); + } String result = testMailServer.getResult(); String expectedResult = "220 test SMTP EmailTaskTest\r\n" + "HELO " + local + "\r\n" @@ -129,23 +119,23 @@ public class MailMessageTest { */ @Test public void testToOnly() throws InterruptedException { - final int port = TEST_PORT + 2; - ServerThread testMailServer = new ServerThread(port); - Thread server = new Thread(testMailServer); - server.start(); - - ClientThread testMailClient = new ClientThread(port); + final DummyMailServer testMailServer = DummyMailServer.startMailServer(this.local); + final ClientThread testMailClient; + try { + testMailClient = new ClientThread(testMailServer.getPort()); - testMailClient.from("Mail Message "); - testMailClient.to("to@you.com"); - testMailClient.setSubject("Test subject"); - testMailClient.setMessage("test line 1\n" + "test line 2"); + testMailClient.from("Mail Message "); + testMailClient.to("to@you.com"); + testMailClient.setSubject("Test subject"); + testMailClient.setMessage("test line 1\n" + "test line 2"); - Thread client = new Thread(testMailClient); - client.start(); + Thread client = new Thread(testMailClient); + client.start(); - server.join(60 * 1000); // 60s - client.join(30 * 1000); // a further 30s + client.join(30 * 1000); // a further 30s + } finally { + testMailServer.disconnect(); + } String result = testMailServer.getResult(); String expectedResult = "220 test SMTP EmailTaskTest\r\n" @@ -179,23 +169,22 @@ public class MailMessageTest { */ @Test public void testCcOnly() throws InterruptedException { - final int port = TEST_PORT + 3; - ServerThread testMailServer = new ServerThread(port); - Thread server = new Thread(testMailServer); - server.start(); - - ClientThread testMailClient = new ClientThread(port); - - testMailClient.from("Mail Message "); - testMailClient.cc("cc@you.com"); - testMailClient.setSubject("Test subject"); - testMailClient.setMessage("test line 1\n" + "test line 2"); - - Thread client = new Thread(testMailClient); - client.start(); - - server.join(60 * 1000); // 60s - client.join(30 * 1000); // a further 30s + final DummyMailServer testMailServer = DummyMailServer.startMailServer(this.local); + final ClientThread testMailClient; + try { + testMailClient = new ClientThread(testMailServer.getPort()); + testMailClient.from("Mail Message "); + testMailClient.cc("cc@you.com"); + testMailClient.setSubject("Test subject"); + testMailClient.setMessage("test line 1\n" + "test line 2"); + + Thread client = new Thread(testMailClient); + client.start(); + + client.join(30 * 1000); // a further 30s + } finally { + testMailServer.disconnect(); + } String result = testMailServer.getResult(); String expectedResult = "220 test SMTP EmailTaskTest\r\n" @@ -229,23 +218,21 @@ public class MailMessageTest { */ @Test public void testBccOnly() throws InterruptedException { - final int port = TEST_PORT + 4; - ServerThread testMailServer = new ServerThread(port); - Thread server = new Thread(testMailServer); - server.start(); - - ClientThread testMailClient = new ClientThread(port); - - testMailClient.from("Mail Message "); - testMailClient.bcc("bcc@you.com"); - testMailClient.setSubject("Test subject"); - testMailClient.setMessage("test line 1\n" + "test line 2"); - - Thread client = new Thread(testMailClient); - client.start(); - - server.join(60 * 1000); // 60s - client.join(30 * 1000); // a further 30s + final DummyMailServer testMailServer = DummyMailServer.startMailServer(this.local); + final ClientThread testMailClient; + try { + testMailClient = new ClientThread(testMailServer.getPort()); + testMailClient.from("Mail Message "); + testMailClient.bcc("bcc@you.com"); + testMailClient.setSubject("Test subject"); + testMailClient.setMessage("test line 1\n" + "test line 2"); + + Thread client = new Thread(testMailClient); + client.start(); + client.join(30 * 1000); // a further 30s + } finally { + testMailServer.disconnect(); + } String result = testMailServer.getResult(); String expectedResult = "220 test SMTP EmailTaskTest\r\n" @@ -279,22 +266,22 @@ public class MailMessageTest { */ @Test public void testNoSubject() throws InterruptedException { - final int port = TEST_PORT + 5; - ServerThread testMailServer = new ServerThread(port); - Thread server = new Thread(testMailServer); - server.start(); - - ClientThread testMailClient = new ClientThread(port); + final DummyMailServer testMailServer = DummyMailServer.startMailServer(this.local); + final ClientThread testMailClient; - testMailClient.from("Mail Message "); - testMailClient.to("to@you.com"); - testMailClient.setMessage("test line 1\n" + "test line 2"); + try { + testMailClient = new ClientThread(testMailServer.getPort()); + testMailClient.from("Mail Message "); + testMailClient.to("to@you.com"); + testMailClient.setMessage("test line 1\n" + "test line 2"); - Thread client = new Thread(testMailClient); - client.start(); + Thread client = new Thread(testMailClient); + client.start(); - server.join(60 * 1000); // 60s - client.join(30 * 1000); // a further 30s + client.join(30 * 1000); // a further 30s + } finally { + testMailServer.disconnect(); + } String result = testMailServer.getResult(); String expectedResult = "220 test SMTP EmailTaskTest\r\n" @@ -327,23 +314,22 @@ public class MailMessageTest { */ @Test public void testEmptyBody() throws InterruptedException { - final int port = TEST_PORT + 6; - ServerThread testMailServer = new ServerThread(port); - Thread server = new Thread(testMailServer); - server.start(); - - ClientThread testMailClient = new ClientThread(port); - - testMailClient.from("Mail Message "); - testMailClient.to("to@you.com"); - testMailClient.setSubject("Test subject"); - testMailClient.setMessage(""); - - Thread client = new Thread(testMailClient); - client.start(); - - server.join(60 * 1000); // 60s - client.join(30 * 1000); // a further 30s + final DummyMailServer testMailServer = DummyMailServer.startMailServer(this.local); + final ClientThread testMailClient; + try { + testMailClient = new ClientThread(testMailServer.getPort()); + testMailClient.from("Mail Message "); + testMailClient.to("to@you.com"); + testMailClient.setSubject("Test subject"); + testMailClient.setMessage(""); + + Thread client = new Thread(testMailClient); + client.start(); + + client.join(30 * 1000); // a further 30s + } finally { + testMailServer.disconnect(); + } String result = testMailServer.getResult(); String expectedResult = "220 test SMTP EmailTaskTest\r\n" @@ -378,23 +364,23 @@ public class MailMessageTest { */ @Test public void testAsciiCharset() throws InterruptedException { - final int port = TEST_PORT + 7; - ServerThread testMailServer = new ServerThread(port); - Thread server = new Thread(testMailServer); - server.start(); - - ClientThread testMailClient = new ClientThread(port); - - testMailClient.from("Mail Message "); - testMailClient.to("Ceki G\u00fclc\u00fc "); - testMailClient.setSubject("Test subject"); - testMailClient.setMessage(""); + final DummyMailServer testMailServer = DummyMailServer.startMailServer(this.local); + final ClientThread testMailClient; - Thread client = new Thread(testMailClient); - client.start(); - - server.join(60 * 1000); // 60s - client.join(30 * 1000); // a further 30s + try { + testMailClient = new ClientThread(testMailServer.getPort()); + testMailClient.from("Mail Message "); + testMailClient.to("Ceki G\u00fclc\u00fc "); + testMailClient.setSubject("Test subject"); + testMailClient.setMessage(""); + + Thread client = new Thread(testMailClient); + client.start(); + + client.join(30 * 1000); // a further 30s + } finally { + testMailServer.disconnect(); + } String result = testMailServer.getResult(); String expectedResult = "220 test SMTP EmailTaskTest\r\n" @@ -430,127 +416,6 @@ public class MailMessageTest { assertFalse(testMailClient.getFailMessage(), testMailClient.isFailed()); } - - /** - * A private test class that pretends to be a mail transfer agent - */ - private class ServerThread implements Runnable { - - private final int port; - private StringBuilder sb = null; - private boolean loop = false; - ServerSocket ssock = null; - Socket sock = null; - BufferedWriter out = null; - BufferedReader in = null; - private boolean data = false; // state engine: false=envelope, true=message - - ServerThread(int port) { - this.port = port; - } - - public void run() { - - try { - ssock = new ServerSocket(port); - sock = ssock.accept(); // wait for connection - in = new BufferedReader(new InputStreamReader( - sock.getInputStream())); - out = new BufferedWriter(new OutputStreamWriter( - sock.getOutputStream())); - sb = new StringBuilder(); - send("220 test SMTP EmailTaskTest\r\n"); - loop = true; - while (loop) { - String response = in.readLine(); - if (response == null) { - loop = false; - break; - } - sb.append(response).append("\r\n"); - - if (!data && response.startsWith("HELO")) { - send("250 " + local + " Hello " + local + " " - + "[127.0.0.1], pleased to meet you\r\n"); - } else if (!data && response.startsWith("MAIL")) { - send("250\r\n"); - } else if (!data && response.startsWith("RCPT")) { - send("250\r\n"); - } else if (!data && response.startsWith("DATA")) { - send("354\r\n"); - data = true; - } else if (data && response.equals(".")) { - send("250\r\n"); - data = false; - } else if (!data && response.startsWith("QUIT")) { - send("221\r\n"); - loop = false; - } else if (!data) { - //throw new IllegalStateException("Command unrecognized: " - // + response); - send("500 5.5.1 Command unrecognized: \"" - + response + "\"\r\n"); - loop = false; - } else { - // sb.append(response + "\r\n"); - } - } // while - } catch (IOException ioe) { - throw new BuildException(ioe); - } finally { - disconnect(); - } - } - - private void send(String retmsg) throws IOException { - out.write(retmsg); - out.flush(); - sb.append(retmsg); - } - - private void disconnect() { - if (out != null) { - try { - out.flush(); - out.close(); - out = null; - } catch (IOException e) { - // ignore - } - } - if (in != null) { - try { - in.close(); - in = null; - } catch (IOException e) { - // ignore - } - } - if (sock != null) { - try { - sock.close(); - sock = null; - } catch (IOException e) { - // ignore - } - } - if (ssock != null) { - try { - ssock.close(); - ssock = null; - } catch (IOException e) { - // ignore - } - } - } - - public synchronized String getResult() { - loop = false; - return sb.toString(); - } - - } - /** * A private test class that wraps MailMessage */