Copy relevant tests from MessagingControllerTest to ImapSyncTest
This commit is contained in:
parent
87eb9398ae
commit
a47ab9d7fe
1 changed files with 401 additions and 0 deletions
|
@ -0,0 +1,401 @@
|
||||||
|
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…
Reference in a new issue