Add unit tests for ImapStore

This commit is contained in:
cketti 2016-02-02 14:34:38 +01:00
parent 7f3fc84c11
commit 2d887b31ac
2 changed files with 340 additions and 8 deletions

View file

@ -437,7 +437,7 @@ public class ImapStore extends RemoteStore {
* @throws IOException uh oh!
* @throws MessagingException uh oh!
*/
private void autoconfigureFolders(final ImapConnection connection) throws IOException, MessagingException {
void autoconfigureFolders(final ImapConnection connection) throws IOException, MessagingException {
String commandResponse;
String commandOptions = "";
@ -513,10 +513,7 @@ public class ImapStore extends RemoteStore {
@Override
public void checkSettings() throws MessagingException {
try {
ImapConnection connection = new ImapConnection(
new StoreImapSettings(),
mTrustedSocketFactory,
mConnectivityManager);
ImapConnection connection = createImapConnection();
connection.open();
autoconfigureFolders(connection);
@ -538,9 +535,7 @@ public class ImapStore extends RemoteStore {
}
}
if (connection == null) {
connection = new ImapConnection(new StoreImapSettings(),
mTrustedSocketFactory,
mConnectivityManager);
connection = createImapConnection();
}
return connection;
}
@ -554,6 +549,10 @@ public class ImapStore extends RemoteStore {
}
}
ImapConnection createImapConnection() {
return new ImapConnection(new StoreImapSettings(), mTrustedSocketFactory, mConnectivityManager);
}
/**
* Encode a string to be able to use it in an IMAP command.
*

View file

@ -0,0 +1,333 @@
package com.fsck.k9.mail.store.imap;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Collections;
import java.util.Deque;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import android.net.ConnectivityManager;
import com.fsck.k9.mail.Folder;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.ssl.TrustedSocketFactory;
import com.fsck.k9.mail.store.StoreConfig;
import org.junit.Before;
import org.junit.Test;
import org.mockito.internal.util.collections.Sets;
import static com.fsck.k9.mail.store.imap.ImapResponseHelper.createImapResponse;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
public class ImapStoreTest {
private StoreConfig storeConfig;
private TestImapStore imapStore;
@Before
public void setUp() throws Exception {
storeConfig = createStoreConfig();
TrustedSocketFactory trustedSocketFactory = mock(TrustedSocketFactory.class);
ConnectivityManager connectivityManager = mock(ConnectivityManager.class);
imapStore = new TestImapStore(storeConfig, trustedSocketFactory, connectivityManager);
}
@Test
public void getFolder_shouldReturnImapFolderInstance() throws Exception {
Folder result = imapStore.getFolder("INBOX");
assertEquals(ImapFolder.class, result.getClass());
}
@Test
public void getFolder_calledTwice_shouldReturnFirstInstance() throws Exception {
String folderName = "Trash";
Folder imapFolder = imapStore.getFolder(folderName);
Folder result = imapStore.getFolder(folderName);
assertEquals(imapFolder, result);
}
@Test
public void checkSettings_shouldCreateImapConnectionAndCallOpen() throws Exception {
ImapConnection imapConnection = mock(ImapConnection.class);
imapStore.enqueueImapConnection(imapConnection);
imapStore.checkSettings();
verify(imapConnection).open();
}
@Test
public void checkSettings_withOpenThrowing_shouldThrowMessagingException() throws Exception {
ImapConnection imapConnection = mock(ImapConnection.class);
doThrow(IOException.class).when(imapConnection).open();
imapStore.enqueueImapConnection(imapConnection);
try {
imapStore.checkSettings();
fail("Expected exception");
} catch (MessagingException e) {
assertEquals("Unable to connect", e.getMessage());
assertNotNull(e.getCause());
assertEquals(IOException.class, e.getCause().getClass());
}
}
@Test
public void autoconfigureFolders_withSpecialUseCapability_shouldSetSpecialFolders() throws Exception {
ImapConnection imapConnection = mock(ImapConnection.class);
when(imapConnection.hasCapability(Capabilities.SPECIAL_USE)).thenReturn(true);
List<ImapResponse> imapResponses = Arrays.asList(
createImapResponse("* LIST (\\HasNoChildren) \"/\" \"INBOX\""),
createImapResponse("* LIST (\\Noselect \\HasChildren) \"/\" \"[Gmail]\""),
createImapResponse("* LIST (\\HasNoChildren \\All) \"/\" \"[Gmail]/All Mail\""),
createImapResponse("* LIST (\\HasNoChildren \\Drafts) \"/\" \"[Gmail]/Drafts\""),
createImapResponse("* LIST (\\HasNoChildren \\Important) \"/\" \"[Gmail]/Important\""),
createImapResponse("* LIST (\\HasNoChildren \\Sent) \"/\" \"[Gmail]/Sent Mail\""),
createImapResponse("* LIST (\\HasNoChildren \\Junk) \"/\" \"[Gmail]/Spam\""),
createImapResponse("* LIST (\\HasNoChildren \\Flagged) \"/\" \"[Gmail]/Starred\""),
createImapResponse("* LIST (\\HasNoChildren \\Trash) \"/\" \"[Gmail]/Trash\""),
createImapResponse("5 OK Success")
);
when(imapConnection.executeSimpleCommand("LIST (SPECIAL-USE) \"\" \"*\"")).thenReturn(imapResponses);
imapStore.autoconfigureFolders(imapConnection);
verify(storeConfig).setDraftsFolderName("[Gmail]/Drafts");
verify(storeConfig).setSentFolderName("[Gmail]/Sent Mail");
verify(storeConfig).setSpamFolderName("[Gmail]/Spam");
verify(storeConfig).setTrashFolderName("[Gmail]/Trash");
//FIXME: currently fails
verify(storeConfig).setArchiveFolderName("[Gmail]/All Mail");
}
@Test
public void autoconfigureFolders_withoutSpecialUseCapability_shouldNotIssueImapCommand() throws Exception {
ImapConnection imapConnection = mock(ImapConnection.class);
when(imapConnection.hasCapability(Capabilities.SPECIAL_USE)).thenReturn(false);
imapStore.autoconfigureFolders(imapConnection);
verify(imapConnection, atLeastOnce()).hasCapability(anyString());
verifyNoMoreInteractions(imapConnection);
}
@Test
public void getPersonalNamespaces_withForceListAll() throws Exception {
when(storeConfig.subscribedFoldersOnly()).thenReturn(true);
ImapConnection imapConnection = mock(ImapConnection.class);
List<ImapResponse> imapResponses = Arrays.asList(
createImapResponse("* LIST (\\HasNoChildren) \".\" \"INBOX\""),
createImapResponse("* LIST (\\Noselect \\HasChildren) \".\" \"Folder\""),
createImapResponse("* LIST (\\HasNoChildren) \".\" \"Folder.SubFolder\""),
createImapResponse("6 OK Success")
);
when(imapConnection.executeSimpleCommand("LIST \"\" \"*\"")).thenReturn(imapResponses);
imapStore.enqueueImapConnection(imapConnection);
List<? extends Folder> result = imapStore.getPersonalNamespaces(true);
assertNotNull(result);
assertEquals(Sets.newSet("INBOX", "Folder.SubFolder"), extractFolderNames(result));
}
@Test
public void getPersonalNamespaces_withoutForceListAllAndWithoutSubscribedFoldersOnly() throws Exception {
when(storeConfig.subscribedFoldersOnly()).thenReturn(false);
ImapConnection imapConnection = mock(ImapConnection.class);
List<ImapResponse> imapResponses = Arrays.asList(
createImapResponse("* LIST (\\HasNoChildren) \".\" \"INBOX\""),
createImapResponse("* LIST (\\Noselect \\HasChildren) \".\" \"Folder\""),
createImapResponse("* LIST (\\HasNoChildren) \".\" \"Folder.SubFolder\""),
createImapResponse("6 OK Success")
);
when(imapConnection.executeSimpleCommand("LIST \"\" \"*\"")).thenReturn(imapResponses);
imapStore.enqueueImapConnection(imapConnection);
List<? extends Folder> result = imapStore.getPersonalNamespaces(false);
assertNotNull(result);
assertEquals(Sets.newSet("INBOX", "Folder.SubFolder"), extractFolderNames(result));
}
@Test
public void getPersonalNamespaces_withSubscribedFoldersOnlyAndWithoutForceListAll_shouldOnlyReturnExistingSubscribedFolders()
throws Exception {
when(storeConfig.subscribedFoldersOnly()).thenReturn(true);
ImapConnection imapConnection = mock(ImapConnection.class);
List<ImapResponse> lsubResponses = Arrays.asList(
createImapResponse("* LSUB (\\HasNoChildren) \".\" \"INBOX\""),
createImapResponse("* LSUB (\\Noselect \\HasChildren) \".\" \"Folder\""),
createImapResponse("* LSUB (\\HasNoChildren) \".\" \"Folder.SubFolder\""),
createImapResponse("* LSUB (\\HasNoChildren) \".\" \"SubscribedFolderThatHasBeenDeleted\""),
createImapResponse("5 OK Success")
);
when(imapConnection.executeSimpleCommand("LSUB \"\" \"*\"")).thenReturn(lsubResponses);
List<ImapResponse> imapResponses = Arrays.asList(
createImapResponse("* LIST (\\HasNoChildren) \".\" \"INBOX\""),
createImapResponse("* LIST (\\Noselect \\HasChildren) \".\" \"Folder\""),
createImapResponse("* LIST (\\HasNoChildren) \".\" \"Folder.SubFolder\""),
createImapResponse("6 OK Success")
);
when(imapConnection.executeSimpleCommand("LIST \"\" \"*\"")).thenReturn(imapResponses);
imapStore.enqueueImapConnection(imapConnection);
List<? extends Folder> result = imapStore.getPersonalNamespaces(false);
assertNotNull(result);
assertEquals(Sets.newSet("INBOX", "Folder.SubFolder"), extractFolderNames(result));
}
@Test
public void getPersonalNamespaces_withoutException_shouldLeaveImapConnectionOpen() throws Exception {
ImapConnection imapConnection = mock(ImapConnection.class);
List<ImapResponse> imapResponses = Collections.singletonList(createImapResponse("5 OK Success"));
when(imapConnection.executeSimpleCommand(anyString())).thenReturn(imapResponses);
imapStore.enqueueImapConnection(imapConnection);
imapStore.getPersonalNamespaces(true);
verify(imapConnection, never()).close();
}
@Test
public void getPersonalNamespaces_withIoException_shouldCloseImapConnection() throws Exception {
ImapConnection imapConnection = mock(ImapConnection.class);
doThrow(IOException.class).when(imapConnection).executeSimpleCommand("LIST \"\" \"*\"");
imapStore.enqueueImapConnection(imapConnection);
try {
imapStore.getPersonalNamespaces(true);
fail("Expected exception");
} catch (MessagingException ignored) {
}
verify(imapConnection).close();
}
@Test
public void getConnection_shouldCreateImapConnection() throws Exception {
ImapConnection imapConnection = mock(ImapConnection.class);
imapStore.enqueueImapConnection(imapConnection);
ImapConnection result = imapStore.getConnection();
assertSame(imapConnection, result);
}
@Test
public void getConnection_calledTwiceWithoutRelease_shouldCreateTwoImapConnection() throws Exception {
ImapConnection imapConnectionOne = mock(ImapConnection.class);
ImapConnection imapConnectionTwo = mock(ImapConnection.class);
imapStore.enqueueImapConnection(imapConnectionOne);
imapStore.enqueueImapConnection(imapConnectionTwo);
ImapConnection resultOne = imapStore.getConnection();
ImapConnection resultTwo = imapStore.getConnection();
assertSame(imapConnectionOne, resultOne);
assertSame(imapConnectionTwo, resultTwo);
}
@Test
public void getConnection_calledAfterRelease_shouldReturnCachedImapConnection() throws Exception {
ImapConnection imapConnection = mock(ImapConnection.class);
when(imapConnection.isOpen()).thenReturn(true);
imapStore.enqueueImapConnection(imapConnection);
ImapConnection connection = imapStore.getConnection();
imapStore.releaseConnection(connection);
ImapConnection result = imapStore.getConnection();
assertSame(imapConnection, result);
}
@Test
public void getConnection_calledAfterReleaseWithAClosedConnection_shouldReturnNewImapConnectionInstance()
throws Exception {
ImapConnection imapConnectionOne = mock(ImapConnection.class);
ImapConnection imapConnectionTwo = mock(ImapConnection.class);
imapStore.enqueueImapConnection(imapConnectionOne);
imapStore.enqueueImapConnection(imapConnectionTwo);
imapStore.getConnection();
when(imapConnectionOne.isOpen()).thenReturn(false);
imapStore.releaseConnection(imapConnectionOne);
ImapConnection result = imapStore.getConnection();
assertSame(imapConnectionTwo, result);
}
@Test
public void getConnection_withDeadConnectionInPool_shouldReturnNewImapConnectionInstance() throws Exception {
ImapConnection imapConnectionOne = mock(ImapConnection.class);
ImapConnection imapConnectionTwo = mock(ImapConnection.class);
imapStore.enqueueImapConnection(imapConnectionOne);
imapStore.enqueueImapConnection(imapConnectionTwo);
imapStore.getConnection();
when(imapConnectionOne.isOpen()).thenReturn(true);
doThrow(IOException.class).when(imapConnectionOne).executeSimpleCommand(Commands.NOOP);
imapStore.releaseConnection(imapConnectionOne);
ImapConnection result = imapStore.getConnection();
assertSame(imapConnectionTwo, result);
}
private StoreConfig createStoreConfig() {
StoreConfig storeConfig = mock(StoreConfig.class);
when(storeConfig.getInboxFolderName()).thenReturn("INBOX");
when(storeConfig.getStoreUri()).thenReturn("imap://user:password@imap.example.org");
return storeConfig;
}
private Set<String> extractFolderNames(List<? extends Folder> folders) {
Set<String> folderNames = new HashSet<>(folders.size());
for (Folder folder : folders) {
folderNames.add(folder.getName());
}
return folderNames;
}
static class TestImapStore extends ImapStore {
private Deque<ImapConnection> imapConnections = new ArrayDeque<>();
public TestImapStore(StoreConfig storeConfig, TrustedSocketFactory trustedSocketFactory,
ConnectivityManager connectivityManager) throws MessagingException {
super(storeConfig, trustedSocketFactory, connectivityManager);
}
@Override
ImapConnection createImapConnection() {
if (imapConnections.isEmpty()) {
throw new AssertionError("Unexpectedly tried to create an ImapConnection instance");
}
return imapConnections.pop();
}
public void enqueueImapConnection(ImapConnection imapConnection) {
imapConnections.add(imapConnection);
}
}
}