GH-3451: Use GreenMail for testing instead

Fixes https://github.com/spring-projects/spring-integration/issues/3451

The GreenMail provides a comprehensive support for e-mail scenarios
testing.

* Use GreenMail instead our own `TestMailServer` for better and broader
support
* Convert SmtpTests and Pop3Tests to GreenMail
* Document that Pop3MailReceiver does not support autoCloseFolder=false
* Pop3MailReceiver uses `folder.getMessageCount()` to determine if there
are new messages.
This count only gets updated when opening the folder.
* Use GreenMail for remaining mail tests
* convert MailTests and ImapMailReceiverTests to GreenMail
* remove duplicate mail dependencies
* route com.sun.mail logging to log4j (via jul and slf4j)
This commit is contained in:
Alexander Pinske
2021-04-09 16:47:25 -04:00
committed by Artem Bilan
parent 13005dfdcd
commit 996daca228
9 changed files with 223 additions and 140 deletions

View File

@@ -60,6 +60,7 @@ ext {
derbyVersion = '10.14.2.0'
ftpServerVersion = '1.1.1'
googleJsr305Version = '3.0.2'
greenmailVersion = '1.6.4'
groovyVersion = '3.0.8'
hamcrestVersion = '2.2'
hazelcastVersion = '4.2'
@@ -641,9 +642,9 @@ project('spring-integration-mail') {
api project(':spring-integration-core')
api 'org.springframework:spring-context-support'
providedImplementation "jakarta.mail:jakarta.mail-api:$mailVersion"
providedImplementation "com.sun.mail:imap:$mailVersion"
providedImplementation "com.sun.mail:jakarta.mail:$mailVersion"
testImplementation "com.icegreen:greenmail:$greenmailVersion"
testRuntimeOnly 'org.apache.logging.log4j:log4j-jul'
}
}

View File

@@ -31,12 +31,18 @@ import static org.mockito.Mockito.verify;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import javax.mail.Flags;
import javax.mail.Flags.Flag;
@@ -72,8 +78,6 @@ import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
import org.springframework.integration.history.MessageHistory;
import org.springframework.integration.mail.support.DefaultMailHeaderMapper;
import org.springframework.integration.test.mail.TestMailServer;
import org.springframework.integration.test.mail.TestMailServer.ImapServer;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.PollableChannel;
@@ -84,6 +88,11 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.util.MimeTypeUtils;
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 com.sun.mail.imap.IMAPFolder;
/**
@@ -100,31 +109,43 @@ public class ImapMailReceiverTests {
private AtomicInteger failed;
private ImapServer imapIdleServer;
private GreenMail imapIdleServer;
private GreenMailUser user;
@Autowired
private ApplicationContext context;
static {
System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager");
}
private final ImapSearchLoggingHandler imapSearches = new ImapSearchLoggingHandler();
@BeforeEach
public void setup() throws InterruptedException {
public void setup() {
LogManager.getLogManager().getLogger("").setLevel(Level.ALL);
imapSearches.searches.clear();
imapSearches.stores.clear();
LogManager.getLogManager().getLogger("").addHandler(imapSearches);
failed = new AtomicInteger(0);
this.imapIdleServer = TestMailServer.imap(0);
int n = 0;
while (n++ < 100 && (!this.imapIdleServer.isListening())) {
Thread.sleep(100);
}
assertThat(n < 100).isTrue();
ServerSetup imap = ServerSetupTest.IMAP.dynamicPort();
imap.setServerStartupTimeout(10000);
imapIdleServer = new GreenMail(imap);
user = imapIdleServer.setUser("user", "pw");
imapIdleServer.start();
}
@AfterEach
public void tearDown() {
this.imapIdleServer.stop();
LogManager.getLogManager().getLogger("").removeHandler(imapSearches);
}
@Test
public void testIdleWithServerCustomSearch() throws Exception {
ImapMailReceiver receiver =
new ImapMailReceiver("imap://user:pw@localhost:" + this.imapIdleServer.getPort() + "/INBOX");
new ImapMailReceiver("imap://user:pw@localhost:" + this.imapIdleServer.getImap().getPort() + "/INBOX");
receiver.setSearchTermStrategy((supportedFlags, folder) -> {
try {
FromTerm fromTerm = new FromTerm(new InternetAddress("bar@baz"));
@@ -140,15 +161,15 @@ public class ImapMailReceiverTests {
@Test
public void testIdleWithServerDefaultSearch() throws Exception {
ImapMailReceiver receiver =
new ImapMailReceiver("imap://user:pw@localhost:" + this.imapIdleServer.getPort() + "/INBOX");
new ImapMailReceiver("imap://user:pw@localhost:" + this.imapIdleServer.getImap().getPort() + "/INBOX");
testIdleWithServerGuts(receiver, false);
assertThat(this.imapIdleServer.assertReceived("searchWithUserFlag")).isTrue();
assertThat(imapSearches.searches.get(0)).contains("testSIUserFlag");
}
@Test
public void testIdleWithMessageMapping() throws Exception {
ImapMailReceiver receiver =
new ImapMailReceiver("imap://user:pw@localhost:" + this.imapIdleServer.getPort() + "/INBOX");
new ImapMailReceiver("imap://user:pw@localhost:" + this.imapIdleServer.getImap().getPort() + "/INBOX");
receiver.setHeaderMapper(new DefaultMailHeaderMapper());
testIdleWithServerGuts(receiver, true);
}
@@ -156,16 +177,16 @@ public class ImapMailReceiverTests {
@Test
public void testIdleWithServerDefaultSearchSimple() throws Exception {
ImapMailReceiver receiver =
new ImapMailReceiver("imap://user:pw@localhost:" + this.imapIdleServer.getPort() + "/INBOX");
new ImapMailReceiver("imap://user:pw@localhost:" + this.imapIdleServer.getImap().getPort() + "/INBOX");
receiver.setSimpleContent(true);
testIdleWithServerGuts(receiver, false, true);
assertThat(this.imapIdleServer.assertReceived("searchWithUserFlag")).isTrue();
assertThat(imapSearches.searches.get(0)).contains("testSIUserFlag");
}
@Test
public void testIdleWithMessageMappingSimple() throws Exception {
ImapMailReceiver receiver =
new ImapMailReceiver("imap://user:pw@localhost:" + this.imapIdleServer.getPort() + "/INBOX");
new ImapMailReceiver("imap://user:pw@localhost:" + this.imapIdleServer.getImap().getPort() + "/INBOX");
receiver.setSimpleContent(true);
receiver.setHeaderMapper(new DefaultMailHeaderMapper());
testIdleWithServerGuts(receiver, true, true);
@@ -176,10 +197,6 @@ public class ImapMailReceiverTests {
}
public void testIdleWithServerGuts(ImapMailReceiver receiver, boolean mapped, boolean simple) throws Exception {
Properties mailProps = new Properties();
mailProps.put("mail.debug", "true");
mailProps.put("mail.imap.connectionpool.debug", "true");
receiver.setJavaMailProperties(mailProps);
receiver.setMaxFetchSize(1);
receiver.setShouldDeleteMessages(false);
receiver.setShouldMarkMessagesAsRead(true);
@@ -193,6 +210,14 @@ public class ImapMailReceiverTests {
adapter.setTaskScheduler(taskScheduler);
adapter.setReconnectDelay(1);
adapter.start();
MimeMessage message =
GreenMailUtil.createTextEmail("Foo <foo@bar>", "Bar <bar@baz>", "Test Email", "foo\r\n",
imapIdleServer.getImap().getServerSetup());
message.setRecipients(Message.RecipientType.CC, "a@b, c@d");
message.setRecipients(Message.RecipientType.BCC, "e@f, g@h");
user.deliver(message);
user.deliver(GreenMailUtil.createTextEmail("to", "Bar <bar@baz>", "subject", "body",
imapIdleServer.getImap().getServerSetup()));
if (!mapped) {
@SuppressWarnings("unchecked")
org.springframework.messaging.Message<MimeMessage> received =
@@ -202,11 +227,11 @@ public class ImapMailReceiverTests {
assertThat(received.getPayload().getLineCount() > -1).isTrue();
if (simple) {
assertThat(received.getPayload().getContent())
.isEqualTo(TestMailServer.MailServer.MailHandler.BODY + "\r\n");
.isEqualTo("foo\r\n");
}
else {
assertThat(received.getPayload().getContent())
.isEqualTo(TestMailServer.MailServer.MailHandler.MESSAGE + "\r\n");
.isEqualTo("foo");
}
}
else {
@@ -214,7 +239,7 @@ public class ImapMailReceiverTests {
assertThat(received).isNotNull();
MessageHeaders headers = received.getHeaders();
assertThat(headers.get(MailHeaders.RAW_HEADERS)).isNotNull();
assertThat(headers.get(MailHeaders.CONTENT_TYPE)).isEqualTo("TEXT/PLAIN; charset=ISO-8859-1");
assertThat(headers.get(MailHeaders.CONTENT_TYPE)).isEqualTo("TEXT/PLAIN; charset=us-ascii");
assertThat(headers.get(MessageHeaders.CONTENT_TYPE)).isEqualTo(MimeTypeUtils.TEXT_PLAIN_VALUE);
assertThat(headers.get(MailHeaders.FROM)).isEqualTo("Bar <bar@baz>");
String[] toHeader = headers.get(MailHeaders.TO, String[].class);
@@ -224,10 +249,10 @@ public class ImapMailReceiverTests {
assertThat(Arrays.toString(headers.get(MailHeaders.BCC, String[].class))).isEqualTo("[e@f, g@h]");
assertThat(headers.get(MailHeaders.SUBJECT)).isEqualTo("Test Email");
if (simple) {
assertThat(received.getPayload()).isEqualTo(TestMailServer.MailServer.MailHandler.BODY + "\r\n");
assertThat(received.getPayload()).isEqualTo("foo\r\n");
}
else {
assertThat(received.getPayload()).isEqualTo(TestMailServer.MailServer.MailHandler.MESSAGE + "\r\n");
assertThat(received.getPayload()).isEqualTo("foo");
}
}
assertThat(channel.receive(20000)).isNotNull(); // new message after idle
@@ -235,11 +260,13 @@ public class ImapMailReceiverTests {
adapter.stop();
taskScheduler.shutdown();
assertThat(this.imapIdleServer.assertReceived("storeUserFlag")).isTrue();
assertThat(imapSearches.stores.get(0)).contains("testSIUserFlag");
}
@Test
public void receiveAndMarkAsReadDontDelete() throws Exception {
user.deliver(GreenMailUtil.createTextEmail("user", "sender", "subject", "body",
imapIdleServer.getImap().getServerSetup()));
AbstractMailReceiver receiver = new ImapMailReceiver();
Message msg1 = mock(MimeMessage.class);
Message msg2 = mock(MimeMessage.class);
@@ -898,4 +925,40 @@ public class ImapMailReceiverTests {
mailReceiver.setBeanFactory(bf);
}
private static class ImapSearchLoggingHandler extends Handler {
private final List<String> searches = new ArrayList<>();
private final List<String> stores = new ArrayList<>();
private static final String SEARCH = " SEARCH ";
private static final String STORE = " STORE ";
@Override
public void publish(LogRecord record) {
if ("com.sun.mail.imap.protocol".equals(record.getLoggerName())) {
String message = record.getMessage();
if (!message.startsWith("*")) {
if (message.contains(SEARCH) && !message.contains(" OK ")) {
searches.add(message.substring(message.indexOf(SEARCH) + SEARCH.length()));
}
else if (message.contains(STORE) && !message.contains(" OK ")) {
stores.add(message.substring(message.indexOf(STORE) + STORE.length()));
}
}
}
}
@Override
public void flush() {
}
@Override
public void close() throws SecurityException {
}
}
}

View File

@@ -20,6 +20,10 @@ import static org.assertj.core.api.Assertions.assertThat;
import java.util.Arrays;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@@ -28,29 +32,36 @@ import org.springframework.integration.mail.MailHeaders;
import org.springframework.integration.mail.MailReceivingMessageSource;
import org.springframework.integration.mail.Pop3MailReceiver;
import org.springframework.integration.mail.support.DefaultMailHeaderMapper;
import org.springframework.integration.test.mail.TestMailServer;
import org.springframework.integration.test.mail.TestMailServer.Pop3Server;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
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;
/**
* @author Gary Russell
* @author Artem Bilan
* @author Alexander Pinske
*
* @since 5.0
*
*/
public class Pop3Tests {
private static final Pop3Server pop3Server = TestMailServer.pop3(0);
private static GreenMail pop3Server;
private static GreenMailUser user;
@BeforeAll
public static void setup() throws InterruptedException {
int n = 0;
while (n++ < 100 && (!pop3Server.isListening())) {
Thread.sleep(100);
}
assertThat(n < 100).isTrue();
public static void setup() {
ServerSetup pop3 = ServerSetupTest.POP3.dynamicPort();
pop3.setServerStartupTimeout(10000);
pop3Server = new GreenMail(pop3);
user = pop3Server.setUser("user", "pw");
pop3Server.start();
}
@AfterAll
@@ -59,8 +70,15 @@ public class Pop3Tests {
}
@Test
public void testPop3() {
Pop3MailReceiver receiver = new Pop3MailReceiver("localhost", pop3Server.getPort(), "user", "pw");
public void testPop3() throws MessagingException {
MimeMessage mimeMessage =
GreenMailUtil.createTextEmail("Foo <foo@bar>", "Bar <bar@baz>, Bar2 <bar2@baz>", "Test Email",
"foo\r\n", pop3Server.getPop3().getServerSetup());
mimeMessage.setRecipients(RecipientType.CC, "a@b, c@d");
mimeMessage.setRecipients(RecipientType.BCC, "e@f, g@h");
user.deliver(mimeMessage);
Pop3MailReceiver receiver = new Pop3MailReceiver("localhost", pop3Server.getPop3().getPort(), "user", "pw");
receiver.setHeaderMapper(new DefaultMailHeaderMapper());
MailReceivingMessageSource source = new MailReceivingMessageSource(receiver);
Message<?> message = source.receive();
@@ -71,7 +89,7 @@ public class Pop3Tests {
assertThat(Arrays.toString(headers.get(MailHeaders.BCC, String[].class))).isEqualTo("[e@f, g@h]");
assertThat(headers.get(MailHeaders.FROM)).isEqualTo("Bar <bar@baz>,Bar2 <bar2@baz>");
assertThat(headers.get(MailHeaders.SUBJECT)).isEqualTo("Test Email");
assertThat(message.getPayload()).isEqualTo("foo\r\n\r\n");
assertThat(message.getPayload()).isEqualTo("foo\r\n");
}
}

View File

@@ -18,6 +18,10 @@ package org.springframework.integration.mail.config;
import static org.assertj.core.api.Assertions.assertThat;
import javax.mail.Message.RecipientType;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@@ -25,28 +29,31 @@ import org.junit.jupiter.api.Test;
import org.springframework.integration.mail.MailHeaders;
import org.springframework.integration.mail.MailSendingMessageHandler;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.test.mail.TestMailServer;
import org.springframework.integration.test.mail.TestMailServer.SmtpServer;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import com.icegreen.greenmail.util.GreenMail;
import com.icegreen.greenmail.util.ServerSetup;
import com.icegreen.greenmail.util.ServerSetupTest;
/**
* @author Gary Russell
* @author Artem Bilan
* @author Alexander Pinske
*
* @since 5.0
*
*/
public class SmtpTests {
private static final SmtpServer smtpServer = TestMailServer.smtp(0);
private static GreenMail smtpServer;
@BeforeAll
public static void setup() throws InterruptedException {
int n = 0;
while (n++ < 100 && (!smtpServer.isListening())) {
Thread.sleep(100);
}
assertThat(n < 100).isTrue();
public static void setup() {
ServerSetup smtp = ServerSetupTest.SMTP.dynamicPort();
smtp.setServerStartupTimeout(10000);
smtpServer = new GreenMail(smtp);
smtpServer.setUser("user", "pw");
smtpServer.start();
}
@AfterAll
@@ -58,7 +65,7 @@ public class SmtpTests {
public void testSmtp() throws Exception {
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost("localhost");
mailSender.setPort(smtpServer.getPort());
mailSender.setPort(smtpServer.getSmtp().getPort());
mailSender.setUsername("user");
mailSender.setPassword("pw");
MailSendingMessageHandler handler = new MailSendingMessageHandler(mailSender);
@@ -69,19 +76,14 @@ public class SmtpTests {
.setHeader(MailHeaders.SUBJECT, "foo")
.build());
int n = 0;
while (n++ < 100 && smtpServer.getMessages().size() == 0) {
Thread.sleep(100);
}
assertThat(smtpServer.waitForIncomingEmail(10000, 1)).isTrue();
assertThat(smtpServer.getMessages().size() > 0).isTrue();
String message = smtpServer.getMessages().get(0);
assertThat(message)
.endsWith("foo\n")
.contains("foo@bar")
.contains("bar@baz")
.contains("user:user")
.contains("password:pw");
assertThat(smtpServer.getReceivedMessages().length > 0).isTrue();
MimeMessage message = smtpServer.getReceivedMessages()[0];
assertThat(message.getFrom()).containsOnly(new InternetAddress("foo@bar"));
assertThat(message.getRecipients(RecipientType.TO)).containsOnly(new InternetAddress("bar@baz"));
assertThat(message.getSubject()).isEqualTo("foo");
assertThat(message.getContent()).asString().isEqualTo("foo\r\n");
}
}

View File

@@ -19,7 +19,6 @@ package org.springframework.integration.mail.dsl;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.Closeable;
import java.io.IOException;
import java.util.Properties;
import javax.mail.Flags;
@@ -33,12 +32,12 @@ import javax.mail.search.FlagTerm;
import javax.mail.search.FromTerm;
import javax.mail.search.SearchTerm;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.SmartLifecycle;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.IntegrationMessageHeaderAccessor;
@@ -51,10 +50,6 @@ import org.springframework.integration.mail.MailHeaders;
import org.springframework.integration.mail.support.DefaultMailHeaderMapper;
import org.springframework.integration.mapping.HeaderMapper;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.test.mail.TestMailServer;
import org.springframework.integration.test.mail.TestMailServer.ImapServer;
import org.springframework.integration.test.mail.TestMailServer.Pop3Server;
import org.springframework.integration.test.mail.TestMailServer.SmtpServer;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
@@ -64,31 +59,41 @@ import org.springframework.messaging.PollableChannel;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import com.icegreen.greenmail.util.GreenMail;
import com.icegreen.greenmail.util.GreenMailUtil;
import com.icegreen.greenmail.util.ServerSetup;
import com.icegreen.greenmail.util.ServerSetupTest;
/**
* @author Gary Russell
* @author Artem Bilan
* @author Alexander Pinske
*/
@SpringJUnitConfig
@DirtiesContext
public class MailTests {
private static final SmtpServer smtpServer = TestMailServer.smtp(0);
private static final Pop3Server pop3Server = TestMailServer.pop3(0);
private static final ImapServer imapServer = TestMailServer.imap(0);
private static final ImapServer imapIdleServer = TestMailServer.imap(0);
private static GreenMail mailServer;
@BeforeAll
public static void setup() throws InterruptedException {
int n = 0;
while (n++ < 100 && (!smtpServer.isListening() || !pop3Server.isListening()
|| !imapServer.isListening()) || !imapIdleServer.isListening()) {
Thread.sleep(100);
}
assertThat(n < 100).isTrue();
public static void setup() {
ServerSetup smtp = ServerSetupTest.SMTP.dynamicPort();
smtp.setServerStartupTimeout(10000);
ServerSetup imap = ServerSetupTest.IMAP.dynamicPort();
imap.setServerStartupTimeout(10000);
ServerSetup pop3 = ServerSetupTest.POP3.dynamicPort();
pop3.setServerStartupTimeout(10000);
mailServer = new GreenMail(new ServerSetup[]{ smtp, pop3, imap });
mailServer.setUser("bar@baz", "smtpuser", "pw");
mailServer.setUser("popuser", "pw");
mailServer.setUser("imapuser", "pw");
mailServer.setUser("imapidleuser", "pw");
mailServer.start();
}
@AfterAll
static void tearDown() {
mailServer.stop();
}
@Autowired
@@ -120,56 +125,72 @@ public class MailTests {
this.sendMailChannel.send(MessageBuilder.withPayload("foo").build());
int n = 0;
while (n++ < 100 && smtpServer.getMessages().size() == 0) {
Thread.sleep(100);
}
mailServer.waitForIncomingEmail(10000, 1);
assertThat(smtpServer.getMessages().size() > 0).isTrue();
String message = smtpServer.getMessages().get(0);
assertThat(message).endsWith("foo\n");
assertThat(message).contains("foo@bar");
assertThat(message).contains("bar@baz");
assertThat(message).contains("user:user");
assertThat(message).contains("password:pw");
assertThat(mailServer.getReceivedMessagesForDomain("baz").length > 0).isTrue();
MimeMessage message = mailServer.getReceivedMessagesForDomain("baz")[0];
assertThat(message.getFrom()).containsOnly(new InternetAddress("foo@bar"));
assertThat(message.getRecipients(RecipientType.TO)).containsOnly(new InternetAddress("bar@baz"));
assertThat(message.getSubject()).isEqualTo("foo");
assertThat(message.getContent()).asString().isEqualTo("foo\r\n");
}
@Test
public void testPop3() throws IOException {
public void testPop3() throws Exception {
MimeMessage mimeMessage =
GreenMailUtil.createTextEmail("Foo <foo@bar>", "Bar <bar@baz>, Bar2 <bar2@baz>", "Test Email",
"foo\r\n", mailServer.getPop3().getServerSetup());
mimeMessage.setRecipients(RecipientType.CC, "a@b, c@d");
mimeMessage.setRecipients(RecipientType.BCC, "e@f, g@h");
mailServer.getUserManager().getUser("popuser").deliver(mimeMessage);
Message<?> message = this.pop3Channel.receive(10000);
assertThat(message).isNotNull();
MessageHeaders headers = message.getHeaders();
assertThat(headers.get(MailHeaders.TO, String[].class)).containsExactly("Foo <foo@bar>");
assertThat(headers.get(MailHeaders.FROM)).isEqualTo("Bar <bar@baz>,Bar2 <bar2@baz>");
assertThat(headers.get(MailHeaders.SUBJECT)).isEqualTo("Test Email");
assertThat(message.getPayload()).isEqualTo("foo\r\n\r\n");
assertThat(message.getHeaders().containsKey(IntegrationMessageHeaderAccessor.CLOSEABLE_RESOURCE)).isTrue();
message.getHeaders().get(IntegrationMessageHeaderAccessor.CLOSEABLE_RESOURCE, Closeable.class).close();
assertThat(message.getPayload()).isEqualTo("foo\r\n");
assertThat(message.getHeaders().containsKey(IntegrationMessageHeaderAccessor.CLOSEABLE_RESOURCE)).isFalse();
}
@Test
public void testImap() throws Exception {
MimeMessage mimeMessage =
GreenMailUtil.createTextEmail("Foo <foo@bar>", "Bar <bar@baz>", "Test Email", "foo\r\n",
mailServer.getImap().getServerSetup());
mimeMessage.setRecipients(RecipientType.CC, "a@b, c@d");
mimeMessage.setRecipients(RecipientType.BCC, "e@f, g@h");
mailServer.getUserManager().getUser("imapuser").deliver(mimeMessage);
Message<?> message = this.imapChannel.receive(10000);
assertThat(message).isNotNull();
MimeMessage mm = (MimeMessage) message.getPayload();
assertThat(mm.getRecipients(RecipientType.TO)[0].toString()).isEqualTo("Foo <foo@bar>");
assertThat(mm.getFrom()[0].toString()).isEqualTo("Bar <bar@baz>");
assertThat(mm.getSubject()).isEqualTo("Test Email");
assertThat(mm.getContent()).isEqualTo(TestMailServer.MailServer.MailHandler.BODY + "\r\n");
assertThat(mm.getContent()).isEqualTo("foo\r\n");
assertThat(message.getHeaders().containsKey(IntegrationMessageHeaderAccessor.CLOSEABLE_RESOURCE)).isTrue();
message.getHeaders().get(IntegrationMessageHeaderAccessor.CLOSEABLE_RESOURCE, Closeable.class).close();
}
@Test
public void testImapIdle() {
public void testImapIdle() throws Exception {
MimeMessage mimeMessage =
GreenMailUtil.createTextEmail("Foo <foo@bar>", "Bar <bar@baz>", "Test Email", "foo\r\n",
mailServer.getImap().getServerSetup());
mimeMessage.setRecipients(RecipientType.CC, "a@b, c@d");
mimeMessage.setRecipients(RecipientType.BCC, "e@f, g@h");
mailServer.getUserManager().getUser("imapidleuser").deliver(mimeMessage);
Message<?> message = this.imapIdleChannel.receive(10000);
assertThat(message).isNotNull();
MessageHeaders headers = message.getHeaders();
assertThat(headers.get(MailHeaders.TO, String[].class)).containsExactly("Foo <foo@bar>");
assertThat(headers.get(MailHeaders.FROM)).isEqualTo("Bar <bar@baz>");
assertThat(headers.get(MailHeaders.SUBJECT)).isEqualTo("Test Email");
assertThat(message.getPayload()).isEqualTo(TestMailServer.MailServer.MailHandler.BODY + "\r\n");
assertThat(message.getPayload()).isEqualTo("foo\r\n");
assertThat(message.getHeaders().containsKey(IntegrationMessageHeaderAccessor.CLOSEABLE_RESOURCE)).isTrue();
this.imapIdleAdapter.stop();
assertThat(TestUtils.getPropertyValue(this.imapIdleAdapter, "shouldReconnectAutomatically", Boolean.class))
@@ -180,35 +201,6 @@ public class MailTests {
@EnableIntegration
public static class ContextConfiguration {
@Bean
public SmartLifecycle serverStopper() {
return new SmartLifecycle() {
@Override
public int getPhase() {
return Integer.MAX_VALUE;
}
@Override
public void stop() {
smtpServer.stop();
pop3Server.stop();
imapServer.stop();
imapIdleServer.stop();
}
@Override
public void start() {
}
@Override
public boolean isRunning() {
return true;
}
};
}
@Bean
public IntegrationFlow sendMailFlow() {
return IntegrationFlows.from("sendMailChannel")
@@ -217,8 +209,8 @@ public class MailTests {
.from("foo@bar")
.toFunction(m -> new String[]{ "bar@baz" }))
.handle(Mail.outboundAdapter("localhost")
.port(smtpServer.getPort())
.credentials("user", "pw")
.port(mailServer.getSmtp().getPort())
.credentials("smtpuser", "pw")
.protocol("smtp")
.javaMailProperties(p -> p.put("mail.debug", "false")),
e -> e.id("sendMailEndpoint"))
@@ -228,9 +220,9 @@ public class MailTests {
@Bean
public IntegrationFlow pop3MailFlow() {
return IntegrationFlows
.from(Mail.pop3InboundAdapter("localhost", pop3Server.getPort(), "user", "pw")
.from(Mail.pop3InboundAdapter("localhost", mailServer.getPop3().getPort(), "popuser", "pw")
.javaMailProperties(p -> p.put("mail.debug", "false"))
.autoCloseFolder(false)
.autoCloseFolder(true)
.headerMapper(mailHeaderMapper()),
e -> e.autoStartup(true).poller(p -> p.fixedDelay(1000)))
.enrichHeaders(s -> s.headerExpressions(c -> c.put(MailHeaders.SUBJECT, "payload.subject")
@@ -242,7 +234,7 @@ public class MailTests {
@Bean
public IntegrationFlow imapMailFlow() {
return IntegrationFlows
.from(Mail.imapInboundAdapter("imap://user:pw@localhost:" + imapServer.getPort() + "/INBOX")
.from(Mail.imapInboundAdapter("imap://imapuser:pw@localhost:" + mailServer.getImap().getPort() + "/INBOX")
.searchTermStrategy(this::fromAndNotSeenTerm)
.userFlag("testSIUserFlag")
.autoCloseFolder(false)
@@ -257,7 +249,7 @@ public class MailTests {
@Bean
public IntegrationFlow imapIdleFlow() {
return IntegrationFlows
.from(Mail.imapIdleAdapter("imap://user:pw@localhost:" + imapIdleServer.getPort() + "/INBOX")
.from(Mail.imapIdleAdapter("imap://imapidleuser:pw@localhost:" + mailServer.getImap().getPort() + "/INBOX")
.autoStartup(true)
.searchTermStrategy(this::fromAndNotSeenTerm)
.userFlag("testSIUserFlag")

View File

@@ -8,6 +8,8 @@
<Loggers>
<Logger name="org.springframework.integration" level="warn"/>
<Logger name="org.springframework.integration.mail" level="warn"/>
<Logger name="com.icegreen.greenmail" level="warn"/>
<Logger name="com.sun.mail" level="warn"/>
<Root level="warn">
<AppenderRef ref="STDOUT" />
</Root>

View File

@@ -48,7 +48,10 @@ import org.springframework.util.Base64Utils;
*
* @since 5.0
*
* @deprecated since 5.5 in favor of GreenMail library for mail testing.
*
*/
@Deprecated
public final class TestMailServer {
public static SmtpServer smtp(int port) {

View File

@@ -119,6 +119,7 @@ It now allows body-only rendering when a header mapper is provided.
Starting with version 5.2, the `autoCloseFolder` option is provided on the mail receiver.
Setting it to `false` doesn't close the folder automatically after a fetch, but instead an `IntegrationMessageHeaderAccessor.CLOSEABLE_RESOURCE` header (see <<./message.adoc#message-header-accessor,`MessageHeaderAccessor` API>> for more information) is populated into every message to producer from the channel adapter.
This does not work with `Pop3MailReceiver` as it relies on opening and closing the folder to get new messages.
It is the target application's responsibility to call the `close()` on this header whenever it is necessary in the downstream flow:
====

View File

@@ -33,6 +33,7 @@ Examples of such tools include the following:
* Gemfire and Hazelcast can be run as real-data grid nodes in the tests.
* The Curator Framework provides a `TestingServer` for Zookeeper interaction.
* Apache Kafka provides admin tools to embed a Kafka Broker in the tests.
* The GreenMail is an open source, intuitive and easy-to-use test suite of email servers for testing purposes.
Most of these tools and libraries are used in Spring Integration tests.
Also, from the GitHub https://github.com/spring-projects/spring-integration[repository] (in the `test` directory of each module), you can discover ideas for how to build your own tests for integration solutions.
@@ -97,7 +98,7 @@ private UdpSyslogReceivingChannelAdapter adapter;
@Autowired
private PollableChannel sysLogs;
...
@Test
public void testSimplestUdp() throws Exception {
int port = TestUtils.getPropertyValue(adapter1, "udpAdapter.port", Integer.class);
@@ -145,7 +146,7 @@ PollerMetadata poller;
@Autowired
OnlyOnceTrigger testTrigger;
...
@Test
@DirtiesContext
public void testWithEntityClass() throws Exception {
@@ -363,7 +364,7 @@ assertEquals("FOO", receive.getPayload());
Unlike the Mockito `MessageSource` mock object, the `MockMessageHandler` is a regular `AbstractMessageProducingHandler` extension with a chain API to stub handling for incoming messages.
The `MockMessageHandler` provides `handleNext(Consumer<Message<?>>)` to specify a one-way stub for the next request message.
It is used to mock message handlers that do not produce replies.
`handleNextAndReply(Function<Message<?>, ?>)` is provided for performing the same stub logic for the next request message and producing a reply for it.
The `handleNextAndReply(Function<Message<?>, ?>)` is provided for performing the same stub logic for the next request message and producing a reply for it.
They can be chained to simulate any arbitrary request-reply scenarios for all expected request messages variants.
These consumers and functions are applied to the incoming messages, one at a time from the stack, until the last, which is then used for all remaining messages.
The behavior is similar to the Mockito `Answer` or `doReturn()` API.