FileDocCategorySizeDatePackage
Pop3StoreUnitTests.javaAPI DocAndroid 1.5 API28956Wed May 06 22:42:46 BST 2009com.android.email.mail.store

Pop3StoreUnitTests

public class Pop3StoreUnitTests extends android.test.AndroidTestCase
This is a series of unit tests for the POP3 Store class. These tests must be locally complete - no server(s) required.

Fields Summary
final String
UNIQUE_ID_1
static final int
PER_MESSAGE_SIZE
private Pop3Store
mStore
private Pop3Store.Pop3Folder
mFolder
Constructors Summary
Methods Summary
private voidcheckFetchedMessage(com.android.email.mail.Message message, int msgNum, boolean body)
Look at a fetched message and confirm that it is complete. TODO this needs to be more dynamic, not just hardcoded for empty message #1.

param
message the fetched message to be checked
param
msgNum the message number

        // check To:
        Address[] to = message.getRecipients(RecipientType.TO);
        assertNotNull(to);
        assertEquals(1, to.length);
        assertEquals("Smith@Registry.Org", to[0].getAddress());
        assertNull(to[0].getPersonal());
        
        // check From:
        Address[] from = message.getFrom();
        assertNotNull(from);
        assertEquals(1, from.length);
        assertEquals("Jones@Registry.Org", from[0].getAddress());
        assertNull(from[0].getPersonal());
        
        // check Cc:
        Address[] cc = message.getRecipients(RecipientType.CC);
        assertNotNull(cc);
        assertEquals(1, cc.length);
        assertEquals("Chris@Registry.Org", cc[0].getAddress());
        assertNull(cc[0].getPersonal());

        // check Reply-To:
        Address[] replyto = message.getReplyTo();
        assertNotNull(replyto);
        assertEquals(1, replyto.length);
        assertEquals("Roger@Registry.Org", replyto[0].getAddress());
        assertNull(replyto[0].getPersonal());

        // TODO date
        
        // TODO check body (if applicable)
    
private voidcheckOneUnread(com.android.email.mail.transport.MockTransport mockTransport)
Given an initialized mock transport, open it and attempt to "read" one unread message from it. This can be used as a basic test of functionality and it should be possible to call this repeatedly (if you close the folder between calls).

param
mockTransport the mock transport we're using

        openFolderWithMessage(mockTransport);
        
        // index the message(s)
        setupUidlSequence(mockTransport, 1);
        Message[] messages = mFolder.getMessages(1, 1, null);
        assertEquals(1, messages.length);
        assertEquals(getSingleMessageUID(1), messages[0].getUid());
        
        // try the basic fetch of flags & envelope
        setupListSequence(mockTransport, 1);
        FetchProfile fp = new FetchProfile();
        fp.add(FetchProfile.Item.FLAGS);
        fp.add(FetchProfile.Item.ENVELOPE);
        mFolder.fetch(messages, fp, null);
        assertEquals(PER_MESSAGE_SIZE, messages[0].getSize());
        
        // A side effect of how messages work is that if you get fields that are empty, 
        // then empty arrays are written back into the parsed header fields (e.g. mTo, mFrom).  The
        // standard message parser needs to clear these before parsing.  Make sure that this
        // is happening.  (This doesn't affect IMAP, which reads the headers directly via
        // IMAP evelopes.)
        MimeMessage message = (MimeMessage) messages[0];
        message.getRecipients(RecipientType.TO);
        message.getRecipients(RecipientType.CC);
        message.getRecipients(RecipientType.BCC);

        // now try fetching the message
        setupSingleMessage(mockTransport, 1, false);
        fp = new FetchProfile();
        fp.add(FetchProfile.Item.BODY);
        mFolder.fetch(messages, fp, null);
        checkFetchedMessage(messages[0], 1, false);
    
private static java.lang.StringgetSingleMessageUID(int msgNum)
Generates a simple unique code for each message. Repeatable.

param
msgNum The message number
return
a string that can be used as the UID

        final String UID_HEAD = "ABCDEF-";
        final String UID_TAIL = "";
        return UID_HEAD + Integer.toString(msgNum) + UID_TAIL;
    
private com.android.email.mail.transport.MockTransportopenAndInjectMockTransport()
Set up a basic MockTransport. open it, and inject it into mStore

        // Create mock transport and inject it into the POP3Store that's already set up
        MockTransport mockTransport = new MockTransport();
        mockTransport.setSecurity(Transport.CONNECTION_SECURITY_NONE);
        mStore.setTransport(mockTransport);
        return mockTransport;
    
private voidopenFolderWithMessage(com.android.email.mail.transport.MockTransport mockTransport)
Open a folder that's preloaded with one unread message.

param
mockTransport the mock transport we're using

        // try to open it
        setupOpenFolder(mockTransport, 1, null);
        mFolder.open(OpenMode.READ_ONLY);
        
        // check message count
        assertEquals(1, mFolder.getMessageCount());
    
protected voidsetUp()
Setup code. We generate a lightweight Pop3Store and Pop3Store.Pop3Folder.

    
                   
    
         
        super.setUp();
        
        // These are needed so we can get at the inner classes
        mStore = new Pop3Store("pop3://user:password@server:999");
        mFolder = (Pop3Store.Pop3Folder) mStore.getFolder("INBOX");
        
        // This is needed for parsing mime messages
        BinaryTempFileBody.setTempDirectory(this.getContext().getCacheDir());
    
private static voidsetupListSequence(com.android.email.mail.transport.MockTransport transport, int numMessages)
Setup expects for a LIST on a mailbox with 0 or more messages in it.

param
transport The mock transport to preload
param
numMessages The number of messages to return from LIST.

        transport.expect("LIST", "+OK sending scan listing");          
        for (int msgNum = 1; msgNum <= numMessages; ++msgNum) {
            transport.expect(null, Integer.toString(msgNum) + " " + 
                    Integer.toString(PER_MESSAGE_SIZE * msgNum));
        }
        transport.expect(null, ".");
    
private voidsetupOpenFolder(com.android.email.mail.transport.MockTransport mockTransport, int statCount, java.lang.String capabilities)
Helper which stuffs the mock with enough strings to satisfy a call to Pop3Folder.open()

param
mockTransport the mock transport we're using
param
statCount the number of messages to indicate in the STAT
param
capabilities if non-null, comma-separated list of capabilities

        mockTransport.expect(null, "+OK Hello there from the Mock Transport.");
        if (capabilities == null) {
            mockTransport.expect("CAPA", "-ERR unimplemented");
        } else {
            mockTransport.expect("CAPA", "+OK capabilities follow");
            mockTransport.expect(null, capabilities.split(","));        // one capability per line
            mockTransport.expect(null, ".");                            // terminated by "."
        }
        mockTransport.expect("USER user", "+OK User name accepted");
        mockTransport.expect("PASS password", "+OK Logged in");
        String stat = "+OK " + Integer.toString(statCount) + " " + 
                Integer.toString(PER_MESSAGE_SIZE * statCount);
        mockTransport.expect("STAT", stat);
    
private static voidsetupSingleMessage(com.android.email.mail.transport.MockTransport transport, int msgNum, boolean body)
Setup a single message to be retrieved. Per RFC822 here is a minimal message header: Date: 26 Aug 76 1429 EDT From: Jones@Registry.Org To: Smith@Registry.Org We'll add the following fields to support additional tests: Cc: Chris@Registry.Org Reply-To: Roger@Registry.Org

param
transport the mock transport to preload
param
msgNum the message number to expect and return
param
body if true, a non-empty body will be added

        transport.expect("RETR " + Integer.toString(msgNum), "+OK message follows");
        transport.expect(null, "Date: 26 Aug 76 1429 EDT");
        transport.expect(null, "From: Jones@Registry.Org");
        transport.expect(null, "To:   Smith@Registry.Org");
        transport.expect(null, "CC:   Chris@Registry.Org");
        transport.expect(null, "Reply-To: Roger@Registry.Org");
        transport.expect(null, "");
        transport.expect(null, ".");
    
private static voidsetupUidlSequence(com.android.email.mail.transport.MockTransport transport, int numMessages)
Setup expects for a UIDL on a mailbox with 0 or more messages in it.

param
transport The mock transport to preload
param
numMessages The number of messages to return from UIDL.

        transport.expect("UIDL", "+OK sending UIDL list");          
        for (int msgNum = 1; msgNum <= numMessages; ++msgNum) {
            transport.expect(null, Integer.toString(msgNum) + " " + getSingleMessageUID(msgNum));
        }
        transport.expect(null, ".");
    
public voidtestCatchClosed1()
Test the scenario where the transport is "open" but not really (e.g. server closed). Two things should happen: We should see an intermediate failure that makes sense, and the next operation should reopen properly. There are multiple versions of this test because we are simulating the steps of MessagingController.synchronizeMailboxSyncronous() and we will inject the failure a bit further along in each case, to test various recovery points. This test confirms that Pop3Store needs to call close() in the IOExceptionHandler in Pop3Folder.getMessages().

        
        MockTransport mockTransport = openAndInjectMockTransport();
        
        openFolderWithMessage(mockTransport);
        
        // cause the next sequence to fail on the readLine() calls
        mockTransport.closeInputStream();
        
        // index the message(s) - it should fail, because our stream is broken
        try {
            setupUidlSequence(mockTransport, 1);
            Message[] messages = mFolder.getMessages(1, 1, null);
            assertEquals(1, messages.length);
            assertEquals(getSingleMessageUID(1), messages[0].getUid());
            fail("Broken stream should cause getMessages() to throw.");
        }
        catch(MessagingException me) {
            // success
        }
        
        // At this point the UI would display connection error, which is fine.  Now, the real
        // test is, can we recover?  So I'll just repeat the above steps, without the failure.
        // NOTE: everything from here down is copied from testOneUnread() and should be consolidated
        
        // confirm that we're closed at this point
        assertFalse("folder should be 'closed' after an IOError", mFolder.isOpen());
        
        // and confirm that the next connection will be OK
        checkOneUnread(mockTransport);
    
public voidtestCatchClosed2()
Test the scenario where the transport is "open" but not really (e.g. server closed). Two things should happen: We should see an intermediate failure that makes sense, and the next operation should reopen properly. There are multiple versions of this test because we are simulating the steps of MessagingController.synchronizeMailboxSyncronous() and we will inject the failure a bit further along in each case, to test various recovery points. This test confirms that Pop3Store needs to call close() in the first IOExceptionHandler in Pop3Folder.fetch(), for a failure in the call to indexUids().

        
        MockTransport mockTransport = openAndInjectMockTransport();
        
        openFolderWithMessage(mockTransport);
        
        // index the message(s)
        setupUidlSequence(mockTransport, 1);
        Message[] messages = mFolder.getMessages(1, 1, null);
        assertEquals(1, messages.length);
        assertEquals(getSingleMessageUID(1), messages[0].getUid());         
        
        // cause the next sequence to fail on the readLine() calls
        mockTransport.closeInputStream();
        
        try {
            // try the basic fetch of flags & envelope
            setupListSequence(mockTransport, 1);
            FetchProfile fp = new FetchProfile();
            fp.add(FetchProfile.Item.FLAGS);
            fp.add(FetchProfile.Item.ENVELOPE);
            mFolder.fetch(messages, fp, null);
            assertEquals(PER_MESSAGE_SIZE, messages[0].getSize());
            fail("Broken stream should cause fetch() to throw.");
        }
        catch(MessagingException me) {
            // success
        }

        // At this point the UI would display connection error, which is fine.  Now, the real
        // test is, can we recover?  So I'll just repeat the above steps, without the failure.
        // NOTE: everything from here down is copied from testOneUnread() and should be consolidated
        
        // confirm that we're closed at this point
        assertFalse("folder should be 'closed' after an IOError", mFolder.isOpen());
        
        // and confirm that the next connection will be OK
        checkOneUnread(mockTransport);
    
public voidtestCatchClosed2a()
Test the scenario where the transport is "open" but not really (e.g. server closed). Two things should happen: We should see an intermediate failure that makes sense, and the next operation should reopen properly. There are multiple versions of this test because we have to check additional places where Pop3Store and/or Pop3Folder should be dealing with IOErrors. This test confirms that Pop3Store needs to call close() in the first IOExceptionHandler in Pop3Folder.fetch(), for a failure in the call to fetchEnvelope().

        // TODO cannot write this test until we can inject stream closures mid-sequence
    
public voidtestCatchClosed3()
Test the scenario where the transport is "open" but not really (e.g. server closed). Two things should happen: We should see an intermediate failure that makes sense, and the next operation should reopen properly. There are multiple versions of this test because we are simulating the steps of MessagingController.synchronizeMailboxSyncronous() and we will inject the failure a bit further along in each case, to test various recovery points. This test confirms that Pop3Store needs to call close() in the second IOExceptionHandler in Pop3Folder.fetch().

        
        MockTransport mockTransport = openAndInjectMockTransport();
        
        openFolderWithMessage(mockTransport);
        
        // index the message(s)
        setupUidlSequence(mockTransport, 1);
        Message[] messages = mFolder.getMessages(1, 1, null);
        assertEquals(1, messages.length);
        assertEquals(getSingleMessageUID(1), messages[0].getUid());         

        // try the basic fetch of flags & envelope
        setupListSequence(mockTransport, 1);
        FetchProfile fp = new FetchProfile();
        fp.add(FetchProfile.Item.FLAGS);
        fp.add(FetchProfile.Item.ENVELOPE);
        mFolder.fetch(messages, fp, null);
        assertEquals(PER_MESSAGE_SIZE, messages[0].getSize());

        // cause the next sequence to fail on the readLine() calls
        mockTransport.closeInputStream();

        try {
            // now try fetching the message
            setupSingleMessage(mockTransport, 1, false);
            fp = new FetchProfile();
            fp.add(FetchProfile.Item.BODY);
            mFolder.fetch(messages, fp, null);
            checkFetchedMessage(messages[0], 1, false);
            fail("Broken stream should cause fetch() to throw.");
        }
        catch(MessagingException me) {
            // success
        }

        // At this point the UI would display connection error, which is fine.  Now, the real
        // test is, can we recover?  So I'll just repeat the above steps, without the failure.
        // NOTE: everything from here down is copied from testOneUnread() and should be consolidated
        
        // confirm that we're closed at this point
        assertFalse("folder should be 'closed' after an IOError", mFolder.isOpen());
        
        // and confirm that the next connection will be OK
        checkOneUnread(mockTransport);
    
public voidtestCatchClosed4()
Test the scenario where the transport is "open" but not really (e.g. server closed). Two things should happen: We should see an intermediate failure that makes sense, and the next operation should reopen properly. There are multiple versions of this test because we have to check additional places where Pop3Store and/or Pop3Folder should be dealing with IOErrors. This test confirms that Pop3Store needs to call close() in the IOExceptionHandler in Pop3Folder.setFlags().

        
        MockTransport mockTransport = openAndInjectMockTransport();
        
        openFolderWithMessage(mockTransport);
        
        // index the message(s)
        setupUidlSequence(mockTransport, 1);
        Message[] messages = mFolder.getMessages(1, 1, null);
        assertEquals(1, messages.length);
        assertEquals(getSingleMessageUID(1), messages[0].getUid());
        
        // cause the next sequence to fail on the readLine() calls
        mockTransport.closeInputStream();

        // delete 'em all - should fail because of broken stream
        try {
            mockTransport.expect("DELE 1", "+OK message deleted");
            mFolder.setFlags(messages, new Flag[] { Flag.DELETED }, true);
            fail("Broken stream should cause fetch() to throw.");
        }
        catch(MessagingException me) {
            // success
        }

        // At this point the UI would display connection error, which is fine.  Now, the real
        // test is, can we recover?  So I'll just repeat the above steps, without the failure.
        // NOTE: everything from here down is copied from testOneUnread() and should be consolidated
        
        // confirm that we're closed at this point
        assertFalse("folder should be 'closed' after an IOError", mFolder.isOpen());
        
        // and confirm that the next connection will be OK
        checkOneUnread(mockTransport);
    
public voidtestCatchClosed5()
Test the scenario where the transport is "open" but not really (e.g. server closed). Two things should happen: We should see an intermediate failure that makes sense, and the next operation should reopen properly. There are multiple versions of this test because we have to check additional places where Pop3Store and/or Pop3Folder should be dealing with IOErrors. This test confirms that Pop3Store needs to call close() in the first IOExceptionHandler in Pop3Folder.open().

        // TODO cannot write this test until we can inject stream closures mid-sequence
    
public voidtestCatchClosed6()
Test the scenario where the transport is "open" but not really (e.g. server closed). Two things should happen: We should see an intermediate failure that makes sense, and the next operation should reopen properly. There are multiple versions of this test because we have to check additional places where Pop3Store and/or Pop3Folder should be dealing with IOErrors. This test confirms that Pop3Store needs to call close() in the second IOExceptionHandler in Pop3Folder.open() (when it calls STAT).

        // TODO cannot write this test until we can inject stream closures mid-sequence
    
public voidtestCheckSettings()
Test the operation of checkSettings(), which requires (a) a good open and (b) UIDL support.


        MockTransport mockTransport = openAndInjectMockTransport();
        
        // scenario 1:  CAPA returns -ERR, so we try UIDL explicitly
        setupOpenFolder(mockTransport, 0, null);
        setupUidlSequence(mockTransport, 1);
        mockTransport.expect("QUIT", "");
        mStore.checkSettings();
        
        // scenario 2:  CAPA indicates UIDL, so we don't try UIDL
        setupOpenFolder(mockTransport, 0, "UIDL");
        mockTransport.expect("QUIT", "");
        mStore.checkSettings();
        
        // scenario 3:  CAPA returns -ERR, and UIDL fails
        try {
            setupOpenFolder(mockTransport, 0, null);
            mockTransport.expect("UIDL", "-ERR unsupported");
            mockTransport.expect("QUIT", "");
            mStore.checkSettings();
            fail("MessagingException was expected due to UIDL unsupported.");
        } catch (MessagingException me) {
            // this is expected, so eat it
        }
    
public voidtestOneUnread()
Test the process of opening and indexing a mailbox with one unread message in it. TODO should create an instrumented listener to confirm all expected callbacks. Then use it everywhere we could have passed a message listener.

        
        MockTransport mockTransport = openAndInjectMockTransport();
        
        checkOneUnread(mockTransport);
    
public voidtestSimpleLogin()
Confirms simple non-SSL non-TLS login

        
        MockTransport mockTransport = openAndInjectMockTransport();
        
        // try to open it
        setupOpenFolder(mockTransport, 0, null);
        mFolder.open(OpenMode.READ_ONLY);
    
public voidtestSmallFolderFunctions()
Test small Folder functions that don't really do anything in Pop3

            
        // getMode() returns OpenMode.READ_ONLY
        assertEquals(OpenMode.READ_ONLY, mFolder.getMode());
        
       // create() return false
        assertFalse(mFolder.create(FolderType.HOLDS_FOLDERS));
        assertFalse(mFolder.create(FolderType.HOLDS_MESSAGES));
        
        // getUnreadMessageCount() always returns -1
        assertEquals(-1, mFolder.getUnreadMessageCount());
        
        // getMessages(MessageRetrievalListener listener) is unsupported
        try {
            mFolder.getMessages(null);
            fail("Exception not thrown by getMessages()");
        } catch (UnsupportedOperationException e) {
            // expected - succeed
        }
        
        // getMessages(String[] uids, MessageRetrievalListener listener) is unsupported
        try {
            mFolder.getMessages(null, null);
            fail("Exception not thrown by getMessages()");
        } catch (UnsupportedOperationException e) {
            // expected - succeed
        }
        
        // getPermanentFlags() returns { Flag.DELETED }
        Flag[] flags = mFolder.getPermanentFlags();
        assertEquals(1, flags.length);
        assertEquals(Flag.DELETED, flags[0]);
        
        // appendMessages(Message[] messages) does nothing
        mFolder.appendMessages(null);
        
        // delete(boolean recurse) does nothing
        // TODO - it should!
        mFolder.delete(false);
        
        // expunge() returns null
        assertNull(mFolder.expunge());
        
        // copyMessages() is unsupported
        try {
            mFolder.copyMessages(null, null);
            fail("Exception not thrown by copyMessages()");
        } catch (UnsupportedOperationException e) {
            // expected - succeed
        }
    
public voidtestStoreFoldersFunctions()
Test small Store & Folder functions that manage folders & namespace

        
        // getPersonalNamespaces() always returns INBOX folder
        Folder[] folders = mStore.getPersonalNamespaces();
        assertEquals(1, folders.length);
        assertSame(mFolder, folders[0]);

        // getName() returns the name we were created with.  If "inbox", converts to INBOX
        assertEquals("INBOX", mFolder.getName());
        Pop3Store.Pop3Folder folderMixedCaseInbox = mStore.new Pop3Folder("iNbOx");
        assertEquals("INBOX", folderMixedCaseInbox.getName());
        Pop3Store.Pop3Folder folderNotInbox = mStore.new Pop3Folder("NOT-INBOX");
        assertEquals("NOT-INBOX", folderNotInbox.getName());
        
        // exists() true if name is INBOX
        assertTrue(mFolder.exists());
        assertTrue(folderMixedCaseInbox.exists());
        assertFalse(folderNotInbox.exists());
    
public voidtestUIDLComcastVariant()
Tests that variants on the RFC-specified formatting of UIDL work properly.

        
        // multi-line mode
        Pop3Store.Pop3Folder.UidlParser parser = mFolder.new UidlParser();
        
        // Comcast servers send multiple spaces in their darn UIDL strings.
        parser.parseMultiLine("101   " + UNIQUE_ID_1);
        assertEquals(101, parser.mMessageNumber);
        assertEquals(UNIQUE_ID_1, parser.mUniqueId);
        assertFalse(parser.mEndOfMessage);
        assertFalse(parser.mErr);
    
public voidtestUIDLParserMulti()
Test various sunny-day operations of UIDL parser for multi-line responses


        // multi-line mode
        Pop3Store.Pop3Folder.UidlParser parser = mFolder.new UidlParser();
        
        // Test basic in-list UIDL
        parser.parseMultiLine("101 " + UNIQUE_ID_1);
        assertEquals(101, parser.mMessageNumber);
        assertEquals(UNIQUE_ID_1, parser.mUniqueId);
        assertFalse(parser.mEndOfMessage);
        assertFalse(parser.mErr);
        
        //  Test end-of-list
        parser.parseMultiLine(".");
        assertTrue(parser.mEndOfMessage);
        assertFalse(parser.mErr);
    
public voidtestUIDLParserSingle()
Test various sunny-day operations of UIDL parser for single-line responses

      

        // single-line mode
        Pop3Store.Pop3Folder.UidlParser parser = mFolder.new UidlParser();

        // Test single-message OK response
        parser.parseSingleLine("+OK 101 " + UNIQUE_ID_1);
        assertEquals(101, parser.mMessageNumber);
        assertEquals(UNIQUE_ID_1, parser.mUniqueId);
        assertTrue(parser.mEndOfMessage);
        
        // Test single-message ERR response
        parser.parseSingleLine("-ERR what???");
        assertTrue(parser.mErr);