From 41b626a632fbbcb898385b108bf8031bc7ea7204 Mon Sep 17 00:00:00 2001 From: Corneil du Plessis Date: Thu, 12 Jan 2023 16:39:53 +0200 Subject: [PATCH] Added GreenMail. Update all tests for mail-supplier and mail-sink. --- supplier/mail-supplier/pom.xml | 20 +- .../mail/MailSupplierConfiguration.java | 14 +- .../mail/AbstractMailSupplierTests.java | 56 +- .../cloud/fn/supplier/mail/ImapFailTests.java | 37 +- .../fn/supplier/mail/ImapIdleFailTests.java | 34 +- .../fn/supplier/mail/ImapIdlePassTests.java | 33 +- .../cloud/fn/supplier/mail/ImapPassTests.java | 52 +- .../cloud/fn/supplier/mail/Pop3FailTests.java | 29 +- .../cloud/fn/supplier/mail/Pop3PassTests.java | 25 +- .../fn/supplier/mail/TestMailServer.java | 551 ------------------ 10 files changed, 154 insertions(+), 697 deletions(-) delete mode 100644 supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/TestMailServer.java diff --git a/supplier/mail-supplier/pom.xml b/supplier/mail-supplier/pom.xml index 143901f9..5ee72725 100644 --- a/supplier/mail-supplier/pom.xml +++ b/supplier/mail-supplier/pom.xml @@ -28,9 +28,25 @@ ${jakarta-mail.version} - com.sun.mail + org.eclipse.angus jakarta.mail - [2.0.1,) + 1.0.0 + + + com.icegreen + greenmail-junit5 + 2.0.0-alpha-3 + test + + + com.sun.mail + jakarta.mail + + + jakarta.activation + jakarta.activation-api + + diff --git a/supplier/mail-supplier/src/main/java/org/springframework/cloud/fn/supplier/mail/MailSupplierConfiguration.java b/supplier/mail-supplier/src/main/java/org/springframework/cloud/fn/supplier/mail/MailSupplierConfiguration.java index 00da10b3..35ba4e82 100644 --- a/supplier/mail-supplier/src/main/java/org/springframework/cloud/fn/supplier/mail/MailSupplierConfiguration.java +++ b/supplier/mail-supplier/src/main/java/org/springframework/cloud/fn/supplier/mail/MailSupplierConfiguration.java @@ -25,14 +25,13 @@ import jakarta.mail.URLName; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.fn.common.config.ComponentCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.integration.core.MessageSource; -import org.springframework.integration.dsl.IntegrationFlows; +import org.springframework.integration.dsl.IntegrationFlow; import org.springframework.integration.dsl.MessageProducerSpec; import org.springframework.integration.dsl.MessageSourceSpec; import org.springframework.integration.endpoint.MessageProducerSupport; @@ -53,18 +52,23 @@ import org.springframework.messaging.Message; * @author Artem Bilan * @author Chris Schaefer * @author Soby Chacko + * @author Corneil du Plessis */ @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties(MailSupplierProperties.class) public class MailSupplierConfiguration { - @Autowired - private MailSupplierProperties properties; + + final private MailSupplierProperties properties; + + public MailSupplierConfiguration(MailSupplierProperties properties) { + this.properties = properties; + } @Bean public Publisher> mailInboundFlow(MessageProducerSupport messageProducer) { - return IntegrationFlows.from(messageProducer) + return IntegrationFlow.from(messageProducer) .transform(Mail.toStringTransformer(this.properties.getCharset())) .enrichHeaders(h -> h .defaultOverwrite(true) diff --git a/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/AbstractMailSupplierTests.java b/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/AbstractMailSupplierTests.java index 617dfced..08ef475a 100644 --- a/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/AbstractMailSupplierTests.java +++ b/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/AbstractMailSupplierTests.java @@ -18,10 +18,15 @@ package org.springframework.cloud.fn.supplier.mail; import java.util.function.Supplier; +import com.icegreen.greenmail.user.GreenMailUser; +import com.icegreen.greenmail.util.GreenMail; +import com.icegreen.greenmail.util.GreenMailUtil; +import com.icegreen.greenmail.util.ServerSetup; +import com.icegreen.greenmail.util.ServerSetupTest; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import reactor.core.publisher.Flux; import org.springframework.beans.factory.annotation.Autowired; @@ -32,35 +37,44 @@ import org.springframework.integration.test.context.SpringIntegrationTest; import org.springframework.messaging.Message; import org.springframework.test.annotation.DirtiesContext; -import static org.assertj.core.api.Assertions.assertThat; - -@Disabled // TODO add test container solution @SpringIntegrationTest(noAutoStartup = "*") @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, properties = { - "mail.supplier.mark-as-read=true", - "mail.supplier.delete=false", - "mail.supplier.user-flag=testSIUserFlag", - "mail.supplier.java-mail-properties=mail.imap.socketFactory.fallback=true\\n mail.store.protocol=imap\\n mail.debug=true" }) + "mail.supplier.mark-as-read=true", + "mail.supplier.delete=false", + "mail.supplier.user-flag=testSIUserFlag", + "mail.supplier.java-mail-properties=mail.imap.socketFactory.fallback=true\\n mail.store.protocol=imap\\n mail.debug=true"}) @DirtiesContext -public class AbstractMailSupplierTests { +public abstract class AbstractMailSupplierTests { + protected static GreenMail mailServer; - private static TestMailServer.MailServer MAIL_SERVER; + protected static GreenMailUser mailUser; @Autowired protected Supplier>> mailSupplier; - @Autowired - private StandardIntegrationFlow integrationFlow; + protected StandardIntegrationFlow integrationFlow; + protected void sendMessage(String subject, String body) { + mailUser.deliver(GreenMailUtil.createTextEmail("bar@bax", "test@test", subject, body, mailServer.getSmtp().getServerSetup())); + } - protected static void startMailServer(TestMailServer.MailServer mailServer) - throws InterruptedException { - MAIL_SERVER = mailServer; - System.setProperty("test.mail.server.port", "" + MAIL_SERVER.getPort()); - int n = 0; - while (n++ < 100 && (!MAIL_SERVER.isListening())) { - Thread.sleep(100); - } - assertThat(n < 100).isTrue(); + @BeforeAll + public static void setup() { + ServerSetup imap = ServerSetupTest.IMAP.dynamicPort(); + imap.setServerStartupTimeout(10000); + ServerSetup pop3 = ServerSetupTest.POP3.dynamicPort(); + pop3.setServerStartupTimeout(10000); + ServerSetup smtp = ServerSetupTest.SMTP.dynamicPort(); + smtp.setServerStartupTimeout(10000); + + mailServer = new GreenMail(new ServerSetup[]{imap, pop3, smtp}); + mailUser = mailServer.setUser("user", "pw"); + mailServer.start(); + String imapPort = Integer.toString(mailServer.getImap().getServerSetup().getPort()); + String pop3Port = Integer.toString(mailServer.getPop3().getServerSetup().getPort()); + String smtpPort = Integer.toString(mailServer.getPop3().getServerSetup().getPort()); + System.setProperty("test.mail.server.imap.port", imapPort); + System.setProperty("test.mail.server.pop3.port", pop3Port); + System.setProperty("test.mail.server.smtp.port", smtpPort); } @BeforeEach diff --git a/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapFailTests.java b/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapFailTests.java index 0a27c049..63b89f1a 100644 --- a/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapFailTests.java +++ b/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapFailTests.java @@ -16,8 +16,6 @@ package org.springframework.cloud.fn.supplier.mail; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import reactor.core.publisher.Flux; import reactor.test.StepVerifier; @@ -30,34 +28,29 @@ import org.springframework.test.context.TestPropertySource; import static org.assertj.core.api.Assertions.assertThat; -@Disabled // TODO add test container based solution @TestPropertySource(properties = { - "mail.supplier.url=imap://user:pw@localhost:${test.mail.server.port}/INBOX", - "mail.supplier.charset=cp1251"}) + "mail.supplier.url=imap://user:pw@localhost:${test.mail.server.imap.port}/INBOX", + "mail.supplier.charset=cp1251"}) public class ImapFailTests extends AbstractMailSupplierTests { @Autowired - MailToStringTransformer mailToStringTransformer; + protected MailToStringTransformer mailToStringTransformer; - @BeforeAll - public static void startImapServer() throws Throwable { - startMailServer(TestMailServer.imap(0)); - } @Test - public void testSimpleTest() throws Exception { - - assertThat(TestUtils.getPropertyValue(mailToStringTransformer, "charset").equals("cp1251")).isTrue(); - + public void testSimpleTest() { + // given + sendMessage("test", "foo"); + // when final Flux> messageFlux = mailSupplier.get(); - + // then + assertThat(TestUtils.getPropertyValue(mailToStringTransformer, "charset").equals("cp1251")).isTrue(); StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(((String) message.getPayload()).equals("Test Mail")).isFalse(); - } - ) - .thenCancel() - .verify(); - + .assertNext((message) -> { + assertThat(((String) message.getPayload())).isNotEqualTo("Test Mail"); + } + ) + .thenCancel() + .verify(); } } diff --git a/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapIdleFailTests.java b/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapIdleFailTests.java index 144300f9..001f041e 100644 --- a/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapIdleFailTests.java +++ b/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapIdleFailTests.java @@ -16,8 +16,6 @@ package org.springframework.cloud.fn.supplier.mail; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import reactor.core.publisher.Flux; import reactor.test.StepVerifier; @@ -27,29 +25,23 @@ import org.springframework.test.context.TestPropertySource; import static org.assertj.core.api.Assertions.assertThat; -@Disabled // TODO add test container based solution @TestPropertySource(properties = { - "mail.supplier.idle-imap=true", - "mail.supplier.url=imap://user:pw@localhost:${test.mail.server.port}/INBOX"}) + "mail.supplier.idle-imap=true", + "mail.supplier.url=imap://user:pw@localhost:${test.mail.server.imap.port}/INBOX"}) public class ImapIdleFailTests extends AbstractMailSupplierTests { - - - @BeforeAll - public static void startImapServer() throws Throwable { - startMailServer(TestMailServer.imap(0)); - } - @Test - public void testSimpleTest() throws Exception { - + public void testSimpleTest() { + // given + sendMessage("test", "foo"); + // when final Flux> messageFlux = mailSupplier.get(); - + // then StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(((String) message.getPayload()).equals("Test Mail")).isFalse(); - } - ) - .thenCancel() - .verify(); + .assertNext((message) -> { + assertThat(((String) message.getPayload())).isNotEqualTo("Test Mail"); + } + ) + .thenCancel() + .verify(); } } diff --git a/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapIdlePassTests.java b/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapIdlePassTests.java index dd25e4da..1ed7aec3 100644 --- a/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapIdlePassTests.java +++ b/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapIdlePassTests.java @@ -16,8 +16,6 @@ package org.springframework.cloud.fn.supplier.mail; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import reactor.core.publisher.Flux; import reactor.test.StepVerifier; @@ -27,28 +25,25 @@ import org.springframework.test.context.TestPropertySource; import static org.assertj.core.api.Assertions.assertThat; -@Disabled // TODO add test container based solution @TestPropertySource(properties = { - "mail.supplier.idle-imap=true", - "mail.supplier.url=imap://user:pw@localhost:${test.mail.server.port}/INBOX"}) + "mail.supplier.idle-imap=true", + "mail.supplier.url=imap://user:pw@localhost:${test.mail.server.imap.port}/INBOX"}) public class ImapIdlePassTests extends AbstractMailSupplierTests { - @BeforeAll - public static void startImapServer() throws Throwable { - startMailServer(TestMailServer.imap(0)); - } - @Test - public void testSimpleTest() throws Exception { - + public void testSimpleTest() { + // given + sendMessage("test", "foo"); + // when final Flux> messageFlux = mailSupplier.get(); - + // then StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(((String) message.getPayload()).endsWith("\r\n\r\nfoo\r\n\r\n")); - } - ) - .thenCancel() - .verify(); + .assertNext((message) -> { + System.out.println("Message:" + message); + assertThat(((String) message.getPayload())).isEqualTo("foo"); + } + ) + .thenCancel() + .verify(); } } diff --git a/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapPassTests.java b/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapPassTests.java index bacc200a..97cc2a3f 100644 --- a/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapPassTests.java +++ b/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/ImapPassTests.java @@ -16,10 +16,13 @@ package org.springframework.cloud.fn.supplier.mail; +import java.io.UnsupportedEncodingException; import java.util.List; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; +import com.icegreen.greenmail.util.GreenMailUtil; +import jakarta.mail.MessagingException; +import jakarta.mail.internet.InternetAddress; +import jakarta.mail.internet.MimeMessage; import org.junit.jupiter.api.Test; import reactor.core.publisher.Flux; import reactor.test.StepVerifier; @@ -31,33 +34,34 @@ import org.springframework.test.context.TestPropertySource; import static org.assertj.core.api.Assertions.assertThat; -@Disabled // TODO add test container based solution -@TestPropertySource(properties = "mail.supplier.url=imap://user:pw@localhost:${test.mail.server.port}/INBOX") +@TestPropertySource(properties = "mail.supplier.url=imap://user:pw@localhost:${test.mail.server.imap.port}/INBOX") public class ImapPassTests extends AbstractMailSupplierTests { - @BeforeAll - public static void startImapServer() throws Throwable { - startMailServer(TestMailServer.imap(0)); - } @Test - public void testSimpleTest() { - + public void testSimpleTest() throws UnsupportedEncodingException, MessagingException { + // given + MimeMessage mailMessage = GreenMailUtil.createTextEmail("bar@foo", "test@test", "test", "foo", mailServer.getSmtp().getServerSetup()); + mailMessage.addRecipients(jakarta.mail.Message.RecipientType.TO, new InternetAddress[]{new InternetAddress("foo@bar", "Foo")}); + mailMessage.addRecipients(jakarta.mail.Message.RecipientType.CC, new InternetAddress[]{new InternetAddress("a@b"), new InternetAddress("c@d")}); + mailMessage.addRecipients(jakarta.mail.Message.RecipientType.BCC, new InternetAddress[]{new InternetAddress("e@f"), new InternetAddress("g@h")}); + mailUser.deliver(mailMessage); + // when final Flux> messageFlux = mailSupplier.get(); - + // then StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(((String) message.getPayload()).endsWith("\r\n\r\nfoo\r\n\r\n")); - MessageHeaders headers = message.getHeaders(); - assertThat(headers.get(MailHeaders.TO)).isInstanceOf(List.class); - assertThat(headers.get(MailHeaders.CC)).isInstanceOf(List.class); - assertThat(headers.get(MailHeaders.BCC)).isInstanceOf(List.class); - assertThat(headers.get(MailHeaders.TO).toString()).isEqualTo("[Foo ]"); - assertThat(headers.get(MailHeaders.CC).toString()).isEqualTo("[a@b, c@d]"); - assertThat(headers.get(MailHeaders.BCC).toString()).isEqualTo("[e@f, g@h]"); - } - ) - .thenCancel() - .verify(); + .assertNext((message) -> { + assertThat(((String) message.getPayload())).isEqualTo("foo"); + MessageHeaders headers = message.getHeaders(); + assertThat(headers.get(MailHeaders.TO)).isInstanceOf(List.class); + assertThat(headers.get(MailHeaders.CC)).isInstanceOf(List.class); + assertThat(headers.get(MailHeaders.BCC)).isInstanceOf(List.class); + assertThat(headers.get(MailHeaders.TO).toString()).isEqualTo("[bar@foo, Foo ]"); + assertThat(headers.get(MailHeaders.CC).toString()).isEqualTo("[a@b, c@d]"); + assertThat(headers.get(MailHeaders.BCC).toString()).isEqualTo("[e@f, g@h]"); + } + ) + .thenCancel() + .verify(); } } diff --git a/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/Pop3FailTests.java b/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/Pop3FailTests.java index 8ec32fdd..52a17c88 100644 --- a/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/Pop3FailTests.java +++ b/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/Pop3FailTests.java @@ -16,8 +16,6 @@ package org.springframework.cloud.fn.supplier.mail; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import reactor.core.publisher.Flux; import reactor.test.StepVerifier; @@ -27,27 +25,24 @@ import org.springframework.test.context.TestPropertySource; import static org.assertj.core.api.Assertions.assertThat; -@Disabled // TODO add test container based solution -@TestPropertySource(properties = "mail.supplier.url=pop3://user:pw@localhost:${test.mail.server.port}/INBOX") +@TestPropertySource(properties = "mail.supplier.url=pop3://user:pw@localhost:${test.mail.server.pop3.port}/INBOX") public class Pop3FailTests extends AbstractMailSupplierTests { - @BeforeAll - public static void startImapServer() throws Throwable { - startMailServer(TestMailServer.pop3(0)); - } @Test - public void testSimpleTest() throws Exception { - + public void testSimpleTest() { + // given + sendMessage("test", "foo"); + // when final Flux> messageFlux = mailSupplier.get(); - + // then StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(((String) message.getPayload()).equals("Test Mail")).isFalse(); - } - ) - .thenCancel() - .verify(); + .assertNext((message) -> { + assertThat(((String) message.getPayload())).isNotEqualTo("Test Mail"); + } + ) + .thenCancel() + .verify(); } } diff --git a/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/Pop3PassTests.java b/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/Pop3PassTests.java index 0b465d38..fb1166d7 100644 --- a/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/Pop3PassTests.java +++ b/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/Pop3PassTests.java @@ -16,8 +16,6 @@ package org.springframework.cloud.fn.supplier.mail; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import reactor.core.publisher.Flux; import reactor.test.StepVerifier; @@ -27,26 +25,23 @@ import org.springframework.test.context.TestPropertySource; import static org.assertj.core.api.Assertions.assertThat; -@Disabled // TODO add test container based solution -@TestPropertySource(properties = "mail.supplier.url=pop3://user:pw@localhost:${test.mail.server.port}/INBOX") +@TestPropertySource(properties = "mail.supplier.url=pop3://user:pw@localhost:${test.mail.server.pop3.port}/INBOX") public class Pop3PassTests extends AbstractMailSupplierTests { - @BeforeAll - public static void startImapServer() throws Throwable { - startMailServer(TestMailServer.pop3(0)); - } @Test - public void testSimpleTest() throws Exception { + public void testSimpleTest() { + // given + sendMessage("test", "foo"); final Flux> messageFlux = mailSupplier.get(); StepVerifier.create(messageFlux) - .assertNext((message) -> { - assertThat(((String) message.getPayload()).endsWith("foo\r\n\r\n")); - } - ) - .thenCancel() - .verify(); + .assertNext((message) -> { + assertThat(((String) message.getPayload())).contains("foo"); + } + ) + .thenCancel() + .verify(); } } diff --git a/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/TestMailServer.java b/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/TestMailServer.java deleted file mode 100644 index 44b1c257..00000000 --- a/supplier/mail-supplier/src/test/java/org/springframework/cloud/fn/supplier/mail/TestMailServer.java +++ /dev/null @@ -1,551 +0,0 @@ -/* - * Copyright 2014-2021 the original author or authors. - * - * Licensed 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 - * - * https://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.springframework.cloud.fn.supplier.mail; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.net.ServerSocket; -import java.net.Socket; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import javax.net.ServerSocketFactory; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.util.Base64Utils; - -/** - * A basic test mail server for pop3, imap, - * Serves up a canned email message with each protocol. - * For smtp, it handles the basic handshaking and captures - * the pertinent data so it can be verified by a test case. - * - * @author Gary Russell - * @author Artem Bilan - * - * @since 5.0 - * - * @deprecated since 5.5 in favor of GreenMail library for mail testing. - * - */ -@Deprecated -public final class TestMailServer { - - private TestMailServer() { - } - - public static SmtpServer smtp(int port) { - try { - return new SmtpServer(port); - } - catch (IOException e) { - throw new IllegalStateException(e); - } - } - - public static Pop3Server pop3(int port) { - try { - return new Pop3Server(port); - } - catch (IOException e) { - throw new IllegalStateException(e); - } - } - - public static ImapServer imap(int port) { - try { - return new ImapServer(port); - } - catch (IOException e) { - throw new IllegalStateException(e); - } - } - - public static class SmtpServer extends MailServer { - - SmtpServer(int port) throws IOException { - super(port); - } - - @Override - protected MailHandler mailHandler(Socket socket) { - return new SmtpHandler(socket); - } - - class SmtpHandler extends MailHandler { - - SmtpHandler(Socket socket) { - super(socket); - } - - @Override // NOSONAR - void doRun() { // NOSONAR - try { - write("220 foo SMTP"); - while (!socket.isClosed()) { - String line = reader.readLine(); - if (line == null) { - break; - } - if (line.contains("EHLO")) { - write("250-foo hello [0,0,0,0], foo"); - write("250-AUTH LOGIN PLAIN"); - write("250 OK"); - } - else if (line.contains("MAIL FROM")) { - write("250 OK"); - } - else if (line.contains("RCPT TO")) { - write("250 OK"); - } - else if (line.contains("AUTH LOGIN")) { - write("334 VXNlcm5hbWU6"); - } - else if (line.contains("dXNlcg==")) { // base64 'user' - sb.append("user:"); - sb.append((new String(Base64Utils.decode(line.getBytes())))); - sb.append("\n"); - write("334 UGFzc3dvcmQ6"); - } - else if (line.contains("cHc=")) { // base64 'pw' - sb.append("password:"); - sb.append((new String(Base64Utils.decode(line.getBytes())))); - sb.append("\n"); - write("235"); - } - else if (line.equals("DATA")) { - write("354"); - } - else if (line.equals(".")) { - write("250"); - } - else if (line.equals("QUIT")) { - write("221"); - socket.close(); - } - else { - sb.append(line); - sb.append("\n"); - } - } - messages.add(sb.toString()); - } - catch (IOException e) { - if (!this.stopped) { - LOGGER.error(IO_EXCEPTION, e); - } - } - } - - } - - } - - public static class Pop3Server extends MailServer { - - Pop3Server(int port) throws IOException { - super(port); - } - - @Override - protected MailHandler mailHandler(Socket socket) { - return new Pop3Handler(socket); - } - - class Pop3Handler extends MailHandler { - - private static final String PLUS_OK = "+OK"; - - Pop3Handler(Socket socket) { - super(socket); - } - - @Override // NOSONAR - void doRun() { - try { - write("+OK POP3"); - while (!socket.isClosed()) { - String line = reader.readLine(); - if (line == null) { - break; - } - switch (line) { - case "CAPA": - write(PLUS_OK); - write("USER"); - write("."); - break; - case "USER user": - case "PASS pw": - case "NOOP": - write(PLUS_OK); - break; - case "STAT": - write("+OK 1 3"); - break; - case "RETR 1": - write(PLUS_OK); - write(MESSAGE); - write("."); - break; - case "QUIT": - write(PLUS_OK); - socket.close(); - break; - default: - throw new UnsupportedOperationException(line); - } - } - } - catch (IOException e) { - if (!this.stopped) { - LOGGER.error(IO_EXCEPTION, e); - } - } - } - - } - - } - - public static class ImapServer extends MailServer { - - private volatile boolean seen; - - private volatile boolean idled; - - ImapServer(int port) throws IOException { - super(port); - } - - @Override - public void resetServer() { - super.resetServer(); - this.seen = false; - this.idled = false; - } - - @Override - protected MailHandler mailHandler(Socket socket) { - return new ImapHandler(socket); - } - - class ImapHandler extends MailHandler { - - private static final String OK_FETCH_COMPLETED = "OK FETCH completed"; - - /** - * Time to wait while IDLE before returning a result. - */ - private static final int IDLE_WAIT_TIME = 500; - - ImapHandler(Socket socket) { - super(socket); - } - - @Override // NOSONAR - void doRun() { - try { - write("* OK IMAP4rev1 Service Ready"); - String idleTag = ""; - while (!socket.isClosed()) { - String line = reader.readLine(); - if (line == null) { - break; - } - String tag = line.substring(0, line.indexOf(' ') + 1); - if (line.endsWith("CAPABILITY")) { - write("* CAPABILITY IDLE IMAP4rev1"); - write(tag + "OK CAPABILITY completed"); - } - else if (line.endsWith("LOGIN user pw")) { - write(tag + "OK LOGIN completed"); - } - else if (line.endsWith("LIST \"\" INBOX")) { - write("* LIST \"/\" \"INBOX\""); - write(tag + "OK LIST completed"); - } - else if (line.endsWith("LIST \"\" \"\"")) { - write("* LIST \"/\" \"\""); - write(tag + "OK LIST completed"); - } - else if (line.endsWith("SELECT INBOX")) { - write("* 1 EXISTS"); - if (!seen) { - write("* 1 RECENT"); - write("* OK [UNSEEN 1]"); - } - else { - write("* OK"); - } - write("* OK [PERMANENTFLAGS (\\Deleted \\Seen \\*)]"); // \* - user flags allowed - write(tag + "OK SELECT completed"); - } - else if (line.endsWith("EXAMINE INBOX")) { - write(tag + "OK"); - } - else if (line.endsWith("SEARCH FROM bar@baz UNSEEN ALL")) { - searchReply(tag); - } - else if (line.endsWith("SEARCH NOT (DELETED) NOT (SEEN) NOT (KEYWORD testSIUserFlag) ALL")) { - searchReply(tag); - assertions.add("searchWithUserFlag"); - } - else if (line.contains("FETCH 1 (ENVELOPE")) { - write("* 1 FETCH (RFC822.SIZE " - + MESSAGE.length() - + " INTERNALDATE \"27-May-2013 09:45:41 +0000\" " - + "FLAGS (\\Seen) " - + "ENVELOPE (\"Mon, 27 May 2013 15:14:49 +0530\" " - + "\"Test Email\" " - + "((\"Bar\" NIL \"bar\" \"baz\")) " // From - + "((\"Bar\" NIL \"bar\" \"baz\")) " // Sender - + "((\"Bar\" NIL \"bar\" \"baz\")) " // Reply To - + "((\"Foo\" NIL \"foo\" \"bar\")) " // To - + "((NIL NIL \"a\" \"b\") (NIL NIL \"c\" \"d\")) " // cc - + "((NIL NIL \"e\" \"f\") (NIL NIL \"g\" \"h\")) " // bcc - + "\"<4DA0A7E4.3010506@baz.net>\" " // In reply to - + "\"\") " // msgid - + "BODYSTRUCTURE " - + "(\"TEXT\" \"PLAIN\" (\"CHARSET\" \"ISO-8859-1\") NIL NIL \"7BIT\" 1 5)))"); - write(tag + OK_FETCH_COMPLETED); - } - else if (line.contains("FETCH 2 (BODYSTRUCTURE)")) { - write("* 2 FETCH " + - "BODYSTRUCTURE " - + "(\"TEXT\" \"PLAIN\" (\"CHARSET\" \"ISO-8859-1\") NIL NIL \"7BIT\" 1 5)))"); - write(tag + OK_FETCH_COMPLETED); - } - else if (line.contains("STORE 1 +FLAGS (\\Flagged)")) { - write("* 1 FETCH (FLAGS (\\Flagged))"); - write(tag + "OK STORE completed"); - } - else if (line.contains("STORE 1 +FLAGS (\\Seen)")) { - write("* 1 FETCH (FLAGS (\\Flagged \\Seen))"); - write(tag + "OK STORE completed"); - seen = true; - } - else if (line.contains("FETCH 1 FLAGS")) { - write("* 1 FLAGS(\\Seen)"); - write(tag + OK_FETCH_COMPLETED); - } - else if (line.contains("FETCH 1 (BODY.PEEK")) { - write("* 1 FETCH (BODY[]<0> {" + (MESSAGE.length() + 2) + "}"); - write(MESSAGE); - write(")"); - write(tag + OK_FETCH_COMPLETED); - } - else if (line.contains("CLOSE")) { - write(tag + "OK CLOSE completed"); - } - else if (line.contains("NOOP")) { - write(tag + "OK NOOP completed"); - } - else if (line.endsWith("STORE 1 +FLAGS (testSIUserFlag)")) { - write(tag + "OK STORE completed"); - assertions.add("storeUserFlag"); - } - else if (line.endsWith("IDLE")) { - write("+ idling"); - idleTag = tag; - if (!idled) { - try { - Thread.sleep(IDLE_WAIT_TIME); - write("* 2 EXISTS"); - seen = false; - } - catch (@SuppressWarnings("unused") InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - idled = true; - } - else if (line.equals("DONE")) { - write(idleTag + "OK"); - } - else if (line.contains("LOGOUT")) { - write(tag + "OK LOGOUT completed"); - this.socket.close(); - } - } - } - catch (IOException e) { - if (!this.stopped) { - LOGGER.error(IO_EXCEPTION, e); - } - } - } // NOSONAR - - void searchReply(String tag) throws IOException { - if (seen) { - write("* SEARCH"); - } - else { - write("* SEARCH 1"); - } - write(tag + "OK SEARCH completed"); - } - - } - - } - - public abstract static class MailServer implements Runnable { - - protected final Log LOGGER = LogFactory.getLog(getClass()); // NOSONAR - - protected static final String IO_EXCEPTION = "IOException"; // NOSONAR - - private final ServerSocket serverSocket; - - private final ExecutorService exec = Executors.newCachedThreadPool(); - - protected final Set assertions = new HashSet<>(); // NOSONAR protected - - protected final List messages = new ArrayList<>(); // NOSONAR protected - - private final List handlers = new ArrayList<>(); - - private volatile boolean listening; - - MailServer(int port) throws IOException { - this.serverSocket = ServerSocketFactory.getDefault().createServerSocket(port); - this.listening = true; - exec.execute(this); - } - - public int getPort() { - return this.serverSocket.getLocalPort(); - } - - public boolean isListening() { - return listening; - } - - public List getMessages() { - return messages; - } - - public void resetServer() { - this.assertions.clear(); - } - - public boolean assertReceived(String assertion) { - return this.assertions.contains(assertion); - } - - @Override - public void run() { - try { - while (!serverSocket.isClosed()) { - Socket socket = this.serverSocket.accept(); - MailHandler mailHandler = mailHandler(socket); - this.handlers.add(mailHandler); - exec.execute(mailHandler); - } - } - catch (@SuppressWarnings("unused") IOException e) { - this.listening = false; - } - } - - protected abstract MailHandler mailHandler(Socket socket); - - public void stop() { - try { - for (MailHandler handler : this.handlers) { - handler.stop(); - } - this.serverSocket.close(); - } - catch (IOException e) { - LOGGER.error(IO_EXCEPTION, e); - } - this.exec.shutdownNow(); - } - - public abstract class MailHandler implements Runnable { - - public static final String BODY = "foo\r\n"; - - public static final String MESSAGE = - "To: Foo \r\n" - + "cc: a@b, c@d\r\n" - + "bcc: e@f, g@h\r\n" - + "From: Bar , Bar2 \r\n" - + "Subject: Test Email\r\n" - + "\r\n" + BODY; - - protected final Socket socket; // NOSONAR protected - - private BufferedWriter writer; - - protected StringBuilder sb = new StringBuilder(); // NOSONAR protected - - protected BufferedReader reader; // NOSONAR protected - - protected boolean stopped; // NOSONAR - - MailHandler(Socket socket) { - this.socket = socket; - } - - @Override - public void run() { - try { - this.reader = new BufferedReader(new InputStreamReader(this.socket.getInputStream())); - this.writer = new BufferedWriter(new OutputStreamWriter(this.socket.getOutputStream())); - } - catch (IOException e) { - LOGGER.error(IO_EXCEPTION, e); - } - doRun(); - } - - protected void write(String str) throws IOException { - this.writer.write(str); - this.writer.write("\r\n"); - this.writer.flush(); - } - - abstract void doRun(); - - void stop() { - this.stopped = true; - try { - this.socket.close(); - } - catch (IOException e) { - // NOSONAR - } - } - - } - - } - - -}