/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.email; import android.content.Context; import android.net.Uri; import android.test.ProviderTestCase2; import com.android.email.provider.ContentCache; import com.android.email.provider.EmailProvider; import com.android.email.provider.ProviderTestUtils; import com.android.emailcommon.provider.Account; import com.android.emailcommon.provider.EmailContent; import com.android.emailcommon.provider.EmailContent.Body; import com.android.emailcommon.provider.EmailContent.Message; import com.android.emailcommon.provider.HostAuth; import com.android.emailcommon.provider.Mailbox; import java.util.Locale; import java.util.concurrent.ExecutionException; /** * Tests of the Controller class that depend on the underlying provider. * * NOTE: It would probably make sense to rewrite this using a MockProvider, instead of the * ProviderTestCase (which is a real provider running on a temp database). This would be more of * a true "unit test". * * You can run this entire test case with: * runtest -c com.android.email.ControllerProviderOpsTests email */ public class ControllerProviderOpsTests extends ProviderTestCase2<EmailProvider> { private Context mProviderContext; private Context mContext; private TestController mTestController; public ControllerProviderOpsTests() { super(EmailProvider.class, EmailContent.AUTHORITY); } @Override public void setUp() throws Exception { super.setUp(); mProviderContext = getMockContext(); mContext = getContext(); mTestController = new TestController(mProviderContext, mContext); // Invalidate all caches, since we reset the database for each test ContentCache.invalidateAllCaches(); } @Override public void tearDown() throws Exception { super.tearDown(); mTestController.cleanupForTest(); } /** * Lightweight subclass of the Controller class allows injection of mock context */ public static class TestController extends Controller { protected TestController(Context providerContext, Context systemContext) { super(systemContext); setProviderContext(providerContext); } } /** * These are strings that should not change per locale. */ public void testGetMailboxServerName() { assertEquals("", Controller.getMailboxServerName(mContext, -1)); assertEquals("Inbox", Controller.getMailboxServerName(mContext, Mailbox.TYPE_INBOX)); assertEquals("Outbox", Controller.getMailboxServerName(mContext, Mailbox.TYPE_OUTBOX)); assertEquals("Trash", Controller.getMailboxServerName(mContext, Mailbox.TYPE_TRASH)); assertEquals("Sent", Controller.getMailboxServerName(mContext, Mailbox.TYPE_SENT)); assertEquals("Junk", Controller.getMailboxServerName(mContext, Mailbox.TYPE_JUNK)); // Now try again with translation Locale savedLocale = Locale.getDefault(); Locale.setDefault(Locale.FRANCE); assertEquals("Inbox", Controller.getMailboxServerName(mContext, Mailbox.TYPE_INBOX)); assertEquals("Outbox", Controller.getMailboxServerName(mContext, Mailbox.TYPE_OUTBOX)); assertEquals("Trash", Controller.getMailboxServerName(mContext, Mailbox.TYPE_TRASH)); assertEquals("Sent", Controller.getMailboxServerName(mContext, Mailbox.TYPE_SENT)); assertEquals("Junk", Controller.getMailboxServerName(mContext, Mailbox.TYPE_JUNK)); Locale.setDefault(savedLocale); } /** * Test of Controller.createMailbox(). * Sunny day test only - creates a mailbox that does not exist. * Does not test duplication, bad accountID, or any other bad input. */ public void testCreateMailbox() { // safety check that system mailboxes don't exist ... assertEquals(Mailbox.NO_MAILBOX, Mailbox.findMailboxOfType(mProviderContext, 1L, Mailbox.TYPE_DRAFTS)); assertEquals(Mailbox.NO_MAILBOX, Mailbox.findMailboxOfType(mProviderContext, 1L, Mailbox.TYPE_SENT)); long testMailboxId; Mailbox testMailbox; // Test creating "drafts" mailbox mTestController.createMailbox(1L, Mailbox.TYPE_DRAFTS); testMailboxId = Mailbox.findMailboxOfType(mProviderContext, 1L, Mailbox.TYPE_DRAFTS); assertTrue(testMailboxId != Mailbox.NO_MAILBOX); testMailbox = Mailbox.restoreMailboxWithId(mProviderContext, testMailboxId); assertNotNull(testMailbox); assertEquals(8, testMailbox.mFlags); // Flags should be "holds mail" assertEquals(-1L, testMailbox.mParentKey); // Parent is off the top-level // Test creating "sent" mailbox; same as drafts mTestController.createMailbox(1L, Mailbox.TYPE_SENT); testMailboxId = Mailbox.findMailboxOfType(mProviderContext, 1L, Mailbox.TYPE_SENT); assertTrue(testMailboxId != Mailbox.NO_MAILBOX); testMailbox = Mailbox.restoreMailboxWithId(mProviderContext, testMailboxId); assertNotNull(testMailbox); assertEquals(8, testMailbox.mFlags); // Flags should be "holds mail" assertEquals(-1L, testMailbox.mParentKey); // Parent is off the top-level } /** * Test of Controller.findOrCreateMailboxOfType(). * Checks: * - finds correctly the ID of existing mailbox * - creates non-existing mailbox * - creates only once a new mailbox * - when accountId or mailboxType are -1, returns NO_MAILBOX */ public void testFindOrCreateMailboxOfType() { Account account = ProviderTestUtils.setupAccount("mailboxid", true, mProviderContext); long accountId = account.mId; Mailbox box = ProviderTestUtils.setupMailbox("box", accountId, false, mProviderContext); final int boxType = Mailbox.TYPE_TRASH; box.mType = boxType; box.save(mProviderContext); long boxId = box.mId; long testBoxId = mTestController.findOrCreateMailboxOfType(accountId, boxType); // check it found the right mailbox id assertEquals(boxId, testBoxId); long boxId2 = mTestController.findOrCreateMailboxOfType(accountId, Mailbox.TYPE_DRAFTS); assertTrue("mailbox created", boxId2 != Mailbox.NO_MAILBOX); assertTrue("with different id", testBoxId != boxId2); // check it doesn't create twice when existing long boxId3 = mTestController.findOrCreateMailboxOfType(accountId, Mailbox.TYPE_DRAFTS); assertEquals("don't create if exists", boxId3, boxId2); // check invalid aruments assertEquals(Mailbox.NO_MAILBOX, mTestController.findOrCreateMailboxOfType(-1, Mailbox.TYPE_DRAFTS)); assertEquals(Mailbox.NO_MAILBOX, mTestController.findOrCreateMailboxOfType(accountId, -1)); } /** * Test the "move message" function. */ public void testMoveMessage() throws InterruptedException, ExecutionException { Account account1 = ProviderTestUtils.setupAccount("message-move", true, mProviderContext); long account1Id = account1.mId; Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mProviderContext); long box1Id = box1.mId; Mailbox box2 = ProviderTestUtils.setupMailbox("box2", account1Id, true, mProviderContext); long box2Id = box2.mId; Mailbox boxDest = ProviderTestUtils.setupMailbox("d", account1Id, true, mProviderContext); long boxDestId = boxDest.mId; Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, true, mProviderContext); Message message2 = ProviderTestUtils.setupMessage("message2", account1Id, box2Id, false, true, mProviderContext); long message1Id = message1.mId; long message2Id = message2.mId; // Because moveMessage runs asynchronously, call get() to force it to complete mTestController.moveMessages(new long[] { message1Id, message2Id }, boxDestId).get(); // now read back a fresh copy and confirm it's in the trash assertEquals(boxDestId, EmailContent.Message.restoreMessageWithId(mProviderContext, message1Id).mMailboxKey); assertEquals(boxDestId, EmailContent.Message.restoreMessageWithId(mProviderContext, message2Id).mMailboxKey); } /** * Test the "delete message" function. Sunny day: * - message/mailbox/account all exist * - trash mailbox exists */ public void testDeleteMessage() { Account account1 = ProviderTestUtils.setupAccount("message-delete", true, mProviderContext); long account1Id = account1.mId; Mailbox box = ProviderTestUtils.setupMailbox("box1", account1Id, true, mProviderContext); long boxId = box.mId; Mailbox trashBox = ProviderTestUtils.setupMailbox("box2", account1Id, false, mProviderContext); trashBox.mType = Mailbox.TYPE_TRASH; trashBox.save(mProviderContext); long trashBoxId = trashBox.mId; Mailbox draftBox = ProviderTestUtils.setupMailbox("box3", account1Id, false, mProviderContext); draftBox.mType = Mailbox.TYPE_DRAFTS; draftBox.save(mProviderContext); long draftBoxId = draftBox.mId; { // Case 1: Message in a regular mailbox, account known. Message message = ProviderTestUtils.setupMessage("message1", account1Id, boxId, false, true, mProviderContext); long messageId = message.mId; mTestController.deleteMessageSync(messageId); // now read back a fresh copy and confirm it's in the trash Message restored = EmailContent.Message.restoreMessageWithId(mProviderContext, messageId); assertEquals(trashBoxId, restored.mMailboxKey); } { // Case 2: Already in trash Message message = ProviderTestUtils.setupMessage("message3", account1Id, trashBoxId, false, true, mProviderContext); long messageId = message.mId; mTestController.deleteMessageSync(messageId); // Message should be deleted. assertNull(EmailContent.Message.restoreMessageWithId(mProviderContext, messageId)); } { // Case 3: Draft Message message = ProviderTestUtils.setupMessage("message3", account1Id, draftBoxId, false, true, mProviderContext); long messageId = message.mId; mTestController.deleteMessageSync(messageId); // Message should be deleted. assertNull(EmailContent.Message.restoreMessageWithId(mProviderContext, messageId)); } } /** * Test deleting message when there is no trash mailbox */ public void testDeleteMessageNoTrash() { Account account1 = ProviderTestUtils.setupAccount("message-delete-notrash", true, mProviderContext); long account1Id = account1.mId; Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mProviderContext); long box1Id = box1.mId; Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, true, mProviderContext); long message1Id = message1.mId; mTestController.deleteMessageSync(message1Id); // now read back a fresh copy and confirm it's in the trash Message message1get = EmailContent.Message.restoreMessageWithId(mProviderContext, message1Id); // check the new mailbox and see if it looks right assertFalse(-1 == message1get.mMailboxKey); assertFalse(box1Id == message1get.mMailboxKey); Mailbox mailbox2get = Mailbox.restoreMailboxWithId(mProviderContext, message1get.mMailboxKey); assertEquals(Mailbox.TYPE_TRASH, mailbox2get.mType); } /** * Test read/unread flag */ public void testReadUnread() throws InterruptedException, ExecutionException { Account account1 = ProviderTestUtils.setupAccount("read-unread", false, mProviderContext); account1.mHostAuthRecv = ProviderTestUtils.setupHostAuth("read-unread", 0, false, mProviderContext); account1.save(mProviderContext); long account1Id = account1.mId; long box1Id = 2; Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, true, mProviderContext); long message1Id = message1.mId; // test setting to "read" mTestController.setMessageRead(message1Id, true).get(); Message message1get = Message.restoreMessageWithId(mProviderContext, message1Id); assertTrue(message1get.mFlagRead); // test setting to "unread" mTestController.setMessageRead(message1Id, false).get(); message1get = Message.restoreMessageWithId(mProviderContext, message1Id); assertFalse(message1get.mFlagRead); // test setting to "read" mTestController.setMessageRead(message1Id, true).get(); message1get = Message.restoreMessageWithId(mProviderContext, message1Id); assertTrue(message1get.mFlagRead); } /** * Test favorites flag */ public void testFavorites() throws InterruptedException, ExecutionException { Account account1 = ProviderTestUtils.setupAccount("favorites", false, mProviderContext); account1.mHostAuthRecv = ProviderTestUtils.setupHostAuth("favorites", 0, false, mProviderContext); account1.save(mProviderContext); long account1Id = account1.mId; long box1Id = 2; Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, true, mProviderContext); long message1Id = message1.mId; // test setting to "favorite" mTestController.setMessageFavorite(message1Id, true).get(); Message message1get = Message.restoreMessageWithId(mProviderContext, message1Id); assertTrue(message1get.mFlagFavorite); // test setting to "not favorite" mTestController.setMessageFavorite(message1Id, false).get(); message1get = Message.restoreMessageWithId(mProviderContext, message1Id); assertFalse(message1get.mFlagFavorite); // test setting to "favorite" mTestController.setMessageFavorite(message1Id, true).get(); message1get = Message.restoreMessageWithId(mProviderContext, message1Id); assertTrue(message1get.mFlagFavorite); } public void testGetAndDeleteAttachmentMailbox() { Mailbox box = mTestController.getAttachmentMailbox(); assertNotNull(box); Mailbox anotherBox = mTestController.getAttachmentMailbox(); assertNotNull(anotherBox); // We should always get back the same Mailbox row assertEquals(box.mId, anotherBox.mId); // Add two messages to this mailbox ProviderTestUtils.setupMessage("message1", 0, box.mId, false, true, mProviderContext); ProviderTestUtils.setupMessage("message2", 0, box.mId, false, true, mProviderContext); // Make sure we can find them where they are expected assertEquals(2, EmailContent.count(mProviderContext, Message.CONTENT_URI, Message.MAILBOX_KEY + "=?", new String[] {Long.toString(box.mId)})); // Delete them mTestController.deleteAttachmentMessages(); // Make sure they're gone assertEquals(0, EmailContent.count(mProviderContext, Message.CONTENT_URI, Message.MAILBOX_KEY + "=?", new String[] {Long.toString(box.mId)})); } /** * Test wiping an account's synced data. Everything should go, but account & empty inbox. * Also ensures that the remaining account and the remaining inbox have cleared their * server sync keys, to force refresh eventually. */ public void testWipeSyncedData() { Account account1 = ProviderTestUtils.setupAccount("wipe-synced-1", false, mProviderContext); account1.mSyncKey = "account-1-sync-key"; account1.save(mProviderContext); long account1Id = account1.mId; Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, false, mProviderContext); box1.mType = Mailbox.TYPE_INBOX; box1.mSyncKey = "box-1-sync-key"; box1.save(mProviderContext); long box1Id = box1.mId; Mailbox box2 = ProviderTestUtils.setupMailbox("box2", account1Id, true, mProviderContext); long box2Id = box2.mId; // An EAS account mailbox Mailbox eas = ProviderTestUtils.setupMailbox("eas", account1Id, false, mProviderContext); eas.mType = Mailbox.TYPE_EAS_ACCOUNT_MAILBOX; eas.save(mProviderContext); Account account2 = ProviderTestUtils.setupAccount("wipe-synced-2", false, mProviderContext); account2.mSyncKey = "account-2-sync-key"; account2.save(mProviderContext); long account2Id = account2.mId; Mailbox box3 = ProviderTestUtils.setupMailbox("box3", account2Id, false, mProviderContext); box3.mSyncKey = "box-3-sync-key"; box3.mType = Mailbox.TYPE_INBOX; box3.save(mProviderContext); long box3Id = box3.mId; Mailbox box4 = ProviderTestUtils.setupMailbox("box4", account2Id, true, mProviderContext); long box4Id = box4.mId; // Now populate the 4 non-account boxes with messages Message message = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, true, mProviderContext); long message1Id = message.mId; message = ProviderTestUtils.setupMessage("message2", account1Id, box2Id, false, true, mProviderContext); long message2Id = message.mId; message = ProviderTestUtils.setupMessage("message3", account2Id, box3Id, false, true, mProviderContext); long message3Id = message.mId; message = ProviderTestUtils.setupMessage("message4", account2Id, box4Id, false, true, mProviderContext); long message4Id = message.mId; // Now wipe account 1's data mTestController.deleteSyncedDataSync(account1Id); // Confirm: Mailboxes gone (except account box), all messages gone, account survives assertNull(Mailbox.restoreMailboxWithId(mProviderContext, box1Id)); assertNull(Mailbox.restoreMailboxWithId(mProviderContext, box2Id)); assertNotNull(Mailbox.restoreMailboxWithId(mProviderContext, eas.mId)); assertNull(Message.restoreMessageWithId(mProviderContext, message1Id)); assertNull(Message.restoreMessageWithId(mProviderContext, message2Id)); account1 = Account.restoreAccountWithId(mProviderContext, account1Id); assertNotNull(account1); assertNull(account1.mSyncKey); // Confirm: Other account survived assertNotNull(Mailbox.restoreMailboxWithId(mProviderContext, box3Id)); assertNotNull(Mailbox.restoreMailboxWithId(mProviderContext, box4Id)); assertNotNull(Message.restoreMessageWithId(mProviderContext, message3Id)); assertNotNull(Message.restoreMessageWithId(mProviderContext, message4Id)); assertNotNull(Account.restoreAccountWithId(mProviderContext, account2Id)); } public void testLoadMessageFromUri() throws Exception { // Create a simple message Message msg = new Message(); String text = "This is some text"; msg.mText = text; String sender = "sender@host.com"; msg.mFrom = sender; // Save this away msg.save(mProviderContext); Uri fileUri = ProviderTestUtils.createTempEmlFile(mProviderContext, msg, mContext.getFilesDir()); // Load the message via Controller and a Uri Message loadedMsg = mTestController.loadMessageFromUri(fileUri); // Check server id, mailbox key, account key, and from assertNotNull(loadedMsg); assertTrue(loadedMsg.mServerId.startsWith(Controller.ATTACHMENT_MESSAGE_UID_PREFIX)); Mailbox box = mTestController.getAttachmentMailbox(); assertNotNull(box); assertEquals(box.mId, loadedMsg.mMailboxKey); assertEquals(0, loadedMsg.mAccountKey); assertEquals(loadedMsg.mFrom, sender); // Check body text String loadedMsgText = Body.restoreBodyTextWithMessageId(mProviderContext, loadedMsg.mId); assertEquals(text, loadedMsgText); } /** * Create a simple HostAuth with protocol */ private HostAuth setupSimpleHostAuth(String protocol) { HostAuth hostAuth = new HostAuth(); hostAuth.mProtocol = protocol; return hostAuth; } public void testIsMessagingController() { Account account1 = ProviderTestUtils.setupAccount("account1", false, mProviderContext); account1.mHostAuthRecv = setupSimpleHostAuth("eas"); account1.save(mProviderContext); assertFalse(mTestController.isMessagingController(account1)); Account account2 = ProviderTestUtils.setupAccount("account2", false, mProviderContext); account2.mHostAuthRecv = setupSimpleHostAuth("imap"); account2.save(mProviderContext); assertTrue(mTestController.isMessagingController(account2)); Account account3 = ProviderTestUtils.setupAccount("account3", false, mProviderContext); account3.mHostAuthRecv = setupSimpleHostAuth("pop3"); account3.save(mProviderContext); assertTrue(mTestController.isMessagingController(account3)); Account account4 = ProviderTestUtils.setupAccount("account4", false, mProviderContext); account4.mHostAuthRecv = setupSimpleHostAuth("smtp"); account4.save(mProviderContext); assertFalse(mTestController.isMessagingController(account4)); // There should be values for all of these accounts in the legacy map assertNotNull(mTestController.mLegacyControllerMap.get(account1.mId)); assertNotNull(mTestController.mLegacyControllerMap.get(account2.mId)); assertNotNull(mTestController.mLegacyControllerMap.get(account3.mId)); assertNotNull(mTestController.mLegacyControllerMap.get(account4.mId)); // The map should have the expected values assertFalse(mTestController.mLegacyControllerMap.get(account1.mId)); assertTrue(mTestController.mLegacyControllerMap.get(account2.mId)); assertTrue(mTestController.mLegacyControllerMap.get(account3.mId)); assertFalse(mTestController.mLegacyControllerMap.get(account4.mId)); // This second pass should pull values from the cache assertFalse(mTestController.isMessagingController(account1)); assertTrue(mTestController.isMessagingController(account2)); assertTrue(mTestController.isMessagingController(account3)); assertFalse(mTestController.isMessagingController(account4)); } /** * TODO: releasing associated data (e.g. attachments, embedded images) */ }