You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2019/08/28 10:32:15 UTC
[james-project] 07/12: JAMES-2865 MockSMTPServer with mock behaviors
This is an automated email from the ASF dual-hosted git repository.
btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 77bc6458388abb3491cbb3ed6de351f4df656aae
Author: Tran Tien Duc <dt...@linagora.com>
AuthorDate: Thu Aug 22 14:51:39 2019 +0700
JAMES-2865 MockSMTPServer with mock behaviors
- Condition filtering will be tested later
- Counting Number of Anwsers is not implemented
---
.../james/mock/smtp/server/MockMessageHandler.java | 81 +++++++++++++++++---
.../james/mock/smtp/server/MockSMTPServer.java | 16 +++-
.../james/mock/smtp/server/MockSMTPServerTest.java | 87 ++++++++++++++++++++--
.../org/apache/james/utils/SMTPMessageSender.java | 2 +-
4 files changed, 167 insertions(+), 19 deletions(-)
diff --git a/server/mailet/mock-smtp-server/src/main/java/org/apache/james/mock/smtp/server/MockMessageHandler.java b/server/mailet/mock-smtp-server/src/main/java/org/apache/james/mock/smtp/server/MockMessageHandler.java
index 7322fa7..15323ec 100644
--- a/server/mailet/mock-smtp-server/src/main/java/org/apache/james/mock/smtp/server/MockMessageHandler.java
+++ b/server/mailet/mock-smtp-server/src/main/java/org/apache/james/mock/smtp/server/MockMessageHandler.java
@@ -22,51 +22,92 @@ package org.apache.james.mock.smtp.server;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Optional;
import javax.mail.internet.AddressException;
import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.NotImplementedException;
import org.apache.james.core.MailAddress;
import org.apache.james.mock.smtp.server.model.Mail;
+import org.apache.james.mock.smtp.server.model.MockSMTPBehavior;
+import org.apache.james.mock.smtp.server.model.Response;
+import org.apache.james.mock.smtp.server.model.SMTPCommand;
import org.subethamail.smtp.MessageHandler;
import org.subethamail.smtp.RejectException;
import org.subethamail.smtp.TooMuchDataException;
public class MockMessageHandler implements MessageHandler {
+ @FunctionalInterface
+ interface Behavior<T> {
+ void behave(T input) throws RejectException;
+ }
+
+ class MockBehavior<T> implements Behavior<T> {
+
+ private final MockSMTPBehavior behavior;
+
+ MockBehavior(MockSMTPBehavior behavior) {
+ this.behavior = behavior;
+ }
+
+ @Override
+ public void behave(T input) throws RejectException {
+ Response response = behavior.getResponse();
+ if (response.isServerRejected()) {
+ throw new RejectException(response.getCode().getRawCode(), response.getMessage());
+ }
+ throw new NotImplementedException("Not rejecting commands in mock behaviours is not supported yet");
+ }
+ }
+
private static final int ARGUMENT_SYNTAX_ERROR_501 = 501;
private final Mail.Envelope.Builder envelopeBuilder;
private final Mail.Builder mailBuilder;
private final ReceivedMailRepository mailRepository;
+ private final List<MockSMTPBehavior> behaviors;
- MockMessageHandler(ReceivedMailRepository mailRepository) {
+ MockMessageHandler(ReceivedMailRepository mailRepository, List<MockSMTPBehavior> behaviors) {
this.mailRepository = mailRepository;
+ this.behaviors = behaviors;
this.envelopeBuilder = new Mail.Envelope.Builder();
this.mailBuilder = new Mail.Builder();
}
@Override
public void from(String from) throws RejectException {
- try {
- envelopeBuilder.from(new MailAddress(from));
- } catch (AddressException e) {
- throw new RejectException(ARGUMENT_SYNTAX_ERROR_501, "invalid email address supplied");
- }
+ Behavior<MailAddress> fromBehavior = firstMatchedBehavior(SMTPCommand.MAIL_FROM)
+ .<Behavior<MailAddress>>map(MockBehavior::new)
+ .orElseGet(() -> envelopeBuilder::from);
+
+ fromBehavior.behave(parse(from));
}
@Override
public void recipient(String recipient) throws RejectException {
- try {
- envelopeBuilder.addRecipient(new MailAddress(recipient));
- } catch (AddressException e) {
- throw new RejectException(ARGUMENT_SYNTAX_ERROR_501, "invalid email address supplied");
- }
+ Behavior<MailAddress> recipientBehavior = firstMatchedBehavior(SMTPCommand.RCPT_TO)
+ .<Behavior<MailAddress>>map(MockBehavior::new)
+ .orElseGet(() -> envelopeBuilder::addRecipient);
+
+ recipientBehavior.behave(parse(recipient));
}
@Override
public void data(InputStream data) throws RejectException, TooMuchDataException, IOException {
- mailBuilder.message(IOUtils.toString(data, StandardCharsets.UTF_8));
+ Behavior<InputStream> dataBehavior = firstMatchedBehavior(SMTPCommand.DATA)
+ .<Behavior<InputStream>>map(MockBehavior::new)
+ .orElseGet(() -> content -> mailBuilder.message(readData(content)));
+
+ dataBehavior.behave(data);
+ }
+
+ private Optional<MockSMTPBehavior> firstMatchedBehavior(SMTPCommand data) {
+ return behaviors.stream()
+ .filter(behavior -> behavior.getCommand().equals(data))
+ .findFirst();
}
@Override
@@ -75,4 +116,20 @@ public class MockMessageHandler implements MessageHandler {
.build();
mailRepository.store(mail);
}
+
+ private String readData(InputStream data) {
+ try {
+ return IOUtils.toString(data, StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ throw new RejectException(ARGUMENT_SYNTAX_ERROR_501, "invalid data supplied");
+ }
+ }
+
+ private MailAddress parse(String mailAddress) {
+ try {
+ return new MailAddress(mailAddress);
+ } catch (AddressException e) {
+ throw new RejectException(ARGUMENT_SYNTAX_ERROR_501, "invalid email address supplied");
+ }
+ }
}
diff --git a/server/mailet/mock-smtp-server/src/main/java/org/apache/james/mock/smtp/server/MockSMTPServer.java b/server/mailet/mock-smtp-server/src/main/java/org/apache/james/mock/smtp/server/MockSMTPServer.java
index 96246c4..9f05e25 100644
--- a/server/mailet/mock-smtp-server/src/main/java/org/apache/james/mock/smtp/server/MockSMTPServer.java
+++ b/server/mailet/mock-smtp-server/src/main/java/org/apache/james/mock/smtp/server/MockSMTPServer.java
@@ -19,9 +19,12 @@
package org.apache.james.mock.smtp.server;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import org.apache.james.mock.smtp.server.model.Mail;
+import org.apache.james.mock.smtp.server.model.MockSMTPBehavior;
import org.apache.james.util.Port;
import org.subethamail.smtp.server.SMTPServer;
@@ -29,10 +32,12 @@ class MockSMTPServer {
private final SMTPServer server;
private final ReceivedMailRepository mailRepository;
+ private final List<MockSMTPBehavior> behaviors;
MockSMTPServer() {
+ this.behaviors = new ArrayList<>();
this.mailRepository = new ReceivedMailRepository();
- this.server = new SMTPServer(ctx -> new MockMessageHandler(mailRepository));
+ this.server = new SMTPServer(ctx -> new MockMessageHandler(mailRepository, behaviors));
this.server.setPort(0);
}
@@ -52,5 +57,14 @@ class MockSMTPServer {
void stop() {
server.stop();
+ clearBehavior();
+ }
+
+ void setBehaviors(MockSMTPBehavior... behaviors) {
+ this.behaviors.addAll(Arrays.asList(behaviors));
+ }
+
+ private void clearBehavior() {
+ behaviors.clear();
}
}
diff --git a/server/mailet/mock-smtp-server/src/test/java/org/apache/james/mock/smtp/server/MockSMTPServerTest.java b/server/mailet/mock-smtp-server/src/test/java/org/apache/james/mock/smtp/server/MockSMTPServerTest.java
index c2c5bdc..4e9cb09 100644
--- a/server/mailet/mock-smtp-server/src/test/java/org/apache/james/mock/smtp/server/MockSMTPServerTest.java
+++ b/server/mailet/mock-smtp-server/src/test/java/org/apache/james/mock/smtp/server/MockSMTPServerTest.java
@@ -23,6 +23,10 @@ import static org.apache.james.mock.smtp.server.Fixture.ALICE;
import static org.apache.james.mock.smtp.server.Fixture.BOB;
import static org.apache.james.mock.smtp.server.Fixture.DOMAIN;
import static org.apache.james.mock.smtp.server.Fixture.JACK;
+import static org.apache.james.mock.smtp.server.model.Response.SMTPStatusCode.SERVICE_NOT_AVAILABLE_421;
+import static org.apache.james.mock.smtp.server.model.SMTPCommand.DATA;
+import static org.apache.james.mock.smtp.server.model.SMTPCommand.MAIL_FROM;
+import static org.apache.james.mock.smtp.server.model.SMTPCommand.RCPT_TO;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -32,9 +36,12 @@ import java.util.List;
import javax.mail.internet.MimeMessage;
+import org.apache.commons.net.smtp.SMTPConnectionClosedException;
import org.apache.james.core.MailAddress;
import org.apache.james.core.builder.MimeMessageBuilder;
+import org.apache.james.mock.smtp.server.model.Condition;
import org.apache.james.mock.smtp.server.model.Mail;
+import org.apache.james.mock.smtp.server.model.MockSMTPBehavior;
import org.apache.james.mock.smtp.server.model.Response;
import org.apache.james.util.MimeMessageUtil;
import org.apache.james.util.Port;
@@ -52,8 +59,6 @@ import com.github.fge.lambdas.Throwing;
class MockSMTPServerTest {
- private static final Response.SMTPStatusCode SERVICE_NOT_AVAILABLE_421 = Response.SMTPStatusCode.of(421);
-
@Nested
class NormalBehaviorTests {
private MockSMTPServer mockServer;
@@ -75,9 +80,9 @@ class MockSMTPServerTest {
.connect("localhost", mockServer.getPort());
MimeMessage message = MimeMessageBuilder.mimeMessageBuilder()
- .setSubject("test")
- .setText("any text")
- .build();
+ .setSubject("test")
+ .setText("any text")
+ .build();
FakeMail mail = FakeMail.builder()
.name("name")
@@ -104,6 +109,78 @@ class MockSMTPServerTest {
}
}
+ @Nested
+ class MailMockBehaviorTest {
+ private MockSMTPServer mockServer;
+ private FakeMail mail1;
+ private MimeMessage mimeMessage1;
+ private SMTPMessageSender smtpClient;
+
+ @BeforeEach
+ void setUp() throws Exception {
+ mockServer = new MockSMTPServer();
+
+ mimeMessage1 = MimeMessageBuilder.mimeMessageBuilder()
+ .setSubject("test")
+ .setText("any text")
+ .build();
+ mail1 = FakeMail.builder()
+ .name("name")
+ .sender(BOB)
+ .recipients(ALICE, JACK)
+ .mimeMessage(mimeMessage1)
+ .build();
+
+ mockServer.start();
+ smtpClient = new SMTPMessageSender(DOMAIN)
+ .connect("localhost", mockServer.getPort());
+ }
+
+ @AfterEach
+ void tearDown() {
+ mockServer.stop();
+ }
+
+ @Test
+ void serverShouldReceiveMessageFromClient() throws Exception {
+ mockServer.setBehaviors(new MockSMTPBehavior(
+ MAIL_FROM,
+ Condition.MATCH_ALL,
+ Response.serverReject(SERVICE_NOT_AVAILABLE_421, "mock response"),
+ MockSMTPBehavior.NumberOfAnswersPolicy.anytime()));
+
+ assertThatThrownBy(() -> smtpClient.sendMessage(mail1))
+ .isInstanceOf(SMTPConnectionClosedException.class)
+ .hasMessageContaining("421");
+ }
+
+ @Test
+ void serverShouldReceiveMessageRecipientClient() throws Exception {
+ mockServer.setBehaviors(new MockSMTPBehavior(
+ RCPT_TO,
+ Condition.MATCH_ALL,
+ Response.serverReject(SERVICE_NOT_AVAILABLE_421, "mock response"),
+ MockSMTPBehavior.NumberOfAnswersPolicy.anytime()));
+
+ assertThatThrownBy(() -> smtpClient.sendMessage(mail1))
+ .isInstanceOf(SMTPConnectionClosedException.class)
+ .hasMessageContaining("421");
+ }
+
+ @Test
+ void serverShouldReceiveMessageDataClient() throws Exception {
+ mockServer.setBehaviors(new MockSMTPBehavior(
+ DATA,
+ Condition.MATCH_ALL,
+ Response.serverReject(SERVICE_NOT_AVAILABLE_421, "mock response"),
+ MockSMTPBehavior.NumberOfAnswersPolicy.anytime()));
+
+ assertThatThrownBy(() -> smtpClient.sendMessage(mail1))
+ .isInstanceOf(SMTPConnectionClosedException.class)
+ .hasMessageContaining("421");
+ }
+ }
+
@Test
void serverStartShouldOpenASmtpPort() {
MockSMTPServer mockServer = new MockSMTPServer();
diff --git a/server/testing/src/main/java/org/apache/james/utils/SMTPMessageSender.java b/server/testing/src/main/java/org/apache/james/utils/SMTPMessageSender.java
index 7a249b8..cdae5c8 100644
--- a/server/testing/src/main/java/org/apache/james/utils/SMTPMessageSender.java
+++ b/server/testing/src/main/java/org/apache/james/utils/SMTPMessageSender.java
@@ -119,7 +119,7 @@ public class SMTPMessageSender extends ExternalResource implements Closeable {
doSetSender(from);
mail.getRecipients().stream()
.map(MailAddress::asString)
- .forEach(Throwing.consumer(this::doAddRcpt));
+ .forEach(Throwing.consumer(this::doAddRcpt).sneakyThrow());
doData(asString(mail.getMessage()));
return this;
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org