Loading k9mail/src/test/java/com/fsck/k9/controller/imap/ImapSyncTest.java 0 → 100644 +401 −0 Original line number Diff line number Diff line package com.fsck.k9.controller.imap; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import android.content.Context; import com.fsck.k9.Account; import com.fsck.k9.AccountStats; import com.fsck.k9.K9RobolectricTestRunner; import com.fsck.k9.controller.MessagingController; import com.fsck.k9.controller.MessagingListener; import com.fsck.k9.controller.SimpleMessagingListener; import com.fsck.k9.mail.FetchProfile; import com.fsck.k9.mail.Folder; import com.fsck.k9.mail.Message; import com.fsck.k9.mail.MessageRetrievalListener; import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mail.Store; import com.fsck.k9.mailstore.LocalFolder; import com.fsck.k9.mailstore.LocalMessage; import com.fsck.k9.mailstore.LocalStore; import com.fsck.k9.notification.NotificationController; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.robolectric.shadows.ShadowApplication; import org.robolectric.shadows.ShadowLog; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @SuppressWarnings("unchecked") @RunWith(K9RobolectricTestRunner.class) public class ImapSyncTest { private static final String FOLDER_NAME = "Folder"; private static final int MAXIMUM_SMALL_MESSAGE_SIZE = 1000; private static final String MESSAGE_UID1 = "message-uid1"; private ImapSync imapSync; @Mock private MessagingController controller; @Mock private Account account; @Mock private AccountStats accountStats; @Mock private SimpleMessagingListener listener; @Mock private LocalFolder localFolder; @Mock private Folder remoteFolder; @Mock private LocalStore localStore; @Mock private Store remoteStore; @Mock private NotificationController notificationController; @Captor private ArgumentCaptor<List<Message>> messageListCaptor; @Captor private ArgumentCaptor<FetchProfile> fetchProfileCaptor; private Context appContext; @Before public void setUp() throws MessagingException { ShadowLog.stream = System.out; MockitoAnnotations.initMocks(this); appContext = ShadowApplication.getInstance().getApplicationContext(); imapSync = new ImapSync(notificationController, controller, appContext); setUpMessagingController(); configureAccount(); configureLocalStore(); } @Test public void sync_withOneMessageInRemoteFolder_shouldFinishWithoutError() throws Exception { messageCountInRemoteFolder(1); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(listener).synchronizeMailboxFinished(account, FOLDER_NAME, 1, 0); } @Test public void sync_withEmptyRemoteFolder_shouldFinishWithoutError() throws Exception { messageCountInRemoteFolder(0); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(listener).synchronizeMailboxFinished(account, FOLDER_NAME, 0, 0); } @Test public void sync_withNegativeMessageCountInRemoteFolder_shouldFinishWithError() throws Exception { messageCountInRemoteFolder(-1); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(listener).synchronizeMailboxFailed(account, FOLDER_NAME, "Exception: Message count -1 for folder Folder"); } @Test public void sync_withRemoteFolderProvided_shouldNotOpenRemoteFolder() throws Exception { messageCountInRemoteFolder(1); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(remoteFolder, never()).open(Folder.OPEN_MODE_RW); } @Test public void sync_withNoRemoteFolderProvided_shouldOpenRemoteFolderFromStore() throws Exception { messageCountInRemoteFolder(1); configureRemoteStoreWithFolder(); imapSync.sync(account, FOLDER_NAME, listener, null); verify(remoteFolder).open(Folder.OPEN_MODE_RO); } @Test public void sync_withRemoteFolderProvided_shouldNotCloseRemoteFolder() throws Exception { messageCountInRemoteFolder(1); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(remoteFolder, never()).close(); } @Test public void sync_withNoRemoteFolderProvided_shouldCloseRemoteFolderFromStore() throws Exception { messageCountInRemoteFolder(1); configureRemoteStoreWithFolder(); imapSync.sync(account, FOLDER_NAME, listener, null); verify(remoteFolder).close(); } @Test public void sync_withAccountPolicySetToExpungeOnPoll_shouldExpungeRemoteFolder() throws Exception { messageCountInRemoteFolder(1); when(account.getExpungePolicy()).thenReturn(Account.Expunge.EXPUNGE_ON_POLL); configureRemoteStoreWithFolder(); imapSync.sync(account, FOLDER_NAME, listener, null); verify(remoteFolder).expunge(); } @Test public void sync_withAccountPolicySetToExpungeManually_shouldNotExpungeRemoteFolder() throws Exception { messageCountInRemoteFolder(1); when(account.getExpungePolicy()).thenReturn(Account.Expunge.EXPUNGE_MANUALLY); imapSync.sync(account, FOLDER_NAME, listener, null); verify(remoteFolder, never()).expunge(); } @Test public void sync_withAccountSetToSyncRemoteDeletions_shouldDeleteLocalCopiesOfDeletedMessages() throws Exception { messageCountInRemoteFolder(0); LocalMessage localCopyOfRemoteDeletedMessage = mock(LocalMessage.class); when(account.syncRemoteDeletions()).thenReturn(true); when(localFolder.getAllMessagesAndEffectiveDates()).thenReturn(Collections.singletonMap(MESSAGE_UID1, 0L)); when(localFolder.getMessagesByUids(any(List.class))) .thenReturn(Collections.singletonList(localCopyOfRemoteDeletedMessage)); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(localFolder).destroyMessages(messageListCaptor.capture()); assertEquals(localCopyOfRemoteDeletedMessage, messageListCaptor.getValue().get(0)); } @Test public void sync_withAccountSetToSyncRemoteDeletions_shouldNotDeleteLocalCopiesOfExistingMessagesAfterEarliestPollDate() throws Exception { messageCountInRemoteFolder(1); Date dateOfEarliestPoll = new Date(); LocalMessage localMessage = localMessageWithCopyOnServer(); when(account.syncRemoteDeletions()).thenReturn(true); when(account.getEarliestPollDate()).thenReturn(dateOfEarliestPoll); when(localMessage.olderThan(dateOfEarliestPoll)).thenReturn(false); when(localFolder.getMessages(null)).thenReturn(Collections.singletonList(localMessage)); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(localFolder, never()).destroyMessages(messageListCaptor.capture()); } @Test public void sync_withAccountSetToSyncRemoteDeletions_shouldDeleteLocalCopiesOfExistingMessagesBeforeEarliestPollDate() throws Exception { messageCountInRemoteFolder(1); LocalMessage localMessage = localMessageWithCopyOnServer(); Date dateOfEarliestPoll = new Date(); when(account.syncRemoteDeletions()).thenReturn(true); when(account.getEarliestPollDate()).thenReturn(dateOfEarliestPoll); when(localMessage.olderThan(dateOfEarliestPoll)).thenReturn(true); when(localFolder.getAllMessagesAndEffectiveDates()).thenReturn(Collections.singletonMap(MESSAGE_UID1, 0L)); when(localFolder.getMessagesByUids(any(List.class))).thenReturn(Collections.singletonList(localMessage)); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(localFolder).destroyMessages(messageListCaptor.capture()); assertEquals(localMessage, messageListCaptor.getValue().get(0)); } @Test public void sync_withAccountSetNotToSyncRemoteDeletions_shouldNotDeleteLocalCopiesOfMessages() throws Exception { messageCountInRemoteFolder(0); LocalMessage remoteDeletedMessage = mock(LocalMessage.class); when(account.syncRemoteDeletions()).thenReturn(false); when(localFolder.getMessages(null)).thenReturn(Collections.singletonList(remoteDeletedMessage)); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(localFolder, never()).destroyMessages(messageListCaptor.capture()); } @Test public void sync_withAccountSupportingFetchingFlags_shouldFetchUnsychronizedMessagesListAndFlags() throws Exception { messageCountInRemoteFolder(1); hasUnsyncedRemoteMessage(); when(remoteFolder.supportsFetchingFlags()).thenReturn(true); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(remoteFolder, atLeastOnce()).fetch(any(List.class), fetchProfileCaptor.capture(), any(MessageRetrievalListener.class)); assertTrue(fetchProfileCaptor.getAllValues().get(0).contains(FetchProfile.Item.FLAGS)); assertTrue(fetchProfileCaptor.getAllValues().get(0).contains(FetchProfile.Item.ENVELOPE)); assertEquals(2, fetchProfileCaptor.getAllValues().get(0).size()); } @Test public void sync_withAccountNotSupportingFetchingFlags_shouldFetchUnsychronizedMessages() throws Exception { messageCountInRemoteFolder(1); hasUnsyncedRemoteMessage(); when(remoteFolder.supportsFetchingFlags()).thenReturn(false); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(remoteFolder, atLeastOnce()).fetch(any(List.class), fetchProfileCaptor.capture(), any(MessageRetrievalListener.class)); assertEquals(1, fetchProfileCaptor.getAllValues().get(0).size()); assertTrue(fetchProfileCaptor.getAllValues().get(0).contains(FetchProfile.Item.ENVELOPE)); } @Test public void sync_withUnsyncedNewSmallMessage_shouldFetchBodyOfSmallMessage() throws Exception { Message smallMessage = buildSmallNewMessage(); messageCountInRemoteFolder(1); hasUnsyncedRemoteMessage(); when(remoteFolder.supportsFetchingFlags()).thenReturn(false); respondToFetchEnvelopesWithMessage(smallMessage); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(remoteFolder, atLeast(2)).fetch(any(List.class), fetchProfileCaptor.capture(), any(MessageRetrievalListener.class)); assertEquals(1, fetchProfileCaptor.getAllValues().get(1).size()); assertTrue(fetchProfileCaptor.getAllValues().get(1).contains(FetchProfile.Item.BODY)); } @Test public void sync_withUnsyncedNewSmallMessage_shouldFetchStructureAndLimitedBodyOfLargeMessage() throws Exception { Message largeMessage = buildLargeNewMessage(); messageCountInRemoteFolder(1); hasUnsyncedRemoteMessage(); when(remoteFolder.supportsFetchingFlags()).thenReturn(false); respondToFetchEnvelopesWithMessage(largeMessage); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); //TODO: Don't bother fetching messages of a size we don't have verify(remoteFolder, atLeast(4)).fetch(any(List.class), fetchProfileCaptor.capture(), any(MessageRetrievalListener.class)); assertEquals(1, fetchProfileCaptor.getAllValues().get(2).size()); assertEquals(FetchProfile.Item.STRUCTURE, fetchProfileCaptor.getAllValues().get(2).get(0)); assertEquals(1, fetchProfileCaptor.getAllValues().get(3).size()); assertEquals(FetchProfile.Item.BODY_SANE, fetchProfileCaptor.getAllValues().get(3).get(0)); } private void respondToFetchEnvelopesWithMessage(final Message message) throws MessagingException { doAnswer(new Answer() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { FetchProfile fetchProfile = (FetchProfile) invocation.getArguments()[1]; if (invocation.getArguments()[2] != null) { MessageRetrievalListener listener = (MessageRetrievalListener) invocation.getArguments()[2]; if (fetchProfile.contains(FetchProfile.Item.ENVELOPE)) { listener.messageStarted("UID", 1, 1); listener.messageFinished(message, 1, 1); listener.messagesFinished(1); } } return null; } }).when(remoteFolder).fetch(any(List.class), any(FetchProfile.class), any(MessageRetrievalListener.class)); } private Message buildSmallNewMessage() { Message message = mock(Message.class); when(message.olderThan(any(Date.class))).thenReturn(false); when(message.getSize()).thenReturn((long) MAXIMUM_SMALL_MESSAGE_SIZE); return message; } private Message buildLargeNewMessage() { Message message = mock(Message.class); when(message.olderThan(any(Date.class))).thenReturn(false); when(message.getSize()).thenReturn((long) (MAXIMUM_SMALL_MESSAGE_SIZE + 1)); return message; } private void messageCountInRemoteFolder(int value) throws MessagingException { when(remoteFolder.getMessageCount()).thenReturn(value); } private LocalMessage localMessageWithCopyOnServer() throws MessagingException { String messageUid = "UID"; Message remoteMessage = mock(Message.class); LocalMessage localMessage = mock(LocalMessage.class); when(remoteMessage.getUid()).thenReturn(messageUid); when(localMessage.getUid()).thenReturn(messageUid); when(remoteFolder.getMessages(anyInt(), anyInt(), any(Date.class), any(MessageRetrievalListener.class))) .thenReturn(Collections.singletonList(remoteMessage)); return localMessage; } private void hasUnsyncedRemoteMessage() throws MessagingException { String messageUid = "UID"; Message remoteMessage = mock(Message.class); when(remoteMessage.getUid()).thenReturn(messageUid); when(remoteFolder.getMessages(anyInt(), anyInt(), any(Date.class), any(MessageRetrievalListener.class))) .thenReturn(Collections.singletonList(remoteMessage)); } private void setUpMessagingController() throws MessagingException { when(controller.getListeners(any(MessagingListener.class))).thenAnswer(new Answer<Set<MessagingListener>>() { @Override public Set<MessagingListener> answer(InvocationOnMock invocation) throws Throwable { MessagingListener listener = invocation.getArgumentAt(0, MessagingListener.class); Set<MessagingListener> set = new HashSet<>(1); set.add(listener); return set; } }); } private void configureAccount() throws MessagingException { when(account.isAvailable(appContext)).thenReturn(true); when(account.getLocalStore()).thenReturn(localStore); when(account.getStats(any(Context.class))).thenReturn(accountStats); when(account.getMaximumAutoDownloadMessageSize()).thenReturn(MAXIMUM_SMALL_MESSAGE_SIZE); when(account.getEmail()).thenReturn("user@host.com"); } private void configureLocalStore() throws MessagingException { when(localStore.getFolder(FOLDER_NAME)).thenReturn(localFolder); when(localFolder.getName()).thenReturn(FOLDER_NAME); when(localStore.getPersonalNamespaces(false)).thenReturn(Collections.singletonList(localFolder)); } private void configureRemoteStoreWithFolder() throws MessagingException { when(account.getRemoteStore()).thenReturn(remoteStore); when(remoteStore.getFolder(FOLDER_NAME)).thenReturn(remoteFolder); when(remoteFolder.getName()).thenReturn(FOLDER_NAME); } } Loading
k9mail/src/test/java/com/fsck/k9/controller/imap/ImapSyncTest.java 0 → 100644 +401 −0 Original line number Diff line number Diff line package com.fsck.k9.controller.imap; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import android.content.Context; import com.fsck.k9.Account; import com.fsck.k9.AccountStats; import com.fsck.k9.K9RobolectricTestRunner; import com.fsck.k9.controller.MessagingController; import com.fsck.k9.controller.MessagingListener; import com.fsck.k9.controller.SimpleMessagingListener; import com.fsck.k9.mail.FetchProfile; import com.fsck.k9.mail.Folder; import com.fsck.k9.mail.Message; import com.fsck.k9.mail.MessageRetrievalListener; import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mail.Store; import com.fsck.k9.mailstore.LocalFolder; import com.fsck.k9.mailstore.LocalMessage; import com.fsck.k9.mailstore.LocalStore; import com.fsck.k9.notification.NotificationController; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.robolectric.shadows.ShadowApplication; import org.robolectric.shadows.ShadowLog; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @SuppressWarnings("unchecked") @RunWith(K9RobolectricTestRunner.class) public class ImapSyncTest { private static final String FOLDER_NAME = "Folder"; private static final int MAXIMUM_SMALL_MESSAGE_SIZE = 1000; private static final String MESSAGE_UID1 = "message-uid1"; private ImapSync imapSync; @Mock private MessagingController controller; @Mock private Account account; @Mock private AccountStats accountStats; @Mock private SimpleMessagingListener listener; @Mock private LocalFolder localFolder; @Mock private Folder remoteFolder; @Mock private LocalStore localStore; @Mock private Store remoteStore; @Mock private NotificationController notificationController; @Captor private ArgumentCaptor<List<Message>> messageListCaptor; @Captor private ArgumentCaptor<FetchProfile> fetchProfileCaptor; private Context appContext; @Before public void setUp() throws MessagingException { ShadowLog.stream = System.out; MockitoAnnotations.initMocks(this); appContext = ShadowApplication.getInstance().getApplicationContext(); imapSync = new ImapSync(notificationController, controller, appContext); setUpMessagingController(); configureAccount(); configureLocalStore(); } @Test public void sync_withOneMessageInRemoteFolder_shouldFinishWithoutError() throws Exception { messageCountInRemoteFolder(1); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(listener).synchronizeMailboxFinished(account, FOLDER_NAME, 1, 0); } @Test public void sync_withEmptyRemoteFolder_shouldFinishWithoutError() throws Exception { messageCountInRemoteFolder(0); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(listener).synchronizeMailboxFinished(account, FOLDER_NAME, 0, 0); } @Test public void sync_withNegativeMessageCountInRemoteFolder_shouldFinishWithError() throws Exception { messageCountInRemoteFolder(-1); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(listener).synchronizeMailboxFailed(account, FOLDER_NAME, "Exception: Message count -1 for folder Folder"); } @Test public void sync_withRemoteFolderProvided_shouldNotOpenRemoteFolder() throws Exception { messageCountInRemoteFolder(1); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(remoteFolder, never()).open(Folder.OPEN_MODE_RW); } @Test public void sync_withNoRemoteFolderProvided_shouldOpenRemoteFolderFromStore() throws Exception { messageCountInRemoteFolder(1); configureRemoteStoreWithFolder(); imapSync.sync(account, FOLDER_NAME, listener, null); verify(remoteFolder).open(Folder.OPEN_MODE_RO); } @Test public void sync_withRemoteFolderProvided_shouldNotCloseRemoteFolder() throws Exception { messageCountInRemoteFolder(1); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(remoteFolder, never()).close(); } @Test public void sync_withNoRemoteFolderProvided_shouldCloseRemoteFolderFromStore() throws Exception { messageCountInRemoteFolder(1); configureRemoteStoreWithFolder(); imapSync.sync(account, FOLDER_NAME, listener, null); verify(remoteFolder).close(); } @Test public void sync_withAccountPolicySetToExpungeOnPoll_shouldExpungeRemoteFolder() throws Exception { messageCountInRemoteFolder(1); when(account.getExpungePolicy()).thenReturn(Account.Expunge.EXPUNGE_ON_POLL); configureRemoteStoreWithFolder(); imapSync.sync(account, FOLDER_NAME, listener, null); verify(remoteFolder).expunge(); } @Test public void sync_withAccountPolicySetToExpungeManually_shouldNotExpungeRemoteFolder() throws Exception { messageCountInRemoteFolder(1); when(account.getExpungePolicy()).thenReturn(Account.Expunge.EXPUNGE_MANUALLY); imapSync.sync(account, FOLDER_NAME, listener, null); verify(remoteFolder, never()).expunge(); } @Test public void sync_withAccountSetToSyncRemoteDeletions_shouldDeleteLocalCopiesOfDeletedMessages() throws Exception { messageCountInRemoteFolder(0); LocalMessage localCopyOfRemoteDeletedMessage = mock(LocalMessage.class); when(account.syncRemoteDeletions()).thenReturn(true); when(localFolder.getAllMessagesAndEffectiveDates()).thenReturn(Collections.singletonMap(MESSAGE_UID1, 0L)); when(localFolder.getMessagesByUids(any(List.class))) .thenReturn(Collections.singletonList(localCopyOfRemoteDeletedMessage)); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(localFolder).destroyMessages(messageListCaptor.capture()); assertEquals(localCopyOfRemoteDeletedMessage, messageListCaptor.getValue().get(0)); } @Test public void sync_withAccountSetToSyncRemoteDeletions_shouldNotDeleteLocalCopiesOfExistingMessagesAfterEarliestPollDate() throws Exception { messageCountInRemoteFolder(1); Date dateOfEarliestPoll = new Date(); LocalMessage localMessage = localMessageWithCopyOnServer(); when(account.syncRemoteDeletions()).thenReturn(true); when(account.getEarliestPollDate()).thenReturn(dateOfEarliestPoll); when(localMessage.olderThan(dateOfEarliestPoll)).thenReturn(false); when(localFolder.getMessages(null)).thenReturn(Collections.singletonList(localMessage)); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(localFolder, never()).destroyMessages(messageListCaptor.capture()); } @Test public void sync_withAccountSetToSyncRemoteDeletions_shouldDeleteLocalCopiesOfExistingMessagesBeforeEarliestPollDate() throws Exception { messageCountInRemoteFolder(1); LocalMessage localMessage = localMessageWithCopyOnServer(); Date dateOfEarliestPoll = new Date(); when(account.syncRemoteDeletions()).thenReturn(true); when(account.getEarliestPollDate()).thenReturn(dateOfEarliestPoll); when(localMessage.olderThan(dateOfEarliestPoll)).thenReturn(true); when(localFolder.getAllMessagesAndEffectiveDates()).thenReturn(Collections.singletonMap(MESSAGE_UID1, 0L)); when(localFolder.getMessagesByUids(any(List.class))).thenReturn(Collections.singletonList(localMessage)); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(localFolder).destroyMessages(messageListCaptor.capture()); assertEquals(localMessage, messageListCaptor.getValue().get(0)); } @Test public void sync_withAccountSetNotToSyncRemoteDeletions_shouldNotDeleteLocalCopiesOfMessages() throws Exception { messageCountInRemoteFolder(0); LocalMessage remoteDeletedMessage = mock(LocalMessage.class); when(account.syncRemoteDeletions()).thenReturn(false); when(localFolder.getMessages(null)).thenReturn(Collections.singletonList(remoteDeletedMessage)); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(localFolder, never()).destroyMessages(messageListCaptor.capture()); } @Test public void sync_withAccountSupportingFetchingFlags_shouldFetchUnsychronizedMessagesListAndFlags() throws Exception { messageCountInRemoteFolder(1); hasUnsyncedRemoteMessage(); when(remoteFolder.supportsFetchingFlags()).thenReturn(true); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(remoteFolder, atLeastOnce()).fetch(any(List.class), fetchProfileCaptor.capture(), any(MessageRetrievalListener.class)); assertTrue(fetchProfileCaptor.getAllValues().get(0).contains(FetchProfile.Item.FLAGS)); assertTrue(fetchProfileCaptor.getAllValues().get(0).contains(FetchProfile.Item.ENVELOPE)); assertEquals(2, fetchProfileCaptor.getAllValues().get(0).size()); } @Test public void sync_withAccountNotSupportingFetchingFlags_shouldFetchUnsychronizedMessages() throws Exception { messageCountInRemoteFolder(1); hasUnsyncedRemoteMessage(); when(remoteFolder.supportsFetchingFlags()).thenReturn(false); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(remoteFolder, atLeastOnce()).fetch(any(List.class), fetchProfileCaptor.capture(), any(MessageRetrievalListener.class)); assertEquals(1, fetchProfileCaptor.getAllValues().get(0).size()); assertTrue(fetchProfileCaptor.getAllValues().get(0).contains(FetchProfile.Item.ENVELOPE)); } @Test public void sync_withUnsyncedNewSmallMessage_shouldFetchBodyOfSmallMessage() throws Exception { Message smallMessage = buildSmallNewMessage(); messageCountInRemoteFolder(1); hasUnsyncedRemoteMessage(); when(remoteFolder.supportsFetchingFlags()).thenReturn(false); respondToFetchEnvelopesWithMessage(smallMessage); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); verify(remoteFolder, atLeast(2)).fetch(any(List.class), fetchProfileCaptor.capture(), any(MessageRetrievalListener.class)); assertEquals(1, fetchProfileCaptor.getAllValues().get(1).size()); assertTrue(fetchProfileCaptor.getAllValues().get(1).contains(FetchProfile.Item.BODY)); } @Test public void sync_withUnsyncedNewSmallMessage_shouldFetchStructureAndLimitedBodyOfLargeMessage() throws Exception { Message largeMessage = buildLargeNewMessage(); messageCountInRemoteFolder(1); hasUnsyncedRemoteMessage(); when(remoteFolder.supportsFetchingFlags()).thenReturn(false); respondToFetchEnvelopesWithMessage(largeMessage); imapSync.sync(account, FOLDER_NAME, listener, remoteFolder); //TODO: Don't bother fetching messages of a size we don't have verify(remoteFolder, atLeast(4)).fetch(any(List.class), fetchProfileCaptor.capture(), any(MessageRetrievalListener.class)); assertEquals(1, fetchProfileCaptor.getAllValues().get(2).size()); assertEquals(FetchProfile.Item.STRUCTURE, fetchProfileCaptor.getAllValues().get(2).get(0)); assertEquals(1, fetchProfileCaptor.getAllValues().get(3).size()); assertEquals(FetchProfile.Item.BODY_SANE, fetchProfileCaptor.getAllValues().get(3).get(0)); } private void respondToFetchEnvelopesWithMessage(final Message message) throws MessagingException { doAnswer(new Answer() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { FetchProfile fetchProfile = (FetchProfile) invocation.getArguments()[1]; if (invocation.getArguments()[2] != null) { MessageRetrievalListener listener = (MessageRetrievalListener) invocation.getArguments()[2]; if (fetchProfile.contains(FetchProfile.Item.ENVELOPE)) { listener.messageStarted("UID", 1, 1); listener.messageFinished(message, 1, 1); listener.messagesFinished(1); } } return null; } }).when(remoteFolder).fetch(any(List.class), any(FetchProfile.class), any(MessageRetrievalListener.class)); } private Message buildSmallNewMessage() { Message message = mock(Message.class); when(message.olderThan(any(Date.class))).thenReturn(false); when(message.getSize()).thenReturn((long) MAXIMUM_SMALL_MESSAGE_SIZE); return message; } private Message buildLargeNewMessage() { Message message = mock(Message.class); when(message.olderThan(any(Date.class))).thenReturn(false); when(message.getSize()).thenReturn((long) (MAXIMUM_SMALL_MESSAGE_SIZE + 1)); return message; } private void messageCountInRemoteFolder(int value) throws MessagingException { when(remoteFolder.getMessageCount()).thenReturn(value); } private LocalMessage localMessageWithCopyOnServer() throws MessagingException { String messageUid = "UID"; Message remoteMessage = mock(Message.class); LocalMessage localMessage = mock(LocalMessage.class); when(remoteMessage.getUid()).thenReturn(messageUid); when(localMessage.getUid()).thenReturn(messageUid); when(remoteFolder.getMessages(anyInt(), anyInt(), any(Date.class), any(MessageRetrievalListener.class))) .thenReturn(Collections.singletonList(remoteMessage)); return localMessage; } private void hasUnsyncedRemoteMessage() throws MessagingException { String messageUid = "UID"; Message remoteMessage = mock(Message.class); when(remoteMessage.getUid()).thenReturn(messageUid); when(remoteFolder.getMessages(anyInt(), anyInt(), any(Date.class), any(MessageRetrievalListener.class))) .thenReturn(Collections.singletonList(remoteMessage)); } private void setUpMessagingController() throws MessagingException { when(controller.getListeners(any(MessagingListener.class))).thenAnswer(new Answer<Set<MessagingListener>>() { @Override public Set<MessagingListener> answer(InvocationOnMock invocation) throws Throwable { MessagingListener listener = invocation.getArgumentAt(0, MessagingListener.class); Set<MessagingListener> set = new HashSet<>(1); set.add(listener); return set; } }); } private void configureAccount() throws MessagingException { when(account.isAvailable(appContext)).thenReturn(true); when(account.getLocalStore()).thenReturn(localStore); when(account.getStats(any(Context.class))).thenReturn(accountStats); when(account.getMaximumAutoDownloadMessageSize()).thenReturn(MAXIMUM_SMALL_MESSAGE_SIZE); when(account.getEmail()).thenReturn("user@host.com"); } private void configureLocalStore() throws MessagingException { when(localStore.getFolder(FOLDER_NAME)).thenReturn(localFolder); when(localFolder.getName()).thenReturn(FOLDER_NAME); when(localStore.getPersonalNamespaces(false)).thenReturn(Collections.singletonList(localFolder)); } private void configureRemoteStoreWithFolder() throws MessagingException { when(account.getRemoteStore()).thenReturn(remoteStore); when(remoteStore.getFolder(FOLDER_NAME)).thenReturn(remoteFolder); when(remoteFolder.getName()).thenReturn(FOLDER_NAME); } }