ControllerProviderOpsTests.java revision e87ff6c3cbbfc5e3636f9827b58820652e3ea1c5
1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.email;
18
19import com.android.email.provider.ContentCache;
20import com.android.email.provider.EmailProvider;
21import com.android.email.provider.ProviderTestUtils;
22import com.android.emailcommon.provider.EmailContent;
23import com.android.emailcommon.provider.EmailContent.Account;
24import com.android.emailcommon.provider.EmailContent.Body;
25import com.android.emailcommon.provider.EmailContent.HostAuth;
26import com.android.emailcommon.provider.EmailContent.Mailbox;
27import com.android.emailcommon.provider.EmailContent.Message;
28
29import android.content.Context;
30import android.net.Uri;
31import android.test.ProviderTestCase2;
32
33import java.util.Locale;
34import java.util.concurrent.ExecutionException;
35
36/**
37 * Tests of the Controller class that depend on the underlying provider.
38 *
39 * NOTE:  It would probably make sense to rewrite this using a MockProvider, instead of the
40 * ProviderTestCase (which is a real provider running on a temp database).  This would be more of
41 * a true "unit test".
42 *
43 * You can run this entire test case with:
44 *   runtest -c com.android.email.ControllerProviderOpsTests email
45 */
46public class ControllerProviderOpsTests extends ProviderTestCase2<EmailProvider> {
47
48    private Context mProviderContext;
49    private Context mContext;
50    private TestController mTestController;
51
52
53    public ControllerProviderOpsTests() {
54        super(EmailProvider.class, EmailContent.AUTHORITY);
55    }
56
57    @Override
58    public void setUp() throws Exception {
59        super.setUp();
60        mProviderContext = getMockContext();
61        mContext = getContext();
62        mTestController = new TestController(mProviderContext, mContext);
63        // Invalidate all caches, since we reset the database for each test
64        ContentCache.invalidateAllCachesForTest();
65    }
66
67    @Override
68    public void tearDown() throws Exception {
69        super.tearDown();
70        mTestController.cleanupForTest();
71    }
72
73    /**
74     * Lightweight subclass of the Controller class allows injection of mock context
75     */
76    public static class TestController extends Controller {
77
78        protected TestController(Context providerContext, Context systemContext) {
79            super(systemContext);
80            setProviderContext(providerContext);
81        }
82    }
83
84    /**
85     * These are strings that should not change per locale.
86     */
87    public void testGetMailboxServerName() {
88        assertEquals("", mTestController.getMailboxServerName(-1));
89
90        assertEquals("Inbox", mTestController.getMailboxServerName(Mailbox.TYPE_INBOX));
91        assertEquals("Outbox", mTestController.getMailboxServerName(Mailbox.TYPE_OUTBOX));
92        assertEquals("Trash", mTestController.getMailboxServerName(Mailbox.TYPE_TRASH));
93        assertEquals("Sent", mTestController.getMailboxServerName(Mailbox.TYPE_SENT));
94        assertEquals("Junk", mTestController.getMailboxServerName(Mailbox.TYPE_JUNK));
95
96        // Now try again with translation
97        Locale savedLocale = Locale.getDefault();
98        Locale.setDefault(Locale.FRANCE);
99        assertEquals("Inbox", mTestController.getMailboxServerName(Mailbox.TYPE_INBOX));
100        assertEquals("Outbox", mTestController.getMailboxServerName(Mailbox.TYPE_OUTBOX));
101        assertEquals("Trash", mTestController.getMailboxServerName(Mailbox.TYPE_TRASH));
102        assertEquals("Sent", mTestController.getMailboxServerName(Mailbox.TYPE_SENT));
103        assertEquals("Junk", mTestController.getMailboxServerName(Mailbox.TYPE_JUNK));
104        Locale.setDefault(savedLocale);
105    }
106
107    /**
108     * Test of Controller.createMailbox().
109     * Sunny day test only - creates a mailbox that does not exist.
110     * Does not test duplication, bad accountID, or any other bad input.
111     */
112    public void testCreateMailbox() {
113        Account account = ProviderTestUtils.setupAccount("mailboxid", true, mProviderContext);
114        long accountId = account.mId;
115
116        long oldBoxId = Mailbox.findMailboxOfType(mProviderContext, accountId, Mailbox.TYPE_DRAFTS);
117        assertEquals(Mailbox.NO_MAILBOX, oldBoxId);
118
119        mTestController.createMailbox(accountId, Mailbox.TYPE_DRAFTS);
120        long boxId = Mailbox.findMailboxOfType(mProviderContext, accountId, Mailbox.TYPE_DRAFTS);
121
122        // check that the drafts mailbox exists
123        assertTrue("mailbox exists", boxId != Mailbox.NO_MAILBOX);
124    }
125
126    /**
127     * Test of Controller.findOrCreateMailboxOfType().
128     * Checks:
129     * - finds correctly the ID of existing mailbox
130     * - creates non-existing mailbox
131     * - creates only once a new mailbox
132     * - when accountId or mailboxType are -1, returns NO_MAILBOX
133     */
134    public void testFindOrCreateMailboxOfType() {
135        Account account = ProviderTestUtils.setupAccount("mailboxid", true, mProviderContext);
136        long accountId = account.mId;
137        Mailbox box = ProviderTestUtils.setupMailbox("box", accountId, false, mProviderContext);
138        final int boxType = Mailbox.TYPE_TRASH;
139        box.mType = boxType;
140        box.save(mProviderContext);
141        long boxId = box.mId;
142
143        long testBoxId = mTestController.findOrCreateMailboxOfType(accountId, boxType);
144
145        // check it found the right mailbox id
146        assertEquals(boxId, testBoxId);
147
148        long boxId2 = mTestController.findOrCreateMailboxOfType(accountId, Mailbox.TYPE_DRAFTS);
149        assertTrue("mailbox created", boxId2 != Mailbox.NO_MAILBOX);
150        assertTrue("with different id", testBoxId != boxId2);
151
152        // check it doesn't create twice when existing
153        long boxId3 = mTestController.findOrCreateMailboxOfType(accountId, Mailbox.TYPE_DRAFTS);
154        assertEquals("don't create if exists", boxId3, boxId2);
155
156        // check invalid aruments
157        assertEquals(Mailbox.NO_MAILBOX,
158                mTestController.findOrCreateMailboxOfType(-1, Mailbox.TYPE_DRAFTS));
159        assertEquals(Mailbox.NO_MAILBOX, mTestController.findOrCreateMailboxOfType(accountId, -1));
160    }
161
162    /**
163     * Test the "move message" function.
164     */
165    public void testMoveMessage() throws InterruptedException, ExecutionException {
166        Account account1 = ProviderTestUtils.setupAccount("message-move", true, mProviderContext);
167        long account1Id = account1.mId;
168        Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mProviderContext);
169        long box1Id = box1.mId;
170        Mailbox box2 = ProviderTestUtils.setupMailbox("box2", account1Id, true, mProviderContext);
171        long box2Id = box2.mId;
172        Mailbox boxDest = ProviderTestUtils.setupMailbox("d", account1Id, true, mProviderContext);
173        long boxDestId = boxDest.mId;
174
175        Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false,
176                true, mProviderContext);
177        Message message2 = ProviderTestUtils.setupMessage("message2", account1Id, box2Id, false,
178                true, mProviderContext);
179        long message1Id = message1.mId;
180        long message2Id = message2.mId;
181
182        // Because moveMessage runs asynchronously, call get() to force it to complete
183        mTestController.moveMessages(
184                new long[] { message1Id, message2Id }, boxDestId).waitForFinish();
185
186        // now read back a fresh copy and confirm it's in the trash
187        assertEquals(boxDestId, EmailContent.Message.restoreMessageWithId(mProviderContext,
188                message1Id).mMailboxKey);
189        assertEquals(boxDestId, EmailContent.Message.restoreMessageWithId(mProviderContext,
190                message2Id).mMailboxKey);
191    }
192
193    /**
194     * Test the "delete message" function.  Sunny day:
195     *    - message/mailbox/account all exist
196     *    - trash mailbox exists
197     */
198    public void testDeleteMessage() {
199        Account account1 = ProviderTestUtils.setupAccount("message-delete", true, mProviderContext);
200        long account1Id = account1.mId;
201        Mailbox box = ProviderTestUtils.setupMailbox("box1", account1Id, true, mProviderContext);
202        long boxId = box.mId;
203
204        Mailbox trashBox = ProviderTestUtils.setupMailbox("box2", account1Id, false,
205                mProviderContext);
206        trashBox.mType = EmailContent.Mailbox.TYPE_TRASH;
207        trashBox.save(mProviderContext);
208        long trashBoxId = trashBox.mId;
209
210        Mailbox draftBox = ProviderTestUtils.setupMailbox("box3", account1Id, false,
211                mProviderContext);
212        draftBox.mType = EmailContent.Mailbox.TYPE_DRAFTS;
213        draftBox.save(mProviderContext);
214        long draftBoxId = draftBox.mId;
215
216        {
217            // Case 1: Message in a regular mailbox, account known.
218            Message message = ProviderTestUtils.setupMessage("message1", account1Id, boxId, false,
219                    true, mProviderContext);
220            long messageId = message.mId;
221
222            mTestController.deleteMessageSync(messageId, account1Id);
223
224            // now read back a fresh copy and confirm it's in the trash
225            Message restored = EmailContent.Message.restoreMessageWithId(mProviderContext,
226                    messageId);
227            assertEquals(trashBoxId, restored.mMailboxKey);
228        }
229
230        {
231            // Case 2: Message in a regular mailbox, account *un*known.
232            Message message = ProviderTestUtils.setupMessage("message2", account1Id, boxId, false,
233                    true, mProviderContext);
234            long messageId = message.mId;
235
236            mTestController.deleteMessageSync(messageId, -1);
237
238            // now read back a fresh copy and confirm it's in the trash
239            Message restored = EmailContent.Message.restoreMessageWithId(mProviderContext,
240                    messageId);
241            assertEquals(trashBoxId, restored.mMailboxKey);
242        }
243
244        {
245            // Case 3: Already in trash
246            Message message = ProviderTestUtils.setupMessage("message3", account1Id, trashBoxId,
247                    false, true, mProviderContext);
248            long messageId = message.mId;
249
250            mTestController.deleteMessageSync(messageId, account1Id);
251
252            // Message should be deleted.
253            assertNull(EmailContent.Message.restoreMessageWithId(mProviderContext, messageId));
254        }
255
256        {
257            // Case 4: Draft
258            Message message = ProviderTestUtils.setupMessage("message3", account1Id, draftBoxId,
259                    false, true, mProviderContext);
260            long messageId = message.mId;
261
262            mTestController.deleteMessageSync(messageId, account1Id);
263
264            // Message should be deleted.
265            assertNull(EmailContent.Message.restoreMessageWithId(mProviderContext, messageId));
266        }
267    }
268
269    /**
270     * Test deleting message when there is no trash mailbox
271     */
272    public void testDeleteMessageNoTrash() {
273        Account account1 =
274                ProviderTestUtils.setupAccount("message-delete-notrash", true, mProviderContext);
275        long account1Id = account1.mId;
276        Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mProviderContext);
277        long box1Id = box1.mId;
278
279        Message message1 =
280                ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, true,
281                        mProviderContext);
282        long message1Id = message1.mId;
283
284        mTestController.deleteMessageSync(message1Id, account1Id);
285
286        // now read back a fresh copy and confirm it's in the trash
287        Message message1get =
288                EmailContent.Message.restoreMessageWithId(mProviderContext, message1Id);
289
290        // check the new mailbox and see if it looks right
291        assertFalse(-1 == message1get.mMailboxKey);
292        assertFalse(box1Id == message1get.mMailboxKey);
293        Mailbox mailbox2get = EmailContent.Mailbox.restoreMailboxWithId(mProviderContext,
294                message1get.mMailboxKey);
295        assertEquals(EmailContent.Mailbox.TYPE_TRASH, mailbox2get.mType);
296    }
297
298    /**
299     * Test read/unread flag
300     */
301    public void testReadUnread() throws InterruptedException, ExecutionException {
302        Account account1 = ProviderTestUtils.setupAccount("read-unread", false, mProviderContext);
303        account1.mHostAuthRecv
304                = ProviderTestUtils.setupHostAuth("read-unread", 0, false, mProviderContext);
305        account1.save(mProviderContext);
306        long account1Id = account1.mId;
307        long box1Id = 2;
308
309        Message message1 =
310                ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, true,
311                        mProviderContext);
312        long message1Id = message1.mId;
313
314        // test setting to "read"
315        mTestController.setMessageRead(message1Id, true).get();
316        Message message1get = Message.restoreMessageWithId(mProviderContext, message1Id);
317        assertTrue(message1get.mFlagRead);
318
319        // test setting to "unread"
320        mTestController.setMessageRead(message1Id, false).get();
321        message1get = Message.restoreMessageWithId(mProviderContext, message1Id);
322        assertFalse(message1get.mFlagRead);
323
324        // test setting to "read"
325        mTestController.setMessageRead(message1Id, true).get();
326        message1get = Message.restoreMessageWithId(mProviderContext, message1Id);
327        assertTrue(message1get.mFlagRead);
328    }
329
330    /**
331     * Test favorites flag
332     */
333    public void testFavorites() throws InterruptedException, ExecutionException {
334        Account account1 = ProviderTestUtils.setupAccount("favorites", false, mProviderContext);
335        account1.mHostAuthRecv
336                = ProviderTestUtils.setupHostAuth("favorites", 0, false, mProviderContext);
337        account1.save(mProviderContext);
338        long account1Id = account1.mId;
339        long box1Id = 2;
340
341        Message message1 =
342                ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, true,
343                        mProviderContext);
344        long message1Id = message1.mId;
345
346        // test setting to "favorite"
347        mTestController.setMessageFavorite(message1Id, true).get();
348        Message message1get = Message.restoreMessageWithId(mProviderContext, message1Id);
349        assertTrue(message1get.mFlagFavorite);
350
351        // test setting to "not favorite"
352        mTestController.setMessageFavorite(message1Id, false).get();
353        message1get = Message.restoreMessageWithId(mProviderContext, message1Id);
354        assertFalse(message1get.mFlagFavorite);
355
356        // test setting to "favorite"
357        mTestController.setMessageFavorite(message1Id, true).get();
358        message1get = Message.restoreMessageWithId(mProviderContext, message1Id);
359        assertTrue(message1get.mFlagFavorite);
360    }
361
362    public void testGetAndDeleteAttachmentMailbox() {
363        Mailbox box = mTestController.getAttachmentMailbox();
364        assertNotNull(box);
365        Mailbox anotherBox = mTestController.getAttachmentMailbox();
366        assertNotNull(anotherBox);
367        // We should always get back the same Mailbox row
368        assertEquals(box.mId, anotherBox.mId);
369        // Add two messages to this mailbox
370        ProviderTestUtils.setupMessage("message1", 0, box.mId, false, true,
371                mProviderContext);
372        ProviderTestUtils.setupMessage("message2", 0, box.mId, false, true,
373                mProviderContext);
374        // Make sure we can find them where they are expected
375        assertEquals(2, EmailContent.count(mProviderContext, Message.CONTENT_URI,
376                Message.MAILBOX_KEY + "=?", new String[] {Long.toString(box.mId)}));
377        // Delete them
378        mTestController.deleteAttachmentMessages();
379        // Make sure they're gone
380        assertEquals(0, EmailContent.count(mProviderContext, Message.CONTENT_URI,
381                Message.MAILBOX_KEY + "=?", new String[] {Long.toString(box.mId)}));
382    }
383
384    /**
385     * Test wiping an account's synced data.  Everything should go, but account & empty inbox.
386     * Also ensures that the remaining account and the remaining inbox have cleared their
387     * server sync keys, to force refresh eventually.
388     */
389    public void testWipeSyncedData() {
390        Account account1 = ProviderTestUtils.setupAccount("wipe-synced-1", false, mProviderContext);
391        account1.mSyncKey = "account-1-sync-key";
392        account1.save(mProviderContext);
393        long account1Id = account1.mId;
394        Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, false, mProviderContext);
395        box1.mType = Mailbox.TYPE_INBOX;
396        box1.mSyncKey = "box-1-sync-key";
397        box1.save(mProviderContext);
398        long box1Id = box1.mId;
399        Mailbox box2 = ProviderTestUtils.setupMailbox("box2", account1Id, true, mProviderContext);
400        long box2Id = box2.mId;
401        // An EAS account mailbox
402        Mailbox eas = ProviderTestUtils.setupMailbox("eas", account1Id, false, mProviderContext);
403        eas.mType = Mailbox.TYPE_EAS_ACCOUNT_MAILBOX;
404        eas.save(mProviderContext);
405
406        Account account2 = ProviderTestUtils.setupAccount("wipe-synced-2", false, mProviderContext);
407        account2.mSyncKey = "account-2-sync-key";
408        account2.save(mProviderContext);
409        long account2Id = account2.mId;
410        Mailbox box3 = ProviderTestUtils.setupMailbox("box3", account2Id, false, mProviderContext);
411        box3.mSyncKey = "box-3-sync-key";
412        box3.mType = Mailbox.TYPE_INBOX;
413        box3.save(mProviderContext);
414        long box3Id = box3.mId;
415        Mailbox box4 = ProviderTestUtils.setupMailbox("box4", account2Id, true, mProviderContext);
416        long box4Id = box4.mId;
417
418        // Now populate the 4 non-account boxes with messages
419        Message message = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false,
420                true, mProviderContext);
421        long message1Id = message.mId;
422        message = ProviderTestUtils.setupMessage("message2", account1Id, box2Id, false,
423                true, mProviderContext);
424        long message2Id = message.mId;
425        message = ProviderTestUtils.setupMessage("message3", account2Id, box3Id, false,
426                true, mProviderContext);
427        long message3Id = message.mId;
428        message = ProviderTestUtils.setupMessage("message4", account2Id, box4Id, false,
429                true, mProviderContext);
430        long message4Id = message.mId;
431
432        // Now wipe account 1's data
433        mTestController.deleteSyncedDataSync(account1Id);
434
435        // Confirm:  Mailboxes gone (except account box), all messages gone, account survives
436        assertNull(Mailbox.restoreMailboxWithId(mProviderContext, box1Id));
437        assertNull(Mailbox.restoreMailboxWithId(mProviderContext, box2Id));
438        assertNotNull(Mailbox.restoreMailboxWithId(mProviderContext, eas.mId));
439        assertNull(Message.restoreMessageWithId(mProviderContext, message1Id));
440        assertNull(Message.restoreMessageWithId(mProviderContext, message2Id));
441        account1 = Account.restoreAccountWithId(mProviderContext, account1Id);
442        assertNotNull(account1);
443        assertNull(account1.mSyncKey);
444
445        // Confirm:  Other account survived
446        assertNotNull(Mailbox.restoreMailboxWithId(mProviderContext, box3Id));
447        assertNotNull(Mailbox.restoreMailboxWithId(mProviderContext, box4Id));
448        assertNotNull(Message.restoreMessageWithId(mProviderContext, message3Id));
449        assertNotNull(Message.restoreMessageWithId(mProviderContext, message4Id));
450        assertNotNull(Account.restoreAccountWithId(mProviderContext, account2Id));
451    }
452
453    public void testLoadMessageFromUri() throws Exception {
454        // Create a simple message
455        Message msg = new Message();
456        String text = "This is some text";
457        msg.mText = text;
458        String sender = "sender@host.com";
459        msg.mFrom = sender;
460        // Save this away
461        msg.save(mProviderContext);
462
463        Uri fileUri = ProviderTestUtils.createTempEmlFile(mProviderContext, msg,
464                mContext.getFilesDir());
465
466        // Load the message via Controller and a Uri
467        Message loadedMsg = mTestController.loadMessageFromUri(fileUri);
468
469        // Check server id, mailbox key, account key, and from
470        assertNotNull(loadedMsg);
471        assertTrue(loadedMsg.mServerId.startsWith(Controller.ATTACHMENT_MESSAGE_UID_PREFIX));
472        Mailbox box = mTestController.getAttachmentMailbox();
473        assertNotNull(box);
474        assertEquals(box.mId, loadedMsg.mMailboxKey);
475        assertEquals(0, loadedMsg.mAccountKey);
476        assertEquals(loadedMsg.mFrom, sender);
477        // Check body text
478        String loadedMsgText = Body.restoreBodyTextWithMessageId(mProviderContext, loadedMsg.mId);
479        assertEquals(text, loadedMsgText);
480    }
481
482    /**
483     * Create a simple HostAuth with protocol
484     */
485    private HostAuth setupSimpleHostAuth(String protocol) {
486        HostAuth hostAuth = new HostAuth();
487        hostAuth.mProtocol = protocol;
488        return hostAuth;
489    }
490
491    public void testIsMessagingController() {
492        Account account1 = ProviderTestUtils.setupAccount("account1", false,
493                mProviderContext);
494        account1.mHostAuthRecv = setupSimpleHostAuth("eas");
495        account1.save(mProviderContext);
496        assertFalse(mTestController.isMessagingController(account1));
497        Account account2 = ProviderTestUtils.setupAccount("account2", false,
498                mProviderContext);
499        account2.mHostAuthRecv = setupSimpleHostAuth("imap");
500        account2.save(mProviderContext);
501        assertTrue(mTestController.isMessagingController(account2));
502        Account account3 = ProviderTestUtils.setupAccount("account3", false,
503                mProviderContext);
504        account3.mHostAuthRecv = setupSimpleHostAuth("pop3");
505        account3.save(mProviderContext);
506        assertTrue(mTestController.isMessagingController(account3));
507        Account account4 = ProviderTestUtils.setupAccount("account4", false,
508                mProviderContext);
509        account4.mHostAuthRecv = setupSimpleHostAuth("smtp");
510        account4.save(mProviderContext);
511        assertFalse(mTestController.isMessagingController(account4));
512        // There should be values for all of these accounts in the legacy map
513        assertNotNull(mTestController.mLegacyControllerMap.get(account1.mId));
514        assertNotNull(mTestController.mLegacyControllerMap.get(account2.mId));
515        assertNotNull(mTestController.mLegacyControllerMap.get(account3.mId));
516        assertNotNull(mTestController.mLegacyControllerMap.get(account4.mId));
517        // The map should have the expected values
518        assertFalse(mTestController.mLegacyControllerMap.get(account1.mId));
519        assertTrue(mTestController.mLegacyControllerMap.get(account2.mId));
520        assertTrue(mTestController.mLegacyControllerMap.get(account3.mId));
521        assertFalse(mTestController.mLegacyControllerMap.get(account4.mId));
522        // This second pass should pull values from the cache
523        assertFalse(mTestController.isMessagingController(account1));
524        assertTrue(mTestController.isMessagingController(account2));
525        assertTrue(mTestController.isMessagingController(account3));
526        assertFalse(mTestController.isMessagingController(account4));
527    }
528
529    /**
530     * TODO: releasing associated data (e.g. attachments, embedded images)
531     */
532}
533