Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 4d070167 authored by cketti's avatar cketti Committed by GitHub
Browse files

Merge pull request #6451 from thundernest/convert_to_kotlin

Convert more POP3 tests to Kotlin
parents 75989a24 15b7d8ee
Loading
Loading
Loading
Loading
+0 −260
Original line number Diff line number Diff line
package com.fsck.k9.mail.store.pop3;


import com.fsck.k9.mail.FetchProfile;
import com.fsck.k9.mail.FetchProfile.Item;
import com.fsck.k9.mail.MessageRetrievalListener;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.internet.BinaryTempFileBody;

import org.junit.Before;
import org.junit.Test;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;


public class Pop3FolderTest {
    private static final int MAX_DOWNLOAD_SIZE = -1;

    private Pop3Store mockStore;
    private Pop3Connection mockConnection;
    private MessageRetrievalListener<Pop3Message> mockListener;
    private Pop3Folder folder;

    @Before
    public void before() throws MessagingException {
        mockStore = mock(Pop3Store.class);
        mockConnection = mock(Pop3Connection.class);
        mockListener = mock(MessageRetrievalListener.class);
        when(mockStore.createConnection()).thenReturn(mockConnection);
        when(mockConnection.executeSimpleCommand(Pop3Commands.STAT_COMMAND)).thenReturn("+OK 10 0");
        folder = new Pop3Folder(mockStore, Pop3Folder.INBOX);
        BinaryTempFileBody.setTempDirectory(new File(System.getProperty("java.io.tmpdir")));
    }

    @Test(expected = MessagingException.class)
    public void open_withoutInboxFolder_shouldThrow() throws Exception {
        Pop3Folder folder = new Pop3Folder(mockStore, "TestFolder");

        folder.open();
    }

    @Test
    public void open_withoutInboxFolder_shouldNotTryAndCreateConnection() throws Exception {
        Pop3Folder folder = new Pop3Folder(mockStore, "TestFolder");
        try {
            folder.open();
        } catch (Exception ignored) {}
        verify(mockStore, never()).createConnection();
    }

    @Test(expected = MessagingException.class)
    public void open_withInboxFolderWithExceptionCreatingConnection_shouldThrow()
            throws MessagingException {

        when(mockStore.createConnection()).thenThrow(new MessagingException("Test"));
        folder.open();
    }

    @Test
    public void open_withInboxFolder_shouldSetMessageCountFromStatResponse()
            throws MessagingException {
        folder.open();

        int messageCount = folder.getMessageCount();

        assertEquals(10, messageCount);
    }

    @Test(expected = MessagingException.class)
    public void open_withInboxFolder_whenStatCommandFails_shouldThrow()
            throws MessagingException {
        when(mockConnection.executeSimpleCommand(Pop3Commands.STAT_COMMAND))
                .thenThrow(new MessagingException("Test"));

        folder.open();
    }

    @Test
    public void open_createsAndOpensConnection()
            throws MessagingException {
        folder.open();

        verify(mockStore, times(1)).createConnection();
        verify(mockConnection).open();
    }

    @Test
    public void open_whenAlreadyOpenWithValidConnection_doesNotCreateAnotherConnection()
            throws MessagingException {
        folder.open();
        when(mockConnection.isOpen()).thenReturn(true);

        folder.open();

        verify(mockStore, times(1)).createConnection();
    }

    @Test
    public void close_onNonOpenedFolder_succeeds()
            throws MessagingException {


        folder.close();
    }

    @Test
    public void close_onOpenedFolder_succeeds()
            throws MessagingException {

        folder.open();

        folder.close();
    }

    @Test
    public void close_onOpenedFolder_sendsQUIT()
            throws MessagingException {

        folder.open();
        when(mockConnection.isOpen()).thenReturn(true);

        folder.close();

        verify(mockConnection).executeSimpleCommand(Pop3Commands.QUIT_COMMAND);
    }

    @Test
    public void close_withExceptionQuiting_ignoresException()
            throws MessagingException {

        folder.open();
        when(mockConnection.isOpen()).thenReturn(true);
        doThrow(new MessagingException("Test"))
                .when(mockConnection)
                .executeSimpleCommand(Pop3Commands.QUIT_COMMAND);

        folder.close();
    }

    @Test
    public void close_onOpenedFolder_closesConnection()
            throws MessagingException {

        folder.open();
        when(mockConnection.isOpen()).thenReturn(true);

        folder.close();

        verify(mockConnection).close();
    }

    @Test
    public void getMessages_returnsListOfMessagesOnServer() throws IOException, MessagingException {
        folder.open();

        when(mockConnection.readLine()).thenReturn("1 abcd").thenReturn(".");

        List<Pop3Message> result = folder.getMessages(1, 1, mockListener);

        assertEquals(1, result.size());
    }

    @Test(expected = MessagingException.class)
    public void getMessages_withInvalidSet_throwsException() throws IOException, MessagingException {
        folder.open();

        folder.getMessages(2, 1, mockListener);
    }

    @Test(expected = MessagingException.class)
    public void getMessages_withIOExceptionReadingLine_throwsException() throws IOException, MessagingException {
        folder.open();

        when(mockConnection.readLine()).thenThrow(new IOException("Test"));

        folder.getMessages(1, 1, mockListener);
    }

    @Test
    public void getMessage_withPreviouslyFetchedMessage_returnsMessage()
            throws IOException, MessagingException {
        folder.open();

        List<Pop3Message> messageList = setupMessageFromServer();

        Pop3Message message = folder.getMessage("abcd");

        assertSame(messageList.get(0), message);
    }

    @Test
    public void getMessage_withNoPreviouslyFetchedMessage_returnsNewMessage()
            throws IOException, MessagingException {
        folder.open();

        Pop3Message message = folder.getMessage("abcd");

        assertNotNull(message);
    }


    @Test
    public void fetch_withEnvelopeProfile_setsSizeOfMessage() throws MessagingException, IOException {
        folder.open();
        List<Pop3Message> messageList = setupMessageFromServer();
        FetchProfile fetchProfile = new FetchProfile();
        fetchProfile.add(Item.ENVELOPE);
        when(mockConnection.readLine()).thenReturn("1 100").thenReturn(".");

        folder.fetch(messageList, fetchProfile, mockListener, MAX_DOWNLOAD_SIZE);

        assertEquals(100, messageList.get(0).getSize());
    }

    @Test
    public void fetch_withBodyProfile_setsContentOfMessage() throws MessagingException, IOException {
        InputStream messageInputStream = new ByteArrayInputStream((
                "From: <adam@example.org>\r\n" +
                "To: <eva@example.org>\r\n" +
                "Subject: Testmail\r\n" +
                "MIME-Version: 1.0\r\n" +
                "Content-type: text/plain\r\n" +
                "Content-Transfer-Encoding: 7bit\r\n" +
                "\r\n" +
                "this is some test text.").getBytes());
        folder.open();
        List<Pop3Message> messageList = setupMessageFromServer();
        FetchProfile fetchProfile = new FetchProfile();
        fetchProfile.add(Item.BODY);
        when(mockConnection.readLine()).thenReturn("1 100").thenReturn(".");
        when(mockConnection.getInputStream()).thenReturn(messageInputStream);

        folder.fetch(messageList, fetchProfile, mockListener, MAX_DOWNLOAD_SIZE);

        ByteArrayOutputStream bodyData = new ByteArrayOutputStream();
        messageList.get(0).getBody().writeTo(bodyData);

        assertEquals("this is some test text.", new String(bodyData.toByteArray(), "UTF-8"));
    }

    private List<Pop3Message> setupMessageFromServer() throws IOException, MessagingException {
        when(mockConnection.readLine()).thenReturn("1 abcd").thenReturn(".");
        return folder.getMessages(1, 1, mockListener);
    }
}
+260 −0
Original line number Diff line number Diff line
package com.fsck.k9.mail.store.pop3

import com.fsck.k9.mail.AuthenticationFailedException
import com.fsck.k9.mail.Body
import com.fsck.k9.mail.FetchProfile
import com.fsck.k9.mail.MessageRetrievalListener
import com.fsck.k9.mail.MessagingException
import com.fsck.k9.mail.crlf
import com.fsck.k9.mail.internet.BinaryTempFileBody
import com.fsck.k9.mail.store.pop3.Pop3Commands.STAT_COMMAND
import com.google.common.truth.Truth.assertThat
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.IOException
import org.junit.Before
import org.junit.Test
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.doThrow
import org.mockito.kotlin.mock
import org.mockito.kotlin.stubbing

class Pop3FolderTest {
    private val connection = mock<Pop3Connection> {
        on { executeSimpleCommand(STAT_COMMAND) } doReturn "+OK $MESSAGE_COUNT 0"
        on { isOpen } doReturn true
    }
    private val store = mock<Pop3Store> {
        on { createConnection() } doReturn connection
    }
    private val messageRetrievalListener = mock<MessageRetrievalListener<Pop3Message>>()
    private val folder = Pop3Folder(store, Pop3Folder.INBOX)

    @Before
    fun setUp() {
        BinaryTempFileBody.setTempDirectory(File(System.getProperty("java.io.tmpdir")))
    }

    @Test(expected = MessagingException::class)
    fun `open() without Inbox folder should throw`() {
        val folder = Pop3Folder(store, "TestFolder")

        folder.open()
    }

    @Test
    fun `open() without Inbox folder should not call Pop3Store_createConnection()`() {
        val folder = Pop3Folder(store, "TestFolder")

        try {
            folder.open()
        } catch (ignored: Exception) {
        }

        verify(store, never()).createConnection()
    }

    @Test(expected = MessagingException::class)
    fun `open() with exception when creating a connection should throw`() {
        stubbing(store) {
            on { createConnection() } doThrow MessagingException("Test")
        }

        folder.open()
    }

    @Test(expected = AuthenticationFailedException::class)
    fun `open() with failed authentication should throw`() {
        stubbing(connection) {
            on { open() } doThrow AuthenticationFailedException("Test")
        }

        folder.open()
    }

    @Test
    fun `open() should set message count from STAT response`() {
        folder.open()

        assertThat(folder.messageCount).isEqualTo(MESSAGE_COUNT)
    }

    @Test(expected = MessagingException::class)
    fun `open() with STAT command failing should throw`() {
        stubbing(connection) {
            on { executeSimpleCommand(STAT_COMMAND) } doThrow MessagingException("Test")
        }

        folder.open()
    }

    @Test
    fun `open() should open connection`() {
        folder.open()

        verify(store, times(1)).createConnection()
        verify(connection).open()
    }

    @Test
    fun `open() with connection already open should not create another connection`() {
        folder.open()

        folder.open()

        verify(store, times(1)).createConnection()
    }

    @Test
    fun `close() with closed folder should not throw`() {
        folder.close()
    }

    @Test
    fun `close() with open folder should not throw`() {
        folder.open()

        folder.close()
    }

    @Test
    fun `close() with open folder should send QUIT command`() {
        folder.open()

        folder.close()

        verify(connection).executeSimpleCommand(Pop3Commands.QUIT_COMMAND)
    }

    @Test
    fun `close() with exception when sending QUIT command should not throw`() {
        stubbing(connection) {
            on { executeSimpleCommand(Pop3Commands.QUIT_COMMAND) } doThrow MessagingException("Test")
        }
        folder.open()

        folder.close()
    }

    @Test
    fun `close() with open folder should close connection`() {
        folder.open()

        folder.close()

        verify(connection).close()
    }

    @Test
    fun `getMessages() should return list of messages on server`() {
        stubbing(connection) {
            on { readLine() } doReturn "1 $MESSAGE_SERVER_ID" doReturn "."
        }
        folder.open()

        val result = folder.getMessages(1, 1, messageRetrievalListener)

        assertThat(result).hasSize(1)
    }

    @Test(expected = MessagingException::class)
    fun `getMessages() with invalid set should throw`() {
        folder.open()

        folder.getMessages(2, 1, messageRetrievalListener)
    }

    @Test(expected = MessagingException::class)
    fun `getMessages() with IOException when reading line should throw`() {
        stubbing(connection) {
            on { readLine() } doThrow IOException("Test")
        }
        folder.open()

        folder.getMessages(1, 1, messageRetrievalListener)
    }

    @Test
    fun `getMessage() with previously fetched message should return message`() {
        folder.open()
        val messageList = setupMessageFromServer()

        val message = folder.getMessage(MESSAGE_SERVER_ID)

        assertThat(message).isSameInstanceAs(messageList.first())
    }

    @Test
    fun `getMessage() without previously fetched message should return new message`() {
        folder.open()

        val message = folder.getMessage(MESSAGE_SERVER_ID)

        assertThat(message).isNotNull()
    }

    @Test
    fun `fetch() with ENVELOPE profile should set size of message`() {
        folder.open()
        val messageList = setupMessageFromServer()
        val fetchProfile = FetchProfile()
        fetchProfile.add(FetchProfile.Item.ENVELOPE)
        stubbing(connection) {
            on { readLine() } doReturn "1 100" doReturn "."
        }

        folder.fetch(messageList, fetchProfile, messageRetrievalListener, MAX_DOWNLOAD_SIZE)

        assertThat(messageList.first().size).isEqualTo(100)
    }

    @Test
    fun `fetch() with BODY profile should set content of message`() {
        val messageInputStream =
            """
            From: <adam@example.org>
            To: <eva@example.org>
            Subject: Testmail
            MIME-Version: 1.0
            Content-type: text/plain
            Content-Transfer-Encoding: 7bit
            
            this is some test text.
            """.trimIndent().crlf().byteInputStream()
        folder.open()
        val messageList = setupMessageFromServer()
        val fetchProfile = FetchProfile()
        fetchProfile.add(FetchProfile.Item.BODY)
        stubbing(connection) {
            on { readLine() } doReturn("1 100") doReturn(".")
            on { inputStream } doReturn messageInputStream
        }

        folder.fetch(messageList, fetchProfile, messageRetrievalListener, MAX_DOWNLOAD_SIZE)

        assertThat(messageList.first().body.writeToString()).isEqualTo("this is some test text.")
    }

    private fun setupMessageFromServer(): List<Pop3Message> {
        stubbing(connection) {
            on { readLine() } doReturn "1 $MESSAGE_SERVER_ID" doReturn "."
        }

        return folder.getMessages(1, 1, messageRetrievalListener)
    }

    private fun Body.writeToString(): String {
        return ByteArrayOutputStream().also { outputStream ->
            writeTo(outputStream)
        }.toByteArray().decodeToString()
    }

    companion object {
        private const val MESSAGE_COUNT = 10
        private const val MESSAGE_SERVER_ID = "abcd"
        private const val MAX_DOWNLOAD_SIZE = -1
    }
}
+0 −154
Original line number Diff line number Diff line
package com.fsck.k9.mail.store.pop3;


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

import com.fsck.k9.mail.AuthType;
import com.fsck.k9.mail.AuthenticationFailedException;
import com.fsck.k9.mail.ConnectionSecurity;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.ServerSettings;
import com.fsck.k9.mail.filter.Base64;
import com.fsck.k9.mail.ssl.TrustedSocketFactory;
import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
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 CAPA = "CAPA\r\n";
    private static final String CAPA_RESPONSE = "+OK Listing of supported mechanisms follows\r\n" +
            "SASL PLAIN CRAM-MD5 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 static final String UIDL_UNSUPPORTED_RESPONSE = "-ERR UIDL unsupported\r\n";
    private static final String UIDL_SUPPORTED_RESPONSE = "+OK UIDL supported\r\n";


    private Pop3Store store;
    private TrustedSocketFactory mockTrustedSocketFactory = mock(TrustedSocketFactory.class);
    private Socket mockSocket = mock(Socket.class);
    private OutputStream mockOutputStream = mock(OutputStream.class);


    @Before
    public void setUp() throws Exception {
        ServerSettings serverSettings = createServerSettings();
        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(serverSettings, mockTrustedSocketFactory);
    }

    @Test
    public void getFolder_shouldReturnSameFolderEachTime() {
        Pop3Folder folderOne = store.getFolder("TestFolder");
        Pop3Folder folderTwo = store.getFolder("TestFolder");

        assertSame(folderOne, folderTwo);
    }

    @Test
    public void getFolder_shouldReturnFolderWithCorrectName() throws Exception {
        Pop3Folder folder = store.getFolder("TestFolder");

        assertEquals("TestFolder", folder.getServerId());
    }

    @Test(expected = MessagingException.class)
    public void checkSetting_whenConnectionThrowsException_shouldThrowMessagingException()
            throws Exception {
        when(mockTrustedSocketFactory.createSocket(any(Socket.class),
                anyString(), anyInt(), anyString())).thenThrow(new IOException("Test"));
        store.checkSettings();
    }

    @Test(expected = MessagingException.class)
    public void checkSetting_whenUidlUnsupported_shouldThrowMessagingException()
            throws Exception {
        String response = INITIAL_RESPONSE +
                CAPA_RESPONSE +
                AUTH_PLAIN_AUTHENTICATED_RESPONSE +
                STAT_RESPONSE +
                UIDL_UNSUPPORTED_RESPONSE;
        when(mockSocket.getInputStream()).thenReturn(new ByteArrayInputStream(response.getBytes("UTF-8")));
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        when(mockSocket.getOutputStream()).thenReturn(byteArrayOutputStream);
        store.checkSettings();
    }

    @Test
    public void checkSetting_whenUidlSupported_shouldReturn()
            throws Exception {
        String response = INITIAL_RESPONSE +
                CAPA_RESPONSE +
                AUTH_PLAIN_AUTHENTICATED_RESPONSE +
                STAT_RESPONSE +
                UIDL_SUPPORTED_RESPONSE;
        when(mockSocket.getInputStream()).thenReturn(new ByteArrayInputStream(response.getBytes("UTF-8")));
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        when(mockSocket.getOutputStream()).thenReturn(byteArrayOutputStream);
        store.checkSettings();
    }

    // Component Level Tests

    @Test
    public void open_withAuthResponseUsingAuthPlain_shouldRetrieveMessageCountOnAuthenticatedSocket() throws Exception {
        String response = INITIAL_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);
        Pop3Folder folder = store.getFolder(Pop3Folder.INBOX);

        folder.open();

        assertEquals(20, folder.getMessageCount());
        assertEquals(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 +
                CAPA_RESPONSE +
                AUTH_PLAIN_FAILED_RESPONSE;
        when(mockSocket.getInputStream()).thenReturn(new ByteArrayInputStream(response.getBytes("UTF-8")));
        Pop3Folder folder = store.getFolder(Pop3Folder.INBOX);

        folder.open();
    }

    private ServerSettings createServerSettings() {
        return new ServerSettings(
                "pop3",
                "server",
                12345,
                ConnectionSecurity.SSL_TLS_REQUIRED,
                AuthType.PLAIN,
                "user",
                "password",
                null);
    }
}
+116 −0

File added.

Preview size limit exceeded, changes collapsed.