ControllerProviderOpsTests.java revision 31d9acbf0623872f9d4a2b3210b5970854b654c7
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.moveMessage(new long[] {message1Id, message2Id}, boxDestId).get();
184
185        // now read back a fresh copy and confirm it's in the trash
186        assertEquals(boxDestId, EmailContent.Message.restoreMessageWithId(mProviderContext,
187                message1Id).mMailboxKey);
188        assertEquals(boxDestId, EmailContent.Message.restoreMessageWithId(mProviderContext,
189                message2Id).mMailboxKey);
190    }
191
192    /**
193     * Test the "delete message" function.  Sunny day:
194     *    - message/mailbox/account all exist
195     *    - trash mailbox exists
196     */
197    public void testDeleteMessage() throws InterruptedException, ExecutionException {
198        Account account1 = ProviderTestUtils.setupAccount("message-delete", true, mProviderContext);
199        long account1Id = account1.mId;
200        Mailbox box = ProviderTestUtils.setupMailbox("box1", account1Id, true, mProviderContext);
201        long boxId = box.mId;
202
203        Mailbox trashBox = ProviderTestUtils.setupMailbox("box2", account1Id, false,
204                mProviderContext);
205        trashBox.mType = EmailContent.Mailbox.TYPE_TRASH;
206        trashBox.save(mProviderContext);
207        long trashBoxId = trashBox.mId;
208
209        Mailbox draftBox = ProviderTestUtils.setupMailbox("box3", account1Id, false,
210                mProviderContext);
211        draftBox.mType = EmailContent.Mailbox.TYPE_DRAFTS;
212        draftBox.save(mProviderContext);
213        long draftBoxId = draftBox.mId;
214
215        {
216            // Case 1: Message in a regular mailbox, account known.
217            Message message = ProviderTestUtils.setupMessage("message1", account1Id, boxId, false,
218                    true, mProviderContext);
219            long messageId = message.mId;
220
221            mTestController.deleteMessageSync(messageId, account1Id);
222
223            // now read back a fresh copy and confirm it's in the trash
224            Message restored = EmailContent.Message.restoreMessageWithId(mProviderContext,
225                    messageId);
226            assertEquals(trashBoxId, restored.mMailboxKey);
227        }
228
229        {
230            // Case 2: Message in a regular mailbox, account *un*known.
231            Message message = ProviderTestUtils.setupMessage("message2", account1Id, boxId, false,
232                    true, mProviderContext);
233            long messageId = message.mId;
234
235            mTestController.deleteMessageSync(messageId, -1);
236
237            // now read back a fresh copy and confirm it's in the trash
238            Message restored = EmailContent.Message.restoreMessageWithId(mProviderContext,
239                    messageId);
240            assertEquals(trashBoxId, restored.mMailboxKey);
241        }
242
243        {
244            // Case 3: Already in trash
245            Message message = ProviderTestUtils.setupMessage("message3", account1Id, trashBoxId,
246                    false, true, mProviderContext);
247            long messageId = message.mId;
248
249            mTestController.deleteMessageSync(messageId, account1Id);
250
251            // Message should be deleted.
252            assertNull(EmailContent.Message.restoreMessageWithId(mProviderContext, messageId));
253        }
254
255        {
256            // Case 4: Draft
257            Message message = ProviderTestUtils.setupMessage("message3", account1Id, draftBoxId,
258                    false, true, mProviderContext);
259            long messageId = message.mId;
260
261            mTestController.deleteMessageSync(messageId, account1Id);
262
263            // Message should be deleted.
264            assertNull(EmailContent.Message.restoreMessageWithId(mProviderContext, messageId));
265        }
266    }
267
268    /**
269     * Test deleting message when there is no trash mailbox
270     */
271    public void testDeleteMessageNoTrash() throws InterruptedException, ExecutionException {
272        Account account1 =
273                ProviderTestUtils.setupAccount("message-delete-notrash", true, mProviderContext);
274        long account1Id = account1.mId;
275        Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mProviderContext);
276        long box1Id = box1.mId;
277
278        Message message1 =
279                ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, true,
280                        mProviderContext);
281        long message1Id = message1.mId;
282
283        mTestController.deleteMessageSync(message1Id, account1Id);
284
285        // now read back a fresh copy and confirm it's in the trash
286        Message message1get =
287                EmailContent.Message.restoreMessageWithId(mProviderContext, message1Id);
288
289        // check the new mailbox and see if it looks right
290        assertFalse(-1 == message1get.mMailboxKey);
291        assertFalse(box1Id == message1get.mMailboxKey);
292        Mailbox mailbox2get = EmailContent.Mailbox.restoreMailboxWithId(mProviderContext,
293                message1get.mMailboxKey);
294        assertEquals(EmailContent.Mailbox.TYPE_TRASH, mailbox2get.mType);
295    }
296
297    /**
298     * Test read/unread flag
299     */
300    public void testReadUnread() throws InterruptedException, ExecutionException {
301        Account account1 = ProviderTestUtils.setupAccount("read-unread", false, mProviderContext);
302        account1.mHostAuthRecv
303                = ProviderTestUtils.setupHostAuth("read-unread", 0, false, mProviderContext);
304        account1.save(mProviderContext);
305        long account1Id = account1.mId;
306        long box1Id = 2;
307
308        Message message1 =
309                ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, true,
310                        mProviderContext);
311        long message1Id = message1.mId;
312
313        // test setting to "read"
314        mTestController.setMessageRead(message1Id, true).get();
315        Message message1get = Message.restoreMessageWithId(mProviderContext, message1Id);
316        assertTrue(message1get.mFlagRead);
317
318        // test setting to "unread"
319        mTestController.setMessageRead(message1Id, false).get();
320        message1get = Message.restoreMessageWithId(mProviderContext, message1Id);
321        assertFalse(message1get.mFlagRead);
322
323        // test setting to "read"
324        mTestController.setMessageRead(message1Id, true).get();
325        message1get = Message.restoreMessageWithId(mProviderContext, message1Id);
326        assertTrue(message1get.mFlagRead);
327    }
328
329    /**
330     * Test favorites flag
331     */
332    public void testFavorites() throws InterruptedException, ExecutionException {
333        Account account1 = ProviderTestUtils.setupAccount("favorites", false, mProviderContext);
334        account1.mHostAuthRecv
335                = ProviderTestUtils.setupHostAuth("favorites", 0, false, mProviderContext);
336        account1.save(mProviderContext);
337        long account1Id = account1.mId;
338        long box1Id = 2;
339
340        Message message1 =
341                ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, true,
342                        mProviderContext);
343        long message1Id = message1.mId;
344
345        // test setting to "favorite"
346        mTestController.setMessageFavorite(message1Id, true).get();
347        Message message1get = Message.restoreMessageWithId(mProviderContext, message1Id);
348        assertTrue(message1get.mFlagFavorite);
349
350        // test setting to "not favorite"
351        mTestController.setMessageFavorite(message1Id, false).get();
352        message1get = Message.restoreMessageWithId(mProviderContext, message1Id);
353        assertFalse(message1get.mFlagFavorite);
354
355        // test setting to "favorite"
356        mTestController.setMessageFavorite(message1Id, true).get();
357        message1get = Message.restoreMessageWithId(mProviderContext, message1Id);
358        assertTrue(message1get.mFlagFavorite);
359    }
360
361    public void testGetAndDeleteAttachmentMailbox() {
362        Mailbox box = mTestController.getAttachmentMailbox();
363        assertNotNull(box);
364        Mailbox anotherBox = mTestController.getAttachmentMailbox();
365        assertNotNull(anotherBox);
366        // We should always get back the same Mailbox row
367        assertEquals(box.mId, anotherBox.mId);
368        // Add two messages to this mailbox
369        ProviderTestUtils.setupMessage("message1", 0, box.mId, false, true,
370                mProviderContext);
371        ProviderTestUtils.setupMessage("message2", 0, box.mId, false, true,
372                mProviderContext);
373        // Make sure we can find them where they are expected
374        assertEquals(2, EmailContent.count(mProviderContext, Message.CONTENT_URI,
375                Message.MAILBOX_KEY + "=?", new String[] {Long.toString(box.mId)}));
376        // Delete them
377        mTestController.deleteAttachmentMessages();
378        // Make sure they're gone
379        assertEquals(0, EmailContent.count(mProviderContext, Message.CONTENT_URI,
380                Message.MAILBOX_KEY + "=?", new String[] {Long.toString(box.mId)}));
381    }
382
383    /**
384     * Test wiping an account's synced data.  Everything should go, but account & empty inbox.
385     * Also ensures that the remaining account and the remaining inbox have cleared their
386     * server sync keys, to force refresh eventually.
387     */
388    public void testWipeSyncedData() {
389        Account account1 = ProviderTestUtils.setupAccount("wipe-synced-1", false, mProviderContext);
390        account1.mSyncKey = "account-1-sync-key";
391        account1.save(mProviderContext);
392        long account1Id = account1.mId;
393        Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, false, mProviderContext);
394        box1.mType = Mailbox.TYPE_INBOX;
395        box1.mSyncKey = "box-1-sync-key";
396        box1.save(mProviderContext);
397        long box1Id = box1.mId;
398        Mailbox box2 = ProviderTestUtils.setupMailbox("box2", account1Id, true, mProviderContext);
399        long box2Id = box2.mId;
400        // An EAS account mailbox
401        Mailbox eas = ProviderTestUtils.setupMailbox("eas", account1Id, false, mProviderContext);
402        eas.mType = Mailbox.TYPE_EAS_ACCOUNT_MAILBOX;
403        eas.save(mProviderContext);
404
405        Account account2 = ProviderTestUtils.setupAccount("wipe-synced-2", false, mProviderContext);
406        account2.mSyncKey = "account-2-sync-key";
407        account2.save(mProviderContext);
408        long account2Id = account2.mId;
409        Mailbox box3 = ProviderTestUtils.setupMailbox("box3", account2Id, false, mProviderContext);
410        box3.mSyncKey = "box-3-sync-key";
411        box3.mType = Mailbox.TYPE_INBOX;
412        box3.save(mProviderContext);
413        long box3Id = box3.mId;
414        Mailbox box4 = ProviderTestUtils.setupMailbox("box4", account2Id, true, mProviderContext);
415        long box4Id = box4.mId;
416
417        // Now populate the 4 non-account boxes with messages
418        Message message = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false,
419                true, mProviderContext);
420        long message1Id = message.mId;
421        message = ProviderTestUtils.setupMessage("message2", account1Id, box2Id, false,
422                true, mProviderContext);
423        long message2Id = message.mId;
424        message = ProviderTestUtils.setupMessage("message3", account2Id, box3Id, false,
425                true, mProviderContext);
426        long message3Id = message.mId;
427        message = ProviderTestUtils.setupMessage("message4", account2Id, box4Id, false,
428                true, mProviderContext);
429        long message4Id = message.mId;
430
431        // Now wipe account 1's data
432        mTestController.deleteSyncedDataSync(account1Id);
433
434        // Confirm:  Mailboxes gone (except account box), all messages gone, account survives
435        assertNull(Mailbox.restoreMailboxWithId(mProviderContext, box1Id));
436        assertNull(Mailbox.restoreMailboxWithId(mProviderContext, box2Id));
437        assertNotNull(Mailbox.restoreMailboxWithId(mProviderContext, eas.mId));
438        assertNull(Message.restoreMessageWithId(mProviderContext, message1Id));
439        assertNull(Message.restoreMessageWithId(mProviderContext, message2Id));
440        account1 = Account.restoreAccountWithId(mProviderContext, account1Id);
441        assertNotNull(account1);
442        assertNull(account1.mSyncKey);
443
444        // Confirm:  Other account survived
445        assertNotNull(Mailbox.restoreMailboxWithId(mProviderContext, box3Id));
446        assertNotNull(Mailbox.restoreMailboxWithId(mProviderContext, box4Id));
447        assertNotNull(Message.restoreMessageWithId(mProviderContext, message3Id));
448        assertNotNull(Message.restoreMessageWithId(mProviderContext, message4Id));
449        assertNotNull(Account.restoreAccountWithId(mProviderContext, account2Id));
450    }
451
452    public void testLoadMessageFromUri() throws Exception {
453        // Create a simple message
454        Message msg = new Message();
455        String text = "This is some text";
456        msg.mText = text;
457        String sender = "sender@host.com";
458        msg.mFrom = sender;
459        // Save this away
460        msg.save(mProviderContext);
461
462        Uri fileUri = ProviderTestUtils.createTempEmlFile(mProviderContext, msg,
463                mContext.getFilesDir());
464
465        // Load the message via Controller and a Uri
466        Message loadedMsg = mTestController.loadMessageFromUri(fileUri);
467
468        // Check server id, mailbox key, account key, and from
469        assertNotNull(loadedMsg);
470        assertTrue(loadedMsg.mServerId.startsWith(Controller.ATTACHMENT_MESSAGE_UID_PREFIX));
471        Mailbox box = mTestController.getAttachmentMailbox();
472        assertNotNull(box);
473        assertEquals(box.mId, loadedMsg.mMailboxKey);
474        assertEquals(0, loadedMsg.mAccountKey);
475        assertEquals(loadedMsg.mFrom, sender);
476        // Check body text
477        String loadedMsgText = Body.restoreBodyTextWithMessageId(mProviderContext, loadedMsg.mId);
478        assertEquals(text, loadedMsgText);
479    }
480
481    /**
482     * Create a simple HostAuth with protocol
483     */
484    private HostAuth setupSimpleHostAuth(String protocol) {
485        HostAuth hostAuth = new HostAuth();
486        hostAuth.mProtocol = protocol;
487        return hostAuth;
488    }
489
490    public void testIsMessagingController() {
491        Account account1 = ProviderTestUtils.setupAccount("account1", false,
492                mProviderContext);
493        account1.mHostAuthRecv = setupSimpleHostAuth("eas");
494        account1.save(mProviderContext);
495        assertFalse(mTestController.isMessagingController(account1));
496        Account account2 = ProviderTestUtils.setupAccount("account2", false,
497                mProviderContext);
498        account2.mHostAuthRecv = setupSimpleHostAuth("imap");
499        account2.save(mProviderContext);
500        assertTrue(mTestController.isMessagingController(account2));
501        Account account3 = ProviderTestUtils.setupAccount("account3", false,
502                mProviderContext);
503        account3.mHostAuthRecv = setupSimpleHostAuth("pop3");
504        account3.save(mProviderContext);
505        assertTrue(mTestController.isMessagingController(account3));
506        Account account4 = ProviderTestUtils.setupAccount("account4", false,
507                mProviderContext);
508        account4.mHostAuthRecv = setupSimpleHostAuth("smtp");
509        account4.save(mProviderContext);
510        assertFalse(mTestController.isMessagingController(account4));
511        // There should be values for all of these accounts in the legacy map
512        assertNotNull(mTestController.mLegacyControllerMap.get(account1.mId));
513        assertNotNull(mTestController.mLegacyControllerMap.get(account2.mId));
514        assertNotNull(mTestController.mLegacyControllerMap.get(account3.mId));
515        assertNotNull(mTestController.mLegacyControllerMap.get(account4.mId));
516        // The map should have the expected values
517        assertFalse(mTestController.mLegacyControllerMap.get(account1.mId));
518        assertTrue(mTestController.mLegacyControllerMap.get(account2.mId));
519        assertTrue(mTestController.mLegacyControllerMap.get(account3.mId));
520        assertFalse(mTestController.mLegacyControllerMap.get(account4.mId));
521        // This second pass should pull values from the cache
522        assertFalse(mTestController.isMessagingController(account1));
523        assertTrue(mTestController.isMessagingController(account2));
524        assertTrue(mTestController.isMessagingController(account3));
525        assertFalse(mTestController.isMessagingController(account4));
526    }
527
528    /**
529     * TODO: releasing associated data (e.g. attachments, embedded images)
530     */
531}
532