INT-3879: Mail: Configurable USER Flag

JIRA: https://jira.spring.io/browse/INT-3879

Namespace support to follow in 4.3.

Simple polishing and fix some typos in the `mail.adoc`
This commit is contained in:
Gary Russell
2015-11-05 12:36:16 -05:00
committed by Artem Bilan
parent eec937b6d9
commit b3dd85fb4b
7 changed files with 181 additions and 59 deletions

View File

@@ -81,7 +81,6 @@ import org.springframework.integration.mail.ImapIdleChannelAdapter.ImapIdleExcep
import org.springframework.integration.mail.PoorMansMailServer.ImapServer;
import org.springframework.integration.mail.config.ImapIdleChannelAdapterParserTests;
import org.springframework.integration.test.support.LongRunningIntegrationTest;
import org.springframework.integration.test.util.SocketUtils;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.PollableChannel;
import org.springframework.scheduling.TaskScheduler;
@@ -103,9 +102,7 @@ public class ImapMailReceiverTests {
private final AtomicInteger failed = new AtomicInteger(0);
private final static int imapIdlePort = SocketUtils.findAvailableServerSocket();
private final static ImapServer imapIdleServer = PoorMansMailServer.imap(imapIdlePort);
private final static ImapServer imapIdleServer = PoorMansMailServer.imap(0);
@BeforeClass
@@ -123,15 +120,9 @@ public class ImapMailReceiverTests {
}
@Test
public void testIdleWithServer() throws Exception {
Properties mailProps = new Properties();
mailProps.put("mail.debug", "true");
mailProps.put("mail.imap.connectionpool.debug", "true");
ImapMailReceiver receiver = new ImapMailReceiver("imap://user:pw@localhost:" + imapIdlePort + "/INBOX");
receiver.setJavaMailProperties(mailProps);
receiver.setMaxFetchSize(1);
receiver.setShouldDeleteMessages(false);
receiver.setShouldMarkMessagesAsRead(true);
public void testIdleWithServerCustomSearch() throws Exception {
ImapMailReceiver receiver = new ImapMailReceiver("imap://user:pw@localhost:" + imapIdleServer.getPort()
+ "/INBOX");
receiver.setSearchTermStrategy(new SearchTermStrategy() {
@Override
@@ -146,9 +137,30 @@ public class ImapMailReceiverTests {
}
}
});
testIdleWithServerGuts(receiver);
}
@Test
public void testIdleWithServerDefaultSearch() throws Exception {
ImapMailReceiver receiver = new ImapMailReceiver("imap://user:pw@localhost:" + imapIdleServer.getPort()
+ "/INBOX");
testIdleWithServerGuts(receiver);
assertTrue(imapIdleServer.assertReceived("searchWithUserFlag"));
}
public void testIdleWithServerGuts(ImapMailReceiver receiver) throws MessagingException {
imapIdleServer.resetServer();
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);
receiver.setCancelIdleInterval(8);
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
setUpScheduler(receiver, taskScheduler);
receiver.setUserFlag("testSIUserFlag");
receiver.afterPropertiesSet();
Log logger = spy(TestUtils.getPropertyValue(receiver, "logger", Log.class));
new DirectFieldAccessor(receiver).setPropertyValue("logger", logger);
@@ -167,6 +179,7 @@ public class ImapMailReceiverTests {
assertNull(channel.receive(10000)); // no new message after second and third idle
verify(logger).debug("Canceling IDLE");
taskScheduler.shutdown();
assertTrue(imapIdleServer.assertReceived("storeUserFlag"));
}
@Test
@@ -464,9 +477,9 @@ public class ImapMailReceiverTests {
doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
DirectFieldAccessor accesor = new DirectFieldAccessor((invocation.getMock()));
DirectFieldAccessor accessor = new DirectFieldAccessor((invocation.getMock()));
IMAPFolder folder = mock(IMAPFolder.class);
accesor.setPropertyValue("folder", folder);
accessor.setPropertyValue("folder", folder);
when(folder.hasNewMessages()).thenReturn(true);
return null;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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.
@@ -21,6 +21,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.mail.Flags;
@@ -45,7 +46,21 @@ public class ImapMailSearchTermsTests {
@Test
public void validateSearchTermsWhenShouldMarkAsReadNoExistingFlags() throws Exception {
String userFlag = AbstractMailReceiver.DEFAULT_SI_USER_FLAG;
ImapMailReceiver receiver = new ImapMailReceiver();
validateSearchTermsWhenShouldMarkAsReadNoExistingFlagsGuts(userFlag, receiver);
}
@Test
public void validateSearchTermsWhenShouldMarkAsReadNoExistingFlagsCustom() throws Exception {
String userFlag = "foo";
ImapMailReceiver receiver = new ImapMailReceiver();
receiver.setUserFlag(userFlag);
validateSearchTermsWhenShouldMarkAsReadNoExistingFlagsGuts(userFlag, receiver);
}
public void validateSearchTermsWhenShouldMarkAsReadNoExistingFlagsGuts(String userFlag, ImapMailReceiver receiver)
throws NoSuchFieldException, IllegalAccessException, InvocationTargetException {
receiver.setShouldMarkMessagesAsRead(true);
receiver.setBeanFactory(mock(BeanFactory.class));
@@ -62,9 +77,10 @@ public class ImapMailSearchTermsTests {
assertTrue(searchTerms instanceof NotTerm);
NotTerm notTerm = (NotTerm) searchTerms;
Flags siFlags = new Flags();
siFlags.add(AbstractMailReceiver.SI_USER_FLAG);
notTerm.getTerm().equals(siFlags);
siFlags.add(userFlag);
assertEquals(siFlags, ((FlagTerm)notTerm.getTerm()).getFlags());
}
@Test
public void validateSearchTermsWhenShouldMarkAsReadWithExistingFlags() throws Exception {
ImapMailReceiver receiver = new ImapMailReceiver();
@@ -91,7 +107,7 @@ public class ImapMailSearchTermsTests {
assertTrue(((FlagTerm)notTerm.getTerm()).getFlags().contains(Flag.ANSWERED));
notTerm = (NotTerm) terms[1];
Flags siFlags = new Flags();
siFlags.add(AbstractMailReceiver.SI_USER_FLAG);
siFlags.add(AbstractMailReceiver.DEFAULT_SI_USER_FLAG);
assertTrue(((FlagTerm)notTerm.getTerm()).getFlags().contains(siFlags));
}
@@ -114,4 +130,5 @@ public class ImapMailSearchTermsTests {
SearchTerm searchTerms = (SearchTerm) compileSearchTerms.invoke(receiver, flags);
assertTrue(searchTerms instanceof NotTerm);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014 the original author or authors.
* Copyright 2014-2015 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.
@@ -23,7 +23,9 @@ 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;
@@ -209,6 +211,13 @@ public class PoorMansMailServer {
super(port);
}
@Override
public void resetServer() {
super.resetServer();
this.seen = false;
this.idled = false;
}
@Override
protected MailHandler mailHandler(Socket socket) {
return new ImapHandler(socket);
@@ -255,19 +264,18 @@ public class PoorMansMailServer {
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")) {
if (seen) {
write("* SEARCH");
}
else {
write("* SEARCH 1");
}
write(tag + "OK SEARCH completed");
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 6909 INTERNALDATE \"27-May-2013 09:45:41 +0000\" "
@@ -312,6 +320,10 @@ public class PoorMansMailServer {
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;
@@ -341,6 +353,16 @@ public class PoorMansMailServer {
}
}
public void searchReply(String tag) throws IOException {
if (seen) {
write("* SEARCH");
}
else {
write("* SEARCH 1");
}
write(tag + "OK SEARCH completed");
}
}
}
@@ -351,6 +373,8 @@ public class PoorMansMailServer {
private final ExecutorService exec = Executors.newCachedThreadPool();
protected final Set<String> assertions = new HashSet<String>();
protected final List<String> messages = new ArrayList<String>();
private volatile boolean listening;
@@ -361,6 +385,10 @@ public class PoorMansMailServer {
exec.execute(this);
}
public int getPort() {
return this.socket.getLocalPort();
}
public boolean isListening() {
return listening;
}
@@ -369,6 +397,14 @@ public class PoorMansMailServer {
return messages;
}
public void resetServer() {
this.assertions.clear();
}
public boolean assertReceived(String assertion) {
return this.assertions.contains(assertion);
}
@Override
public void run() {
try {

View File

@@ -64,6 +64,7 @@ public class ImapIdleIntegrationTests {
doAnswer(new Answer<Object>() { // ensures that waitFornewMessages call blocks after a first execution
// to emulate the behavior of IDLE
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
if (block.get()) {
Thread.sleep(5000);
@@ -103,7 +104,7 @@ public class ImapIdleIntegrationTests {
assertTrue(txProcessorLatch.await(10, TimeUnit.SECONDS));
adapter.stop();
context.destroy();
context.close();
}