package com.fsck.k9.mail.store.pop3; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.OutputStream; import java.net.Socket; import java.util.List; import com.fsck.k9.mail.AuthenticationFailedException; import com.fsck.k9.mail.Folder; import com.fsck.k9.mail.Folder.FolderType; import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mail.filter.Base64; import com.fsck.k9.mail.ssl.TrustedSocketFactory; import com.fsck.k9.mail.store.StoreConfig; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; public class Pop3StoreTest { private static final String INITIAL_RESPONSE = "+OK POP3 server greeting\r\n"; private static final String AUTH = "AUTH\r\n"; private static final String AUTH_HANDLE_RESPONSE = "+OK Listing of supported mechanisms follows\r\n" + "PLAIN\r\n" + "CRAM-MD5\r\n" + "EXTERNAL\r\n" + ".\r\n"; private static final String CAPA = "CAPA\r\n"; private static final String CAPA_RESPONSE = "+OK Listing of supported mechanisms follows\r\n" + "PLAIN\r\n" + "CRAM-MD5\r\n" + "EXTERNAL\r\n" + ".\r\n"; private static final String AUTH_PLAIN_WITH_LOGIN = "AUTH PLAIN\r\n" + new String(Base64.encodeBase64(("\000user\000password").getBytes())) + "\r\n"; private static final String AUTH_PLAIN_AUTHENTICATED_RESPONSE = "+OK\r\n" + "+OK\r\n"; private static final String AUTH_PLAIN_FAILED_RESPONSE = "+OK\r\n" + "Plain authentication failure"; private static final String STAT = "STAT\r\n"; private static final String STAT_RESPONSE = "+OK 20 0\r\n"; private Pop3Store store; private StoreConfig mockStoreConfig = mock(StoreConfig.class); private TrustedSocketFactory mockTrustedSocketFactory = mock(TrustedSocketFactory.class); private Socket mockSocket = mock(Socket.class); private OutputStream mockOutputStream = mock(OutputStream.class); @Before public void setUp() throws Exception { //Using a SSL socket allows us to mock it when(mockStoreConfig.getStoreUri()).thenReturn("pop3+ssl+://PLAIN:user:password@server:12345"); when(mockStoreConfig.getInboxFolderName()).thenReturn("Inbox"); when(mockTrustedSocketFactory.createSocket(null, "server", 12345, null)).thenReturn(mockSocket); when(mockSocket.isConnected()).thenReturn(true); when(mockSocket.isClosed()).thenReturn(false); when(mockSocket.getOutputStream()).thenReturn(mockOutputStream); store = new Pop3Store(mockStoreConfig, mockTrustedSocketFactory); } @Test public void getFolder_shouldReturnSameFolderEachTime() { Folder folderOne = store.getFolder("TestFolder"); Folder folderTwo = store.getFolder("TestFolder"); assertSame(folderOne, folderTwo); } @Test public void getFolder_shouldReturnFolderWithCorrectName() throws Exception { Folder folder = store.getFolder("TestFolder"); assertEquals("TestFolder", folder.getName()); } @Test public void create_withHoldsFoldersArgument_shouldDoNothing() throws Exception { Folder folder = store.getFolder("TestFolder"); boolean result = folder.create(FolderType.HOLDS_FOLDERS); assertFalse(result); verifyZeroInteractions(mockSocket); } @Test public void create_withHoldsMessagesArgument_shouldDoNothing() throws Exception { Folder folder = store.getFolder("TestFolder"); boolean result = folder.create(FolderType.HOLDS_MESSAGES); assertFalse(result); verifyZeroInteractions(mockSocket); } @Test public void exists_withInbox_shouldReturnTrue() throws Exception { Folder inbox = store.getFolder("Inbox"); boolean result = inbox.exists(); assertTrue(result); } @Test public void exists_withNonInboxFolder_shouldReturnFalse() throws Exception { Folder folder = store.getFolder("TestFolder"); boolean result = folder.exists(); assertFalse(result); } @Test public void getUnreadMessageCount_shouldBeMinusOne() throws Exception { Folder inbox = store.getFolder("Inbox"); int result = inbox.getUnreadMessageCount(); assertEquals(-1, result); } @Test public void getFlaggedMessageCount_shouldBeMinusOne() throws Exception { Folder inbox = store.getFolder("Inbox"); int result = inbox.getFlaggedMessageCount(); assertEquals(-1, result); } @Test public void getPersonalNamespace_shouldReturnListConsistingOfInbox() throws Exception { List<? extends Folder> folders = store.getPersonalNamespaces(true); assertEquals(1, folders.size()); assertEquals("Inbox", folders.get(0).getName()); } @Test public void isSeenFlagSupported_shouldReturnFalse() throws Exception { boolean result = store.isSeenFlagSupported(); assertFalse(result); } @Test(expected = MessagingException.class) public void open_withoutInboxFolder_shouldThrow() throws Exception { Folder folder = store.getFolder("TestFolder"); folder.open(Folder.OPEN_MODE_RW); } @Test public void open_withAuthResponseUsingAuthPlain_shouldRetrieveMessageCountOnAuthenticatedSocket() throws Exception { String response = INITIAL_RESPONSE + AUTH_HANDLE_RESPONSE + CAPA_RESPONSE + AUTH_PLAIN_AUTHENTICATED_RESPONSE + STAT_RESPONSE; when(mockSocket.getInputStream()).thenReturn(new ByteArrayInputStream(response.getBytes("UTF-8"))); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); when(mockSocket.getOutputStream()).thenReturn(byteArrayOutputStream); Folder folder = store.getFolder("Inbox"); folder.open(Folder.OPEN_MODE_RW); assertEquals(20, folder.getMessageCount()); assertEquals(AUTH + CAPA + AUTH_PLAIN_WITH_LOGIN + STAT, byteArrayOutputStream.toString("UTF-8")); } @Test(expected = AuthenticationFailedException.class) public void open_withFailedAuth_shouldThrow() throws Exception { String response = INITIAL_RESPONSE + AUTH_HANDLE_RESPONSE + CAPA_RESPONSE + AUTH_PLAIN_FAILED_RESPONSE; when(mockSocket.getInputStream()).thenReturn(new ByteArrayInputStream(response.getBytes("UTF-8"))); Folder folder = store.getFolder("Inbox"); folder.open(Folder.OPEN_MODE_RW); } }