http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliverySocketFactory.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliverySocketFactory.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliverySocketFactory.java deleted file mode 100644 index d4a5ba5..0000000 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/RemoteDeliverySocketFactory.java +++ /dev/null @@ -1,138 +0,0 @@ -/**************************************************************** - * 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.james.transport.mailets.remoteDelivery; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.UnknownHostException; - -import javax.net.SocketFactory; - -/** - * <p> - * It is used by RemoteDelivery in order to make possible to bind the client - * socket to a specific ip address. - * </p> - * <p> - * This is not a nice solution because the ip address must be shared by all - * RemoteDelivery instances. It would be better to modify JavaMail (current - * version 1.3) to support a corresonding property, e.g. mail.smtp.bindAdress. - * </p> - * <p> - * This used to not extend javax.net.SocketFactory descendant, because - * <ol> - * <li> - * it was not necessary because JavaMail 1.2 uses reflection when accessing this - * class;</li> - * <li> - * it was not desirable because it would require java 1.4.</li> - * </ol> - * </p> - * <p> - * But since James 2.3.0a1: - * <ol> - * <li>we require Java 1.4 so the dependency on SocketFactory is not really an - * issue;</li> - * <li>Javamail 1.4 cast the object returned by getDefault to SocketFactory and - * fails to create the socket if we don't extend SocketFactory.</li> - * </ol> - * </p> - * <p> - * <strong>Note</strong>: Javamail 1.4 should correctly support - * mail.smtp.localaddr so we could probably get rid of this class and simply add - * that property to the Session. - * </p> - */ -public class RemoteDeliverySocketFactory extends SocketFactory { - - /** - * @param addr - * the ip address or host name the delivery socket will bind to - */ - public static void setBindAdress(String addr) throws UnknownHostException { - if (addr == null) { - bindAddress = null; - } else { - bindAddress = InetAddress.getByName(addr); - } - } - - /** - * the same as the similarly named javax.net.SocketFactory operation. - */ - public static SocketFactory getDefault() { - return new RemoteDeliverySocketFactory(); - } - - /** - * the same as the similarly named javax.net.SocketFactory operation. Just - * to be safe, it is not used by JavaMail 1.3. This is the only method used - * by JavaMail 1.4. - */ - public Socket createSocket() throws IOException { - Socket s = new Socket(); - s.bind(new InetSocketAddress(bindAddress, 0)); - return s; - } - - /** - * the same as the similarly named javax.net.SocketFactory operation. This - * is the one which is used by JavaMail 1.3. This is not used by JavaMail - * 1.4. - */ - public Socket createSocket(String host, int port) throws IOException { - return new Socket(host, port, bindAddress, 0); - } - - /** - * the same as the similarly named javax.net.SocketFactory operation. Just - * to be safe, it is not used by JavaMail 1.3. This is not used by JavaMail - * 1.4. - */ - public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException { - return new Socket(host, port, clientHost == null ? bindAddress : clientHost, clientPort); - } - - /** - * the same as the similarly named javax.net.SocketFactory operation. Just - * to be safe, it is not used by JavaMail 1.3. This is not used by JavaMail - * 1.4. - */ - public Socket createSocket(InetAddress host, int port) throws IOException { - return new Socket(host, port, bindAddress, 0); - } - - /** - * the same as the similarly named javax.net.SocketFactory operation. Just - * to be safe, it is not used by JavaMail 1.3. This is not used by JavaMail - * 1.4. - */ - public Socket createSocket(InetAddress address, int port, InetAddress clientAddress, int clientPort) throws IOException { - return new Socket(address, port, clientAddress == null ? bindAddress : clientAddress, clientPort); - } - - /** - * it should be set by setBindAdress(). Null means the socket is bind to the - * default address. - */ - private static InetAddress bindAddress; -}
http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Repeat.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Repeat.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Repeat.java deleted file mode 100644 index 5c26342..0000000 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Repeat.java +++ /dev/null @@ -1,38 +0,0 @@ -/**************************************************************** - * 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.james.transport.mailets.remoteDelivery; - -import java.util.List; - -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; - -public class Repeat { - - @SuppressWarnings("unchecked") - public static <T> List<T> repeat(T element, int times) { - Preconditions.checkArgument(times >= 0, "Times argument should be strictly positive"); - return ImmutableList.copyOf( - Iterables.limit( - Iterables.cycle(element), times)); - } - -} http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/AddressesArrayToMailAddressListConverterTest.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/AddressesArrayToMailAddressListConverterTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/AddressesArrayToMailAddressListConverterTest.java new file mode 100644 index 0000000..b54f940 --- /dev/null +++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/AddressesArrayToMailAddressListConverterTest.java @@ -0,0 +1,67 @@ +/**************************************************************** + * 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.james.transport.mailets.remote.delivery; + +import static org.assertj.core.api.Assertions.assertThat; + +import javax.mail.Address; +import javax.mail.internet.InternetAddress; + +import org.apache.james.transport.mailets.remote.delivery.AddressesArrayToMailAddressListConverter; +import org.apache.mailet.base.MailAddressFixture; +import org.junit.Test; + +public class AddressesArrayToMailAddressListConverterTest { + + private static final String WRONG_INTERNET_ADDRESS = "!!"; + + @Test + public void getAddressesAsMailAddressShouldReturnEmptyOnNull() { + assertThat(AddressesArrayToMailAddressListConverter.getAddressesAsMailAddress(null)).isEmpty(); + } + + @Test + public void getAddressesAsMailAddressShouldReturnEmptyOnEmpty() { + assertThat(AddressesArrayToMailAddressListConverter.getAddressesAsMailAddress(new Address[]{})).isEmpty(); + } + + @Test + public void getAddressesAsMailAddressShouldWorkWithSingleValue() throws Exception { + assertThat(AddressesArrayToMailAddressListConverter.getAddressesAsMailAddress(new Address[]{ + new InternetAddress(MailAddressFixture.ANY_AT_JAMES.toString())})) + .containsOnly(MailAddressFixture.ANY_AT_JAMES); + } + + @Test + public void getAddressesAsMailAddressShouldWorkWithTwoValues() throws Exception { + assertThat(AddressesArrayToMailAddressListConverter.getAddressesAsMailAddress(new Address[]{ + new InternetAddress(MailAddressFixture.ANY_AT_JAMES.toString()), + new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.toString())})) + .containsOnly(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES); + } + + @Test + public void getAddressesAsMailAddressShouldFilterErrorMailAddress() throws Exception { + assertThat(AddressesArrayToMailAddressListConverter.getAddressesAsMailAddress(new Address[]{ + new InternetAddress(MailAddressFixture.ANY_AT_JAMES.toString()), + new InternetAddress(WRONG_INTERNET_ADDRESS)})) + .containsOnly(MailAddressFixture.ANY_AT_JAMES); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/BouncerTest.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/BouncerTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/BouncerTest.java new file mode 100644 index 0000000..4bac706 --- /dev/null +++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/BouncerTest.java @@ -0,0 +1,456 @@ +/**************************************************************** + * 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.james.transport.mailets.remote.delivery; + +import static org.apache.james.transport.mailets.remote.delivery.Bouncer.DELIVERY_ERROR; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +import java.net.ConnectException; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.Optional; + +import javax.mail.MessagingException; +import javax.mail.SendFailedException; + +import org.apache.james.domainlist.api.DomainList; +import org.apache.james.transport.mailets.remote.delivery.Bouncer; +import org.apache.james.transport.mailets.remote.delivery.RemoteDeliveryConfiguration; +import org.apache.mailet.Mail; +import org.apache.mailet.base.MailAddressFixture; +import org.apache.mailet.base.test.FakeMail; +import org.apache.mailet.base.test.FakeMailContext; +import org.apache.mailet.base.test.FakeMailetConfig; +import org.junit.Before; +import org.junit.Test; + +public class BouncerTest { + public static final String HELLO_NAME = "hello_name"; + public static final String BOUNCE_PROCESSOR = "bounce_processor"; + + private FakeMailContext mailetContext; + + @Before + public void setUp() { + mailetContext = FakeMailContext.defaultContext(); + } + + @Test + public void bounceShouldCallMailetContextBounceByDefault() throws Exception { + RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration( + FakeMailetConfig.builder() + .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1") + .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME) + .build(), + mock(DomainList.class)); + Bouncer testee = new Bouncer(configuration, mailetContext); + + Mail mail = FakeMail.builder().state(Mail.DEFAULT) + .sender(MailAddressFixture.ANY_AT_JAMES) + .build(); + testee.bounce(mail, new Exception("Exception message")); + + FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail), + "Hi. This is the James mail server at " + HELLO_NAME + ".\n" + + "I'm afraid I wasn't able to deliver your message to the following addresses.\n" + + "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" + + "I include the list of recipients and the reason why I was unable to deliver\n" + + "your message.\n\n\n", + Optional.empty()); + assertThat(mailetContext.getSentMails()).isEmpty(); + assertThat(mailetContext.getBouncedMails()).containsOnly(expected); + } + + @Test + public void bounceShouldIncludeMessagingExceptionMessageByDefault() throws Exception { + RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration( + FakeMailetConfig.builder() + .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1") + .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME) + .build(), + mock(DomainList.class)); + Bouncer testee = new Bouncer(configuration, mailetContext); + + Mail mail = FakeMail.builder().state(Mail.DEFAULT) + .sender(MailAddressFixture.ANY_AT_JAMES) + .build(); + String exceptionMessage = "Exception message"; + testee.bounce(mail, new MessagingException(exceptionMessage)); + + FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail), + "Hi. This is the James mail server at " + HELLO_NAME + ".\n" + + "I'm afraid I wasn't able to deliver your message to the following addresses.\n" + + "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" + + "I include the list of recipients and the reason why I was unable to deliver\n" + + "your message.\n" + + "\n" + + exceptionMessage + "\n\n", + Optional.empty()); + assertThat(mailetContext.getSentMails()).isEmpty(); + assertThat(mailetContext.getBouncedMails()).containsOnly(expected); + } + + @Test + public void bounceShouldCustomizeSendFailedExceptionByDefault() throws Exception { + RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration( + FakeMailetConfig.builder() + .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1") + .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME) + .build(), + mock(DomainList.class)); + Bouncer testee = new Bouncer(configuration, mailetContext); + + Mail mail = FakeMail.builder().state(Mail.DEFAULT) + .sender(MailAddressFixture.ANY_AT_JAMES) + .build(); + String exceptionMessage = "Error from remote server"; + testee.bounce(mail, new MessagingException("Exception message", new SendFailedException(exceptionMessage))); + + FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail), + "Hi. This is the James mail server at " + HELLO_NAME + ".\n" + + "I'm afraid I wasn't able to deliver your message to the following addresses.\n" + + "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" + + "I include the list of recipients and the reason why I was unable to deliver\n" + + "your message.\n" + + "\n" + + "Remote mail server told me: " + exceptionMessage + "\n\n", + Optional.empty()); + assertThat(mailetContext.getSentMails()).isEmpty(); + assertThat(mailetContext.getBouncedMails()).containsOnly(expected); + } + + @Test + public void bounceShouldCustomizeUnknownHostExceptionByDefault() throws Exception { + RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration( + FakeMailetConfig.builder() + .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1") + .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME) + .build(), + mock(DomainList.class)); + Bouncer testee = new Bouncer(configuration, mailetContext); + + Mail mail = FakeMail.builder().state(Mail.DEFAULT) + .sender(MailAddressFixture.ANY_AT_JAMES) + .build(); + String exceptionMessage = "I don't know him"; + testee.bounce(mail, new MessagingException("Exception message", new UnknownHostException(exceptionMessage))); + + FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail), + "Hi. This is the James mail server at " + HELLO_NAME + ".\n" + + "I'm afraid I wasn't able to deliver your message to the following addresses.\n" + + "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" + + "I include the list of recipients and the reason why I was unable to deliver\n" + + "your message.\n" + + "\n" + + "Unknown host: " + exceptionMessage + "\n" + + "This could be a DNS server error, a typo, or a problem with the recipient's mail server.\n\n", + Optional.empty()); + assertThat(mailetContext.getSentMails()).isEmpty(); + assertThat(mailetContext.getBouncedMails()).containsOnly(expected); + } + + @Test + public void bounceShouldCustomizeConnectionExceptionByDefault() throws Exception { + RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration( + FakeMailetConfig.builder() + .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1") + .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME) + .build(), + mock(DomainList.class)); + Bouncer testee = new Bouncer(configuration, mailetContext); + + Mail mail = FakeMail.builder().state(Mail.DEFAULT) + .sender(MailAddressFixture.ANY_AT_JAMES) + .build(); + String exceptionMessage = "Can not connect"; + testee.bounce(mail, new MessagingException("Exception message", new ConnectException(exceptionMessage))); + + FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail), + "Hi. This is the James mail server at " + HELLO_NAME + ".\n" + + "I'm afraid I wasn't able to deliver your message to the following addresses.\n" + + "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" + + "I include the list of recipients and the reason why I was unable to deliver\n" + + "your message.\n" + + "\n" + + exceptionMessage + "\n\n", + Optional.empty()); + assertThat(mailetContext.getSentMails()).isEmpty(); + assertThat(mailetContext.getBouncedMails()).containsOnly(expected); + } + + @Test + public void bounceShouldCustomizeSocketExceptionByDefault() throws Exception { + RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration( + FakeMailetConfig.builder() + .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1") + .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME) + .build(), + mock(DomainList.class)); + Bouncer testee = new Bouncer(configuration, mailetContext); + + Mail mail = FakeMail.builder().state(Mail.DEFAULT) + .sender(MailAddressFixture.ANY_AT_JAMES) + .build(); + String exceptionMessage = "Can not connect"; + testee.bounce(mail, new MessagingException("Exception message", new SocketException(exceptionMessage))); + + FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail), + "Hi. This is the James mail server at " + HELLO_NAME + ".\n" + + "I'm afraid I wasn't able to deliver your message to the following addresses.\n" + + "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" + + "I include the list of recipients and the reason why I was unable to deliver\n" + + "your message.\n" + + "\n" + + "Socket exception: " + exceptionMessage + "\n\n", + Optional.empty()); + assertThat(mailetContext.getSentMails()).isEmpty(); + assertThat(mailetContext.getBouncedMails()).containsOnly(expected); + } + + @Test + public void bounceShouldCustomizeNestedMessagingExceptionByDefault() throws Exception { + RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration( + FakeMailetConfig.builder() + .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1") + .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME) + .build(), + mock(DomainList.class)); + Bouncer testee = new Bouncer(configuration, mailetContext); + + Mail mail = FakeMail.builder().state(Mail.DEFAULT) + .sender(MailAddressFixture.ANY_AT_JAMES) + .build(); + String exceptionMessage = "Can not connect"; + testee.bounce(mail, new MessagingException("Exception message", new MessagingException(exceptionMessage))); + + FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail), + "Hi. This is the James mail server at " + HELLO_NAME + ".\n" + + "I'm afraid I wasn't able to deliver your message to the following addresses.\n" + + "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" + + "I include the list of recipients and the reason why I was unable to deliver\n" + + "your message.\n" + + "\n" + + exceptionMessage + "\n\n", + Optional.empty()); + assertThat(mailetContext.getSentMails()).isEmpty(); + assertThat(mailetContext.getBouncedMails()).containsOnly(expected); + } + + @Test + public void bounceShouldNotBounceWithNoSenderByDefault() throws Exception { + RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration( + FakeMailetConfig.builder() + .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1") + .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME) + .build(), + mock(DomainList.class)); + Bouncer testee = new Bouncer(configuration, mailetContext); + + Mail mail = FakeMail.builder().state(Mail.DEFAULT) + .build(); + String exceptionMessage = "Can not connect"; + testee.bounce(mail, new MessagingException("Exception message", new ConnectException(exceptionMessage))); + + assertThat(mailetContext.getSentMails()).isEmpty(); + assertThat(mailetContext.getBouncedMails()).isEmpty(); + } + + @Test + public void bounceShouldSupportExceptionWithoutMessagesByDefault() throws Exception { + RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration( + FakeMailetConfig.builder() + .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1") + .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME) + .build(), + mock(DomainList.class)); + Bouncer testee = new Bouncer(configuration, mailetContext); + + Mail mail = FakeMail.builder().state(Mail.DEFAULT) + .sender(MailAddressFixture.ANY_AT_JAMES) + .build(); + testee.bounce(mail, new Exception("Exception message")); + + FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail), + "Hi. This is the James mail server at " + HELLO_NAME + ".\n" + + "I'm afraid I wasn't able to deliver your message to the following addresses.\n" + + "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" + + "I include the list of recipients and the reason why I was unable to deliver\n" + + "your message.\n\n\n", + Optional.empty()); + assertThat(mailetContext.getSentMails()).isEmpty(); + assertThat(mailetContext.getBouncedMails()).containsOnly(expected); + } + + @Test + public void bounceShouldNotSupportMessagingExceptionWithoutMessagesByDefault() throws Exception { + RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration( + FakeMailetConfig.builder() + .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1") + .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME) + .build(), + mock(DomainList.class)); + Bouncer testee = new Bouncer(configuration, mailetContext); + + Mail mail = FakeMail.builder().state(Mail.DEFAULT) + .sender(MailAddressFixture.ANY_AT_JAMES) + .build(); + testee.bounce(mail, new MessagingException()); + + FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail), + "Hi. This is the James mail server at " + HELLO_NAME + ".\n" + + "I'm afraid I wasn't able to deliver your message to the following addresses.\n" + + "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" + + "I include the list of recipients and the reason why I was unable to deliver\n" + + "your message.\n\nnull\n\n", + Optional.empty()); + assertThat(mailetContext.getSentMails()).isEmpty(); + assertThat(mailetContext.getBouncedMails()).containsOnly(expected); + } + + @Test + public void bounceShouldWorkWhenProcessorSpecified() throws Exception { + RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration( + FakeMailetConfig.builder() + .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1") + .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME) + .setProperty(RemoteDeliveryConfiguration.BOUNCE_PROCESSOR, BOUNCE_PROCESSOR) + .build(), + mock(DomainList.class)); + Bouncer testee = new Bouncer(configuration, mailetContext); + + Mail mail = FakeMail.builder().state(Mail.DEFAULT) + .sender(MailAddressFixture.ANY_AT_JAMES) + .build(); + String errorMessage = "message"; + testee.bounce(mail, new MessagingException(errorMessage)); + + FakeMailContext.SentMail expected = FakeMailContext.sentMailBuilder() + .sender(MailAddressFixture.ANY_AT_JAMES) + .attribute(DELIVERY_ERROR, errorMessage) + .state(BOUNCE_PROCESSOR) + .fromMailet() + .build(); + assertThat(mailetContext.getSentMails()).containsOnly(expected); + assertThat(mailetContext.getBouncedMails()).isEmpty(); + } + + @Test + public void bounceShouldNotBounceWhenNoSenderWhenProcessorSpecified() throws Exception { + RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration( + FakeMailetConfig.builder() + .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1") + .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME) + .setProperty(RemoteDeliveryConfiguration.BOUNCE_PROCESSOR, BOUNCE_PROCESSOR) + .build(), + mock(DomainList.class)); + Bouncer testee = new Bouncer(configuration, mailetContext); + + Mail mail = FakeMail.builder().state(Mail.DEFAULT) + .build(); + testee.bounce(mail, new MessagingException("message")); + + assertThat(mailetContext.getSentMails()).isEmpty(); + assertThat(mailetContext.getBouncedMails()).isEmpty(); + } + + @Test + public void bounceShouldDisplayAddressByDefault() throws Exception { + RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration( + FakeMailetConfig.builder() + .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1") + .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME) + .build(), + mock(DomainList.class)); + Bouncer testee = new Bouncer(configuration, mailetContext); + + Mail mail = FakeMail.builder().state(Mail.DEFAULT) + .sender(MailAddressFixture.ANY_AT_JAMES) + .recipient(MailAddressFixture.ANY_AT_JAMES2) + .build(); + testee.bounce(mail, new Exception("Exception message")); + + FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail), + "Hi. This is the James mail server at " + HELLO_NAME + ".\n" + + "I'm afraid I wasn't able to deliver your message to the following addresses.\n" + + "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" + + "I include the list of recipients and the reason why I was unable to deliver\n" + + "your message.\n\n" + + MailAddressFixture.ANY_AT_JAMES2.asString() + "\n\n", + Optional.empty()); + assertThat(mailetContext.getSentMails()).isEmpty(); + assertThat(mailetContext.getBouncedMails()).containsOnly(expected); + } + + @Test + public void bounceShouldDisplayAddressesByDefault() throws Exception { + RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration( + FakeMailetConfig.builder() + .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1") + .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME) + .build(), + mock(DomainList.class)); + Bouncer testee = new Bouncer(configuration, mailetContext); + + Mail mail = FakeMail.builder().state(Mail.DEFAULT) + .sender(MailAddressFixture.ANY_AT_JAMES) + .recipients(MailAddressFixture.ANY_AT_JAMES2, MailAddressFixture.OTHER_AT_JAMES2) + .build(); + testee.bounce(mail, new Exception("Exception message")); + + FakeMailContext.BouncedMail expected = new FakeMailContext.BouncedMail(FakeMailContext.fromMail(mail), + "Hi. This is the James mail server at " + HELLO_NAME + ".\n" + + "I'm afraid I wasn't able to deliver your message to the following addresses.\n" + + "This is a permanent error; I've given up. Sorry it didn't work out. Below\n" + + "I include the list of recipients and the reason why I was unable to deliver\n" + + "your message.\n\n" + + MailAddressFixture.ANY_AT_JAMES2.asString() + "\n" + + MailAddressFixture.OTHER_AT_JAMES2.asString() + "\n\n", + Optional.empty()); + assertThat(mailetContext.getSentMails()).isEmpty(); + assertThat(mailetContext.getBouncedMails()).containsOnly(expected); + } + + @Test + public void bounceShouldWorkWhenProcessorSpecifiedAndNoExceptionMessage() throws Exception { + RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration( + FakeMailetConfig.builder() + .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1") + .setProperty(RemoteDeliveryConfiguration.HELO_NAME, HELLO_NAME) + .setProperty(RemoteDeliveryConfiguration.BOUNCE_PROCESSOR, BOUNCE_PROCESSOR) + .build(), + mock(DomainList.class)); + Bouncer testee = new Bouncer(configuration, mailetContext); + + Mail mail = FakeMail.builder().state(Mail.DEFAULT) + .sender(MailAddressFixture.ANY_AT_JAMES) + .build(); + testee.bounce(mail, new MessagingException()); + + FakeMailContext.SentMail expected = FakeMailContext.sentMailBuilder() + .sender(MailAddressFixture.ANY_AT_JAMES) + .attribute(DELIVERY_ERROR, "null") + .state(BOUNCE_PROCESSOR) + .fromMailet() + .build(); + assertThat(mailetContext.getSentMails()).containsOnly(expected); + assertThat(mailetContext.getBouncedMails()).isEmpty(); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DelayTest.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DelayTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DelayTest.java new file mode 100644 index 0000000..3d55634 --- /dev/null +++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DelayTest.java @@ -0,0 +1,124 @@ +/**************************************************************** + * 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.james.transport.mailets.remote.delivery; + +import static org.assertj.core.api.Assertions.assertThat; + +import javax.mail.MessagingException; + +import org.apache.james.transport.mailets.remote.delivery.Delay; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class DelayTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Test + public void defaultConstructorShouldConstructDefaultDelay() { + assertThat(new Delay()) + .isEqualTo(new Delay(Delay.DEFAULT_ATTEMPTS, Delay.DEFAULT_DELAY_TIME)); + } + + @Test + public void stringConstructorShouldWorkForNumbers() throws Exception { + assertThat(Delay.from("36")).isEqualTo(new Delay(Delay.DEFAULT_ATTEMPTS, 36)); + } + + @Test + public void stringConstructorShouldWorkForZero() throws Exception { + assertThat(Delay.from("0")).isEqualTo(new Delay(Delay.DEFAULT_ATTEMPTS, 0)); + } + + @Test + public void stringConstructorShouldThrowOnNegativeNumbers() throws Exception { + expectedException.expect(NumberFormatException.class); + assertThat(Delay.from("-1s")).isEqualTo(new Delay(Delay.DEFAULT_ATTEMPTS, 0)); + } + + @Test + public void stringConstructorShouldWorkForNumberAndSecond() throws Exception { + assertThat(Delay.from("1s")).isEqualTo(new Delay(Delay.DEFAULT_ATTEMPTS, 1000)); + } + + @Test + public void stringConstructorShouldWorkForNumberAndAttempts() throws Exception { + assertThat(Delay.from("2*36")).isEqualTo(new Delay(2, 36)); + } + + @Test + public void stringConstructorShouldWorkForNumberAndZeroAttempts() throws Exception { + assertThat(Delay.from("0*36")).isEqualTo(new Delay(0, 36)); + } + + @Test + public void stringConstructorShouldThrowOnNegativeAttempts() throws Exception { + expectedException.expect(MessagingException.class); + + Delay.from("-1*36"); + } + + @Test + public void stringConstructorShouldThrowWhenAttemptsOmitted() throws Exception { + expectedException.expect(NumberFormatException.class); + + Delay.from("*36"); + } + + @Test + public void stringConstructorShouldThrowWhenDelayOmitted() throws Exception { + expectedException.expect(NumberFormatException.class); + + Delay.from("2*"); + } + + @Test + public void stringConstructorShouldWorkForNumberAttemptsAndUnit() throws Exception { + assertThat(Delay.from("2*36s")).isEqualTo(new Delay(2, 36000)); + } + + @Test + public void stringConstructorShouldWorkForNumberAttemptsAndUnitWithSpaces() throws Exception { + assertThat(Delay.from("2 * 36 s")).isEqualTo(new Delay(2, 36000)); + } + + @Test + public void stringConstructorShouldThrowOnInvalidInput() throws Exception { + expectedException.expect(NumberFormatException.class); + + Delay.from("invalid"); + } + + @Test + public void stringConstructorShouldThrowOnInvalidUnit() throws Exception { + expectedException.expect(NumberFormatException.class); + + Delay.from("36invalid"); + } + + @Test + public void stringConstructorShouldThrowOnEmptyString() throws Exception { + expectedException.expect(NumberFormatException.class); + + Delay.from(""); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DelaysAndMaxRetryTest.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DelaysAndMaxRetryTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DelaysAndMaxRetryTest.java new file mode 100644 index 0000000..7fb1895 --- /dev/null +++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DelaysAndMaxRetryTest.java @@ -0,0 +1,145 @@ +/**************************************************************** + * 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.james.transport.mailets.remote.delivery; + +import static org.assertj.core.api.Assertions.assertThat; + +import javax.mail.MessagingException; + +import org.apache.james.transport.mailets.remote.delivery.Delay; +import org.apache.james.transport.mailets.remote.delivery.DelaysAndMaxRetry; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import com.google.common.collect.ImmutableList; + +public class DelaysAndMaxRetryTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Test + public void fromShouldParseSingleDelay() throws Exception { + DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(1, "1s"); + + DelaysAndMaxRetry expected = new DelaysAndMaxRetry(1, ImmutableList.of(new Delay(1, 1000))); + + assertThat(actual).isEqualTo(expected); + } + + @Test + public void fromShouldParseTwoDelays() throws Exception { + DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(2, "1s,2s"); + + DelaysAndMaxRetry expected = new DelaysAndMaxRetry(2, ImmutableList.of(new Delay(1, 1000), new Delay(1, 2000))); + + assertThat(actual).isEqualTo(expected); + } + + @Test + public void fromShouldAdaptMaxRetriesWhenUnderAttempts() throws Exception { + DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(1, "1s,2*2s"); + + DelaysAndMaxRetry expected = new DelaysAndMaxRetry(3, ImmutableList.of(new Delay(1, 1000), new Delay(2, 2000))); + + assertThat(actual).isEqualTo(expected); + } + + @Test + public void fromShouldAdaptDelaysWhenUnderMaxRetries() throws Exception { + DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(4, "1s,2*2s"); + + DelaysAndMaxRetry expected = new DelaysAndMaxRetry(4, ImmutableList.of(new Delay(1, 1000), new Delay(3, 2000))); + + assertThat(actual).isEqualTo(expected); + } + + @Test + public void fromShouldHandleNullValuesForDelayAsString() throws Exception { + DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(1, null); + + DelaysAndMaxRetry expected = new DelaysAndMaxRetry(1, ImmutableList.of(new Delay(Delay.DEFAULT_ATTEMPTS, Delay.DEFAULT_DELAY_TIME))); + + assertThat(actual).isEqualTo(expected); + } + + @Test + public void fromShouldIgnoreEmptyDelay() throws Exception { + DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(1, "1s,,2s"); + + DelaysAndMaxRetry expected = new DelaysAndMaxRetry(2, ImmutableList.of(new Delay(1, 1000), new Delay(1, 2000))); + + assertThat(actual).isEqualTo(expected); + } + + @Test + public void fromShouldHandleParsingFailures() throws Exception { + DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(3, "1s,invalid,2s"); + + DelaysAndMaxRetry expected = new DelaysAndMaxRetry(3, ImmutableList.of(new Delay(3, 1000))); + + assertThat(actual).isEqualTo(expected); + } + + @Test + public void fromShouldHandleEmptyStringWithZeroMaxRetries() throws Exception { + DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(0, ""); + + DelaysAndMaxRetry expected = new DelaysAndMaxRetry(0, ImmutableList.<Delay>of()); + + assertThat(actual).isEqualTo(expected); + } + + @Test + public void fromShouldThrowOnEmptyStringWithNonZeroMaxRetry() throws Exception { + expectedException.expect(MessagingException.class); + + DelaysAndMaxRetry.from(2, ""); + } + + @Test + public void getExpandedDelaysShouldReturnEmptyWhenNoDelay() throws Exception { + DelaysAndMaxRetry testee = DelaysAndMaxRetry.from(0, ""); + + assertThat(testee.getExpandedDelays()).isEmpty(); + } + + @Test + public void getExpandedDelaysShouldExpandSingleDelays() throws Exception { + DelaysAndMaxRetry testee = DelaysAndMaxRetry.from(3, "1*1S,1*2S,1*5S"); + + assertThat(testee.getExpandedDelays()).containsExactly(1000L, 2000L, 5000L); + } + + @Test + public void getExpandedDelaysShouldExpandMultipleDelays() throws Exception { + DelaysAndMaxRetry testee = DelaysAndMaxRetry.from(3, "1*1S,2*2S,2*5S"); + + assertThat(testee.getExpandedDelays()).containsExactly(1000L, 2000L, 2000L, 5000L, 5000L); + } + + @Test + public void getExpandedDelaysShouldExpandMultipleDelaysWithSpaces() throws Exception { + DelaysAndMaxRetry testee = DelaysAndMaxRetry.from(3, "1 * 1 S, 2 * 2 S , 2 * 5 S"); + + assertThat(testee.getExpandedDelays()).containsExactly(1000L, 2000L, 2000L, 5000L, 5000L); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRetryHelperTest.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRetryHelperTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRetryHelperTest.java new file mode 100644 index 0000000..0348a74 --- /dev/null +++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRetryHelperTest.java @@ -0,0 +1,84 @@ +/**************************************************************** + * 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.james.transport.mailets.remote.delivery; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.james.transport.mailets.remote.delivery.DeliveryRetriesHelper; +import org.apache.mailet.base.test.FakeMail; +import org.junit.Test; + +public class DeliveryRetryHelperTest { + + @Test + public void retrieveRetriesShouldBeZeroByDefault() throws Exception { + assertThat(DeliveryRetriesHelper.retrieveRetries(FakeMail.defaultFakeMail())) + .isEqualTo(0); + } + + @Test + public void retrieveRetriesShouldBeZeroAfterInit() throws Exception { + FakeMail mail = FakeMail.defaultFakeMail(); + + DeliveryRetriesHelper.initRetries(mail); + + assertThat(DeliveryRetriesHelper.retrieveRetries(mail)) + .isEqualTo(0); + } + + @Test + public void retrieveRetriesShouldBeOneAfterIncrement() throws Exception { + FakeMail mail = FakeMail.defaultFakeMail(); + + DeliveryRetriesHelper.initRetries(mail); + DeliveryRetriesHelper.incrementRetries(mail); + + assertThat(DeliveryRetriesHelper.retrieveRetries(mail)) + .isEqualTo(1); + } + + @Test + public void incrementRetriesShouldWorkOnNonInitializedMails() throws Exception { + FakeMail mail = FakeMail.defaultFakeMail(); + + DeliveryRetriesHelper.incrementRetries(mail); + + assertThat(DeliveryRetriesHelper.retrieveRetries(mail)) + .isEqualTo(1); + } + + @Test + public void retrieveRetriesShouldBeZeroOnInvalidValue() throws Exception { + FakeMail mail = FakeMail.builder().attribute(DeliveryRetriesHelper.DELIVERY_RETRY_COUNT, "invalid").build(); + + assertThat(DeliveryRetriesHelper.retrieveRetries(mail)) + .isEqualTo(0); + } + + @Test + public void incrementRetriesShouldWorkOnInvalidMails() throws Exception { + FakeMail mail = FakeMail.builder().attribute(DeliveryRetriesHelper.DELIVERY_RETRY_COUNT, "invalid").build(); + + DeliveryRetriesHelper.incrementRetries(mail); + + assertThat(DeliveryRetriesHelper.retrieveRetries(mail)) + .isEqualTo(1); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnableTest.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnableTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnableTest.java new file mode 100644 index 0000000..8cfd16a --- /dev/null +++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnableTest.java @@ -0,0 +1,251 @@ +/**************************************************************** + * 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.james.transport.mailets.remote.delivery; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import java.util.Date; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +import org.apache.james.domainlist.api.DomainList; +import org.apache.james.metrics.api.Metric; +import org.apache.james.metrics.api.MetricFactory; +import org.apache.james.metrics.api.NoopMetricFactory; +import org.apache.james.queue.api.MailQueue; +import org.apache.james.transport.mailets.remote.delivery.Bouncer; +import org.apache.james.transport.mailets.remote.delivery.DeliveryRetriesHelper; +import org.apache.james.transport.mailets.remote.delivery.DeliveryRunnable; +import org.apache.james.transport.mailets.remote.delivery.ExecutionResult; +import org.apache.james.transport.mailets.remote.delivery.MailDelivrer; +import org.apache.james.transport.mailets.remote.delivery.RemoteDeliveryConfiguration; +import org.apache.mailet.Mail; +import org.apache.mailet.base.test.FakeMail; +import org.apache.mailet.base.test.FakeMailetConfig; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class DeliveryRunnableTest { + + public static final Date FIXED_DATE = new Date(1159599194961L); + public static final Supplier<Date> FIXED_DATE_SUPPLIER = () -> FIXED_DATE; + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private DeliveryRunnable testee; + private Metric outgoingMailsMetric; + private Bouncer bouncer; + private MailDelivrer mailDelivrer; + private MailQueue mailQueue; + + @Before + public void setUp() { + FakeMailetConfig mailetConfig = FakeMailetConfig.builder() + .setProperty(RemoteDeliveryConfiguration.DELIVERY_THREADS, "1") + .setProperty(RemoteDeliveryConfiguration.DEBUG, "true") + .setProperty(RemoteDeliveryConfiguration.DELAY_TIME, "1000,2000,3000,4000,5000") + .build(); + + RemoteDeliveryConfiguration configuration = new RemoteDeliveryConfiguration(mailetConfig, mock(DomainList.class)); + outgoingMailsMetric = mock(Metric.class); + MetricFactory mockMetricFactory = mock(MetricFactory.class); + when(mockMetricFactory.generate(anyString())).thenReturn(outgoingMailsMetric); + when(mockMetricFactory.timer(anyString())).thenReturn(new NoopMetricFactory.NoopTimeMetric()); + bouncer = mock(Bouncer.class); + mailDelivrer = mock(MailDelivrer.class); + mailQueue = mock(MailQueue.class); + testee = new DeliveryRunnable(mailQueue, configuration, mockMetricFactory, bouncer, mailDelivrer, DeliveryRunnable.DEFAULT_NOT_STARTED, FIXED_DATE_SUPPLIER); + } + + @Test + public void deliverySuccessShouldIncrementMetric() throws Exception { + FakeMail fakeMail = FakeMail.defaultFakeMail(); + when(mailDelivrer.deliver(fakeMail)).thenReturn(ExecutionResult.success()); + + testee.attemptDelivery(fakeMail); + + verify(outgoingMailsMetric).increment(); + verifyNoMoreInteractions(outgoingMailsMetric); + } + + @Test + public void deliveryPermanentFailureShouldBounceTheMail() throws Exception { + FakeMail fakeMail = FakeMail.defaultFakeMail(); + Exception exception = new Exception(); + when(mailDelivrer.deliver(fakeMail)).thenReturn(ExecutionResult.permanentFailure(exception)); + + testee.attemptDelivery(fakeMail); + + verify(bouncer).bounce(fakeMail, exception); + verifyNoMoreInteractions(bouncer); + } + + @Test + public void deliveryPermanentFailureShouldNotIncrementDeliveryMetric() throws Exception { + FakeMail fakeMail = FakeMail.defaultFakeMail(); + Exception exception = new Exception(); + when(mailDelivrer.deliver(fakeMail)).thenReturn(ExecutionResult.permanentFailure(exception)); + + testee.attemptDelivery(fakeMail); + + verifyNoMoreInteractions(outgoingMailsMetric); + } + + @Test + public void deliveryTemporaryFailureShouldNotIncrementDeliveryMetric() throws Exception { + FakeMail fakeMail = FakeMail.builder().state(Mail.DEFAULT).build(); + Exception exception = new Exception(); + when(mailDelivrer.deliver(fakeMail)).thenReturn(ExecutionResult.temporaryFailure(exception)); + + testee.attemptDelivery(fakeMail); + + verifyNoMoreInteractions(outgoingMailsMetric); + } + + @Test + public void deliveryTemporaryFailureShouldFailOnMailsWithoutState() throws Exception { + FakeMail fakeMail = FakeMail.defaultFakeMail(); + Exception exception = new Exception(); + when(mailDelivrer.deliver(fakeMail)).thenReturn(ExecutionResult.temporaryFailure(exception)); + + expectedException.expect(NullPointerException.class); + + testee.attemptDelivery(fakeMail); + } + + @Test + public void deliveryTemporaryFailureShouldRetryDelivery() throws Exception { + FakeMail fakeMail = FakeMail.builder().state(Mail.DEFAULT).build(); + Exception exception = new Exception(); + when(mailDelivrer.deliver(fakeMail)).thenReturn(ExecutionResult.temporaryFailure(exception)); + + testee.attemptDelivery(fakeMail); + + verify(mailQueue).enQueue(FakeMail.builder() + .attribute(DeliveryRetriesHelper.DELIVERY_RETRY_COUNT, 1) + .state(Mail.ERROR) + .lastUpdated(FIXED_DATE) + .build(), + 1000, + TimeUnit.MILLISECONDS); + verifyNoMoreInteractions(mailQueue); + } + + @Test + public void deliveryTemporaryFailureShouldRetryDeliveryWithRightDelay() throws Exception { + FakeMail fakeMail = FakeMail.builder() + .state(Mail.ERROR) + .attribute(DeliveryRetriesHelper.DELIVERY_RETRY_COUNT, 2) + .build(); + Exception exception = new Exception(); + when(mailDelivrer.deliver(fakeMail)).thenReturn(ExecutionResult.temporaryFailure(exception)); + + testee.attemptDelivery(fakeMail); + + verify(mailQueue).enQueue(FakeMail.builder() + .attribute(DeliveryRetriesHelper.DELIVERY_RETRY_COUNT, 3) + .state(Mail.ERROR) + .lastUpdated(FIXED_DATE) + .build(), + 3000, + TimeUnit.MILLISECONDS); + verifyNoMoreInteractions(mailQueue); + } + + @Test + public void deliveryTemporaryFailureShouldRetryDeliveryOnMaximumRetryNumber() throws Exception { + FakeMail fakeMail = FakeMail.builder() + .state(Mail.ERROR) + .attribute(DeliveryRetriesHelper.DELIVERY_RETRY_COUNT, 4) + .build(); + Exception exception = new Exception(); + when(mailDelivrer.deliver(fakeMail)).thenReturn(ExecutionResult.temporaryFailure(exception)); + + testee.attemptDelivery(fakeMail); + + verify(mailQueue).enQueue(FakeMail.builder() + .attribute(DeliveryRetriesHelper.DELIVERY_RETRY_COUNT, 5) + .state(Mail.ERROR) + .lastUpdated(FIXED_DATE) + .build(), + 5000, + TimeUnit.MILLISECONDS); + verifyNoMoreInteractions(mailQueue); + } + + @Test + public void deliveryTemporaryFailureShouldNotRetryDeliveryOverMaximumRetryNumber() throws Exception { + FakeMail fakeMail = FakeMail.builder() + .state(Mail.ERROR) + .attribute(DeliveryRetriesHelper.DELIVERY_RETRY_COUNT, 5) + .build(); + Exception exception = new Exception(); + when(mailDelivrer.deliver(fakeMail)).thenReturn(ExecutionResult.temporaryFailure(exception)); + + testee.attemptDelivery(fakeMail); + + verifyNoMoreInteractions(mailQueue); + } + + @Test + public void deliveryTemporaryFailureShouldBounceWhenRetryExceeded() throws Exception { + FakeMail fakeMail = FakeMail.builder() + .state(Mail.ERROR) + .attribute(DeliveryRetriesHelper.DELIVERY_RETRY_COUNT, 5) + .build(); + Exception exception = new Exception(""); + when(mailDelivrer.deliver(fakeMail)).thenReturn(ExecutionResult.temporaryFailure(exception)); + + testee.attemptDelivery(fakeMail); + + verify(bouncer).bounce(eq(fakeMail), any(Exception.class)); + verifyNoMoreInteractions(bouncer); + } + + @Test + public void deliveryTemporaryFailureShouldResetDeliveryCountOnNonErrorState() throws Exception { + FakeMail fakeMail = FakeMail.builder() + .state(Mail.DEFAULT) + .attribute(DeliveryRetriesHelper.DELIVERY_RETRY_COUNT, 5) + .build(); + Exception exception = new Exception(); + when(mailDelivrer.deliver(fakeMail)).thenReturn(ExecutionResult.temporaryFailure(exception)); + + testee.attemptDelivery(fakeMail); + + verify(mailQueue).enQueue(FakeMail.builder() + .attribute(DeliveryRetriesHelper.DELIVERY_RETRY_COUNT, 1) + .state(Mail.ERROR) + .lastUpdated(FIXED_DATE) + .build(), + 1000, + TimeUnit.MILLISECONDS); + verifyNoMoreInteractions(mailQueue); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/HeloNameProviderTest.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/HeloNameProviderTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/HeloNameProviderTest.java new file mode 100644 index 0000000..1ac0d55 --- /dev/null +++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/HeloNameProviderTest.java @@ -0,0 +1,80 @@ +/**************************************************************** + * 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.james.transport.mailets.remote.delivery; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.apache.james.domainlist.api.DomainList; +import org.apache.james.domainlist.api.DomainListException; +import org.apache.james.transport.mailets.remote.delivery.HeloNameProvider; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class HeloNameProviderTest { + + public static final String DOMAIN = "domain"; + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private DomainList domainList; + + @Before + public void setUp() { + domainList = mock(DomainList.class); + } + + @Test + public void getHeloNameShouldReturnNonNullProvidedHeloName() { + HeloNameProvider heloNameProvider = new HeloNameProvider(DOMAIN, domainList); + + assertThat(heloNameProvider.getHeloName()).isEqualTo(DOMAIN); + } + + @Test + public void getHeloNameShouldReturnDomainListDefaultDomainOnNullHeloName() throws DomainListException { + when(domainList.getDefaultDomain()).thenReturn(DOMAIN); + HeloNameProvider heloNameProvider = new HeloNameProvider(null, domainList); + + assertThat(heloNameProvider.getHeloName()).isEqualTo(DOMAIN); + } + + @Test + public void getHeloNameShouldReturnLocalhostOnDomainListException() throws DomainListException { + when(domainList.getDefaultDomain()).thenThrow(new DomainListException("any message")); + HeloNameProvider heloNameProvider = new HeloNameProvider(null, domainList); + + assertThat(heloNameProvider.getHeloName()).isEqualTo(HeloNameProvider.LOCALHOST); + } + + @Test + public void getHeloNameShouldPropagateRuntimeExceptions() throws DomainListException { + when(domainList.getDefaultDomain()).thenThrow(new RuntimeException()); + HeloNameProvider heloNameProvider = new HeloNameProvider(null, domainList); + + expectedException.expect(RuntimeException.class); + heloNameProvider.getHeloName(); + } + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/InternetAddressConverterTest.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/InternetAddressConverterTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/InternetAddressConverterTest.java new file mode 100644 index 0000000..ef1308c --- /dev/null +++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/InternetAddressConverterTest.java @@ -0,0 +1,63 @@ +/**************************************************************** + * 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.james.transport.mailets.remote.delivery; + +import static org.assertj.core.api.Assertions.assertThat; + +import javax.mail.internet.InternetAddress; + +import org.apache.james.core.MailAddress; +import org.apache.james.transport.mailets.remote.delivery.InternetAddressConverter; +import org.apache.mailet.base.MailAddressFixture; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import com.google.common.collect.ImmutableList; + +public class InternetAddressConverterTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Test + public void convertShouldWorkWithEmptyAddressList() { + assertThat(InternetAddressConverter.convert(ImmutableList.<MailAddress>of())).isEmpty(); + } + + @Test + public void convertShouldThrowOnNullAddress() { + expectedException.expect(NullPointerException.class); + + InternetAddressConverter.convert(null); + } + + @Test + public void convertShouldWorkWithOneAddress() throws Exception { + assertThat(InternetAddressConverter.convert(ImmutableList.of(MailAddressFixture.ANY_AT_JAMES))) + .containsOnly(new InternetAddress(MailAddressFixture.ANY_AT_JAMES.asString())); + } + + @Test + public void convertShouldWorkWithTwoAddress() throws Exception { + assertThat(InternetAddressConverter.convert(ImmutableList.of(MailAddressFixture.ANY_AT_JAMES, MailAddressFixture.OTHER_AT_JAMES))) + .containsOnly(new InternetAddress(MailAddressFixture.ANY_AT_JAMES.asString()), new InternetAddress(MailAddressFixture.OTHER_AT_JAMES.asString())); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
