JAMES-2442 Integration tests for RemoteDelivery - That an unreachable MX IP will generate a failover to the second MX when direct resolution - If all (direct resolution) MX IPs are not reachable, a bounce is sent - what happens when direct resolution to a domain with no mx records? a bounce is sent
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/80535727 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/80535727 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/80535727 Branch: refs/heads/master Commit: 805357274248eb5605e3338cc6ccc1abf05540b7 Parents: 42e473e Author: duc <[email protected]> Authored: Wed Jun 27 18:37:42 2018 +0700 Committer: benwa <[email protected]> Committed: Wed Jul 4 09:33:55 2018 +0700 ---------------------------------------------------------------------- .../util/docker/SwarmGenericContainer.java | 5 + ...ResolutionRemoteDeliveryIntegrationTest.java | 221 +++++++++++++++++++ .../GatewayRemoteDeliveryIntegrationTest.java | 31 --- .../java/org/apache/james/utils/FakeSmtp.java | 27 ++- 4 files changed, 248 insertions(+), 36 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/80535727/server/container/util-java8/src/test/java/org/apache/james/util/docker/SwarmGenericContainer.java ---------------------------------------------------------------------- diff --git a/server/container/util-java8/src/test/java/org/apache/james/util/docker/SwarmGenericContainer.java b/server/container/util-java8/src/test/java/org/apache/james/util/docker/SwarmGenericContainer.java index e9fd984..59488c0 100644 --- a/server/container/util-java8/src/test/java/org/apache/james/util/docker/SwarmGenericContainer.java +++ b/server/container/util-java8/src/test/java/org/apache/james/util/docker/SwarmGenericContainer.java @@ -108,6 +108,11 @@ public class SwarmGenericContainer implements TestRule { return this; } + public SwarmGenericContainer withCommands(String... commands) { + container.withCommand(commands); + return this; + } + public void start() { container.start(); } http://git-wip-us.apache.org/repos/asf/james-project/blob/80535727/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/DirectResolutionRemoteDeliveryIntegrationTest.java ---------------------------------------------------------------------- diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/DirectResolutionRemoteDeliveryIntegrationTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/DirectResolutionRemoteDeliveryIntegrationTest.java new file mode 100644 index 0000000..fc8c7c4 --- /dev/null +++ b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/DirectResolutionRemoteDeliveryIntegrationTest.java @@ -0,0 +1,221 @@ +/**************************************************************** + * 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.mailets; + +import static org.apache.james.MemoryJamesServerMain.SMTP_AND_IMAP_MODULE; +import static org.apache.james.MemoryJamesServerMain.SMTP_ONLY_MODULE; +import static org.apache.james.mailets.configuration.Constants.*; +import static org.apache.james.mailets.configuration.MailetConfiguration.LOCAL_DELIVERY; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; + +import java.net.InetAddress; +import java.util.List; + +import org.apache.james.dnsservice.api.DNSService; +import org.apache.james.dnsservice.api.InMemoryDNSService; +import org.apache.james.mailets.configuration.CommonProcessors; +import org.apache.james.mailets.configuration.MailetConfiguration; +import org.apache.james.mailets.configuration.MailetContainer; +import org.apache.james.mailets.configuration.ProcessorConfiguration; +import org.apache.james.probe.DataProbe; +import org.apache.james.transport.matchers.All; +import org.apache.james.utils.DataProbeImpl; +import org.apache.james.utils.FakeSmtp; +import org.apache.james.utils.IMAPMessageReader; +import org.apache.james.utils.SMTPMessageSender; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import com.google.common.collect.ImmutableList; + +public class DirectResolutionRemoteDeliveryIntegrationTest { + private static final String JAMES_ANOTHER_DOMAIN = "james.com"; + private static final String JAMES_ANOTHER_MX_DOMAIN_1 = "mx1.james.com"; + private static final String JAMES_ANOTHER_MX_DOMAIN_2 = "mx2.james.com"; + private static final List<String> JAMES_ANOTHER_MX_DOMAINS = ImmutableList.of(JAMES_ANOTHER_MX_DOMAIN_1, JAMES_ANOTHER_MX_DOMAIN_2); + + private static final String FROM = "from@" + DEFAULT_DOMAIN; + private static final String RECIPIENT = "touser@" + JAMES_ANOTHER_DOMAIN; + + private static final ImmutableList<InetAddress> ADDRESS_EMPTY_LIST = ImmutableList.of(); + private static final ImmutableList<String> RECORD_EMPTY_LIST = ImmutableList.of(); + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + @Rule + public IMAPMessageReader imapMessageReader = new IMAPMessageReader(); + @Rule + public SMTPMessageSender messageSender = new SMTPMessageSender(DEFAULT_DOMAIN); + @Rule + public FakeSmtp fakeSmtp = new FakeSmtp(); + @Rule + public FakeSmtp fakeSmtpOnPort26 = FakeSmtp.withSmtpPort(26); + + private TemporaryJamesServer jamesServer; + private DataProbe dataProbe; + + @Before + public void setup() { + fakeSmtp.awaitStarted(awaitAtMostOneMinute); + fakeSmtpOnPort26.awaitStarted(awaitAtMostOneMinute); + } + + @After + public void tearDown() { + if (jamesServer != null) { + jamesServer.shutdown(); + } + } + + @Test + public void directResolutionShouldBeWellPerformed() throws Exception { + InMemoryDNSService inMemoryDNSService = new InMemoryDNSService() + .registerMxRecord(JAMES_ANOTHER_DOMAIN, fakeSmtp.getContainer().getContainerIp()); + + jamesServer = TemporaryJamesServer.builder() + .withBase(SMTP_ONLY_MODULE) + .withOverrides(binder -> binder.bind(DNSService.class).toInstance(inMemoryDNSService)) + .withMailetContainer(MailetContainer.builder() + .putProcessor(CommonProcessors.simpleRoot()) + .putProcessor(CommonProcessors.error()) + .putProcessor(directResolutionTransport()) + .putProcessor(CommonProcessors.bounces())) + .build(temporaryFolder); + + dataProbe = jamesServer.getProbe(DataProbeImpl.class); + dataProbe.addDomain(DEFAULT_DOMAIN); + dataProbe.addUser(FROM, PASSWORD); + + messageSender.connect(LOCALHOST_IP, SMTP_PORT) + .sendMessage(FROM, RECIPIENT); + + awaitAtMostOneMinute.until(this::messageIsReceivedByTheSmtpServer); + } + + @Test + public void directResolutionShouldFailoverOnSecondMxWhenFirstMxFailed() throws Exception { + InMemoryDNSService inMemoryDNSService = new InMemoryDNSService() + .registerRecord(JAMES_ANOTHER_DOMAIN, ADDRESS_EMPTY_LIST, JAMES_ANOTHER_MX_DOMAINS, RECORD_EMPTY_LIST) + .registerMxRecord(JAMES_ANOTHER_MX_DOMAIN_1, fakeSmtpOnPort26.getContainer().getContainerIp()) + .registerMxRecord(JAMES_ANOTHER_MX_DOMAIN_2, fakeSmtp.getContainer().getContainerIp()); + + jamesServer = TemporaryJamesServer.builder() + .withBase(SMTP_ONLY_MODULE) + .withOverrides(binder -> binder.bind(DNSService.class).toInstance(inMemoryDNSService)) + .withMailetContainer(MailetContainer.builder() + .putProcessor(CommonProcessors.simpleRoot()) + .putProcessor(CommonProcessors.error()) + .putProcessor(directResolutionTransport()) + .putProcessor(CommonProcessors.bounces())) + .build(temporaryFolder); + + dataProbe = jamesServer.getProbe(DataProbeImpl.class); + dataProbe.addDomain(DEFAULT_DOMAIN); + dataProbe.addUser(FROM, PASSWORD); + + messageSender.connect(LOCALHOST_IP, SMTP_PORT) + .sendMessage(FROM, RECIPIENT); + + awaitAtMostOneMinute.until(this::messageIsReceivedByTheSmtpServer); + } + + @Test + public void directResolutionShouldBounceUponUnreachableMxRecords() throws Exception { + InMemoryDNSService inMemoryDNSService = new InMemoryDNSService() + .registerRecord(JAMES_ANOTHER_DOMAIN, ADDRESS_EMPTY_LIST, ImmutableList.of("unknown"), RECORD_EMPTY_LIST); + + jamesServer = TemporaryJamesServer.builder() + .withBase(SMTP_AND_IMAP_MODULE) + .withOverrides(binder -> binder.bind(DNSService.class).toInstance(inMemoryDNSService)) + .withMailetContainer(MailetContainer.builder() + .putProcessor(CommonProcessors.simpleRoot()) + .putProcessor(CommonProcessors.error()) + .putProcessor(transport()) + .putProcessor(CommonProcessors.bounces())) + .build(temporaryFolder); + + dataProbe = jamesServer.getProbe(DataProbeImpl.class); + dataProbe.addDomain(DEFAULT_DOMAIN); + dataProbe.addUser(FROM, PASSWORD); + + messageSender.connect(LOCALHOST_IP, SMTP_PORT) + .sendMessage(FROM, RECIPIENT); + + imapMessageReader.connect(LOCALHOST_IP, IMAP_PORT) + .login(FROM, PASSWORD) + .select(IMAPMessageReader.INBOX) + .awaitMessage(awaitAtMostOneMinute); + } + + @Test + public void directResolutionShouldBounceWhenNoMxRecord() throws Exception { + InMemoryDNSService inMemoryDNSService = new InMemoryDNSService() + .registerRecord(JAMES_ANOTHER_DOMAIN, ADDRESS_EMPTY_LIST, RECORD_EMPTY_LIST, RECORD_EMPTY_LIST); + + jamesServer = TemporaryJamesServer.builder() + .withBase(SMTP_AND_IMAP_MODULE) + .withOverrides(binder -> binder.bind(DNSService.class).toInstance(inMemoryDNSService)) + .withMailetContainer(MailetContainer.builder() + .putProcessor(CommonProcessors.simpleRoot()) + .putProcessor(CommonProcessors.error()) + .putProcessor(transport()) + .putProcessor(CommonProcessors.bounces())) + .build(temporaryFolder); + + dataProbe = jamesServer.getProbe(DataProbeImpl.class); + dataProbe.addDomain(DEFAULT_DOMAIN); + dataProbe.addUser(FROM, PASSWORD); + + messageSender.connect(LOCALHOST_IP, SMTP_PORT) + .sendMessage(FROM, RECIPIENT); + + imapMessageReader.connect(LOCALHOST_IP, IMAP_PORT) + .login(FROM, PASSWORD) + .select(IMAPMessageReader.INBOX) + .awaitMessage(awaitAtMostOneMinute); + } + + private boolean messageIsReceivedByTheSmtpServer() { + return fakeSmtp.isReceived(response -> response + .body("", hasSize(1)) + .body("[0].from", equalTo(FROM)) + .body("[0].subject", equalTo("test"))); + } + + private ProcessorConfiguration.Builder directResolutionTransport() { + return ProcessorConfiguration.transport() + .addMailet(MailetConfiguration.BCC_STRIPPER) + .addMailet(MailetConfiguration.remoteDeliveryBuilder() + .matcher(All.class)); + } + + private ProcessorConfiguration.Builder transport() { + return ProcessorConfiguration.transport() + .addMailet(MailetConfiguration.BCC_STRIPPER) + .addMailet(LOCAL_DELIVERY) + .addMailet(MailetConfiguration.remoteDeliveryBuilder() + .matcher(All.class)); + } + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/80535727/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/GatewayRemoteDeliveryIntegrationTest.java ---------------------------------------------------------------------- diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/GatewayRemoteDeliveryIntegrationTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/GatewayRemoteDeliveryIntegrationTest.java index cb4cf10..0158104 100644 --- a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/GatewayRemoteDeliveryIntegrationTest.java +++ b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/GatewayRemoteDeliveryIntegrationTest.java @@ -237,28 +237,6 @@ public class GatewayRemoteDeliveryIntegrationTest { .awaitMessage(awaitAtMostOneMinute); } - @Test - public void directResolutionShouldBeWellPerformed() throws Exception { - jamesServer = TemporaryJamesServer.builder() - .withBase(SMTP_ONLY_MODULE) - .withOverrides(binder -> binder.bind(DNSService.class).toInstance(inMemoryDNSService)) - .withMailetContainer(MailetContainer.builder() - .putProcessor(CommonProcessors.simpleRoot()) - .putProcessor(CommonProcessors.error()) - .putProcessor(directResolutionTransport()) - .putProcessor(CommonProcessors.bounces())) - .build(temporaryFolder); - - dataProbe = jamesServer.getProbe(DataProbeImpl.class); - dataProbe.addDomain(DEFAULT_DOMAIN); - dataProbe.addUser(FROM, PASSWORD); - - messageSender.connect(LOCALHOST_IP, SMTP_PORT) - .sendMessage(FROM, RECIPIENT); - - awaitAtMostOneMinute.until(this::messageIsReceivedByTheSmtpServer); - } - private boolean messageIsReceivedByTheSmtpServer() { return fakeSmtp.isReceived(response -> response .body("", hasSize(1)) @@ -278,13 +256,4 @@ public class GatewayRemoteDeliveryIntegrationTest { .addProperty("gateway", gatewayProperty) .matcher(All.class)); } - - private ProcessorConfiguration.Builder directResolutionTransport() { - return ProcessorConfiguration.transport() - .addMailet(MailetConfiguration.BCC_STRIPPER) - .addMailet(MailetConfiguration.remoteDeliveryBuilder() - .matcher(All.class)); - } - - } http://git-wip-us.apache.org/repos/asf/james-project/blob/80535727/server/testing/src/main/java/org/apache/james/utils/FakeSmtp.java ---------------------------------------------------------------------- diff --git a/server/testing/src/main/java/org/apache/james/utils/FakeSmtp.java b/server/testing/src/main/java/org/apache/james/utils/FakeSmtp.java index 4b5fc3a..5013110 100644 --- a/server/testing/src/main/java/org/apache/james/utils/FakeSmtp.java +++ b/server/testing/src/main/java/org/apache/james/utils/FakeSmtp.java @@ -42,15 +42,32 @@ import com.jayway.restassured.specification.RequestSpecification; import com.jayway.restassured.specification.ResponseSpecification; public class FakeSmtp implements TestRule { + + public static FakeSmtp withSmtpPort(Integer smtpPort) { + SwarmGenericContainer container = fakeSmtpContainer() + .withCommands("node", "cli", "--listen", "80", "--smtp", smtpPort.toString()); + + return new FakeSmtp(container, smtpPort); + } + + private static SwarmGenericContainer fakeSmtpContainer() { + return new SwarmGenericContainer(Images.FAKE_SMTP) + .withAffinityToContainer() + .waitingFor(new HostPortWaitStrategy()); + } + private static final int SMTP_PORT = 25; private static final ResponseSpecification RESPONSE_SPECIFICATION = new ResponseSpecBuilder().build(); private final SwarmGenericContainer container; + private final Integer smtpPort; public FakeSmtp() { - container = new SwarmGenericContainer(Images.FAKE_SMTP) - .withExposedPorts(SMTP_PORT) - .withAffinityToContainer() - .waitingFor(new HostPortWaitStrategy()); + this(fakeSmtpContainer().withExposedPorts(SMTP_PORT), SMTP_PORT); + } + + public FakeSmtp(SwarmGenericContainer container, Integer smtpPort) { + this.smtpPort = smtpPort; + this.container = container; } @Override @@ -59,7 +76,7 @@ public class FakeSmtp implements TestRule { } public void awaitStarted(ConditionFactory calmyAwait) { - calmyAwait.until(() -> container.tryConnect(SMTP_PORT)); + calmyAwait.until(() -> container.tryConnect(smtpPort)); } public boolean isReceived(Function<ValidatableResponse, ValidatableResponse> expectations) { --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
