Added GreenMail.
Update all tests for mail-supplier and mail-sink.
This commit is contained in:
@@ -28,9 +28,25 @@
|
||||
<version>${jakarta-mail.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.mail</groupId>
|
||||
<groupId>org.eclipse.angus</groupId>
|
||||
<artifactId>jakarta.mail</artifactId>
|
||||
<version>[2.0.1,)</version>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.icegreen</groupId>
|
||||
<artifactId>greenmail-junit5</artifactId>
|
||||
<version>2.0.0-alpha-3</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.sun.mail</groupId>
|
||||
<artifactId>jakarta.mail</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>jakarta.activation</groupId>
|
||||
<artifactId>jakarta.activation-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -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<Message<Object>> mailInboundFlow(MessageProducerSupport messageProducer) {
|
||||
|
||||
return IntegrationFlows.from(messageProducer)
|
||||
return IntegrationFlow.from(messageProducer)
|
||||
.transform(Mail.toStringTransformer(this.properties.getCharset()))
|
||||
.enrichHeaders(h -> h
|
||||
.defaultOverwrite(true)
|
||||
|
||||
@@ -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<Flux<Message<?>>> 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
|
||||
|
||||
@@ -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<Message<?>> 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Message<?>> 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Message<?>> 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Message<?>> 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 <foo@bar>]");
|
||||
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 <foo@bar>]");
|
||||
assertThat(headers.get(MailHeaders.CC).toString()).isEqualTo("[a@b, c@d]");
|
||||
assertThat(headers.get(MailHeaders.BCC).toString()).isEqualTo("[e@f, g@h]");
|
||||
}
|
||||
)
|
||||
.thenCancel()
|
||||
.verify();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Message<?>> 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<Message<?>> 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();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
+ "\"<CACVnpJkAUUfa3d_-4GNZW2WpxbB39tBCHC=T0gc7hty6dOEHcA@foo.bar.com>\") " // 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<String> assertions = new HashSet<>(); // NOSONAR protected
|
||||
|
||||
protected final List<String> messages = new ArrayList<>(); // NOSONAR protected
|
||||
|
||||
private final List<MailHandler> 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<String> 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 <foo@bar>\r\n"
|
||||
+ "cc: a@b, c@d\r\n"
|
||||
+ "bcc: e@f, g@h\r\n"
|
||||
+ "From: Bar <bar@baz>, Bar2 <bar2@baz>\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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user