• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.email.provider;
18 
19 import com.android.email.provider.EmailContent.Account;
20 import com.android.email.provider.EmailContent.AccountColumns;
21 import com.android.email.provider.EmailContent.Attachment;
22 import com.android.email.provider.EmailContent.AttachmentColumns;
23 import com.android.email.provider.EmailContent.Body;
24 import com.android.email.provider.EmailContent.BodyColumns;
25 import com.android.email.provider.EmailContent.HostAuth;
26 import com.android.email.provider.EmailContent.Mailbox;
27 import com.android.email.provider.EmailContent.MailboxColumns;
28 import com.android.email.provider.EmailContent.Message;
29 import com.android.email.provider.EmailContent.MessageColumns;
30 
31 import android.content.ContentResolver;
32 import android.content.ContentUris;
33 import android.content.ContentValues;
34 import android.content.Context;
35 import android.database.Cursor;
36 import android.net.Uri;
37 import android.os.Bundle;
38 import android.os.Environment;
39 import android.os.Parcel;
40 import android.test.MoreAsserts;
41 import android.test.ProviderTestCase2;
42 
43 import java.io.File;
44 import java.io.IOException;
45 import java.util.ArrayList;
46 
47 /**
48  * Tests of the Email provider.
49  *
50  * You can run this entire test case with:
51  *   runtest -c com.android.email.provider.ProviderTests email
52  */
53 public class ProviderTests extends ProviderTestCase2<EmailProvider> {
54 
55     EmailProvider mProvider;
56     Context mMockContext;
57 
ProviderTests()58     public ProviderTests() {
59         super(EmailProvider.class, EmailProvider.EMAIL_AUTHORITY);
60     }
61 
62     @Override
setUp()63     public void setUp() throws Exception {
64         super.setUp();
65         mMockContext = getMockContext();
66     }
67 
68     @Override
tearDown()69     public void tearDown() throws Exception {
70         super.tearDown();
71     }
72 
73     /**
74      * TODO: Database upgrade tests
75      */
76 
77     /**
78      * Test simple account save/retrieve
79      */
testAccountSave()80     public void testAccountSave() {
81         Account account1 = ProviderTestUtils.setupAccount("account-save", true, mMockContext);
82         long account1Id = account1.mId;
83 
84         Account account2 = EmailContent.Account.restoreAccountWithId(mMockContext, account1Id);
85 
86         ProviderTestUtils.assertAccountEqual("testAccountSave", account1, account2);
87     }
88 
89     /**
90      * Test simple account save/retrieve with predefined hostauth records
91      */
testAccountSaveHostAuth()92     public void testAccountSaveHostAuth() {
93         Account account1 = ProviderTestUtils.setupAccount("account-hostauth", false, mMockContext);
94         // add hostauth data, which should be saved the first time
95         account1.mHostAuthRecv = ProviderTestUtils.setupHostAuth("account-hostauth-recv", -1, false,
96                 mMockContext);
97         account1.mHostAuthSend = ProviderTestUtils.setupHostAuth("account-hostauth-send", -1, false,
98                 mMockContext);
99         account1.save(mMockContext);
100         long account1Id = account1.mId;
101 
102         // Confirm account reads back correctly
103         Account account1get = EmailContent.Account.restoreAccountWithId(mMockContext, account1Id);
104         ProviderTestUtils.assertAccountEqual("testAccountSave", account1, account1get);
105 
106         // Confirm hostauth fields can be accessed & read back correctly
107         HostAuth hostAuth1get = EmailContent.HostAuth.restoreHostAuthWithId(mMockContext,
108                 account1get.mHostAuthKeyRecv);
109         ProviderTestUtils.assertHostAuthEqual("testAccountSaveHostAuth-recv",
110                 account1.mHostAuthRecv, hostAuth1get);
111         HostAuth hostAuth2get = EmailContent.HostAuth.restoreHostAuthWithId(mMockContext,
112                 account1get.mHostAuthKeySend);
113         ProviderTestUtils.assertHostAuthEqual("testAccountSaveHostAuth-send",
114                 account1.mHostAuthSend, hostAuth2get);
115     }
116 
117     /**
118      * Simple test of account parceling.  The rather tortuous path is to ensure that the
119      * account is really flattened all the way down to a parcel and back.
120      */
testAccountParcel()121     public void testAccountParcel() {
122         Account account1 = ProviderTestUtils.setupAccount("parcel", false, mMockContext);
123         Bundle b = new Bundle();
124         b.putParcelable("account", account1);
125         Parcel p = Parcel.obtain();
126         b.writeToParcel(p, 0);
127         p.setDataPosition(0);       // rewind it for reading
128         Bundle b2 = new Bundle(Account.class.getClassLoader());
129         b2.readFromParcel(p);
130         Account account2 = (Account) b2.getParcelable("account");
131         p.recycle();
132 
133         ProviderTestUtils.assertAccountEqual("testAccountParcel", account1, account2);
134     }
135 
136     /**
137      * Test for {@link Account#getShortcutSafeUri()} and
138      * {@link Account#getAccountIdForShortcutSafeUri}.
139      */
testAccountShortcutSafeUri()140     public void testAccountShortcutSafeUri() {
141         final Account account1 = ProviderTestUtils.setupAccount("account-1", true, mMockContext);
142         final Account account2 = ProviderTestUtils.setupAccount("account-2", true, mMockContext);
143         final long account1Id = account1.mId;
144         final long account2Id = account2.mId;
145 
146         final Uri uri1 = account1.getShortcutSafeUri();
147         final Uri uri2 = account2.getShortcutSafeUri();
148 
149         // Check the path part of the URIs.
150         MoreAsserts.assertEquals(new String[] {"account", account1.mCompatibilityUuid},
151                 uri1.getPathSegments().toArray());
152         MoreAsserts.assertEquals(new String[] {"account", account2.mCompatibilityUuid},
153                 uri2.getPathSegments().toArray());
154 
155         assertEquals(account1Id, Account.getAccountIdFromShortcutSafeUri(mMockContext, uri1));
156         assertEquals(account2Id, Account.getAccountIdFromShortcutSafeUri(mMockContext, uri2));
157 
158         // Test for the Eclair(2.0-2.1) style URI.
159         assertEquals(account1Id, Account.getAccountIdFromShortcutSafeUri(mMockContext,
160                 getEclairStyleShortcutUri(account1)));
161         assertEquals(account2Id, Account.getAccountIdFromShortcutSafeUri(mMockContext,
162                 getEclairStyleShortcutUri(account2)));
163     }
164 
getEclairStyleShortcutUri(Account account)165     private static Uri getEclairStyleShortcutUri(Account account) {
166         // We used _id instead of UUID only on Eclair(2.0-2.1).
167         return Account.CONTENT_URI.buildUpon().appendEncodedPath("" + account.mId).build();
168     }
169 
testAccountIsValidId()170     public void testAccountIsValidId() {
171         final Account account1 = ProviderTestUtils.setupAccount("account-1", true, mMockContext);
172         final Account account2 = ProviderTestUtils.setupAccount("account-2", true, mMockContext);
173 
174         assertTrue(Account.isValidId(mMockContext, account1.mId));
175         assertTrue(Account.isValidId(mMockContext, account2.mId));
176 
177         assertFalse(Account.isValidId(mMockContext, 1234567)); // Some random ID
178         assertFalse(Account.isValidId(mMockContext, -1));
179         assertFalse(Account.isValidId(mMockContext, -500));
180     }
181 
182     private final static String[] MAILBOX_UNREAD_COUNT_PROJECTION = new String [] {
183         MailboxColumns.UNREAD_COUNT
184     };
185     private final static int MAILBOX_UNREAD_COUNT_COLMUN = 0;
186 
187     /**
188      * Get the value of the unread count in the mailbox of the account.
189      * This can be different from the actual number of unread messages in that mailbox.
190      * @param accountId
191      * @param mailboxId
192      * @return
193      */
getUnreadCount(long mailboxId)194     private int getUnreadCount(long mailboxId) {
195         String text = null;
196         Cursor c = null;
197         try {
198             c = mMockContext.getContentResolver().query(
199                     Mailbox.CONTENT_URI,
200                     MAILBOX_UNREAD_COUNT_PROJECTION,
201                     EmailContent.RECORD_ID + "=?",
202                     new String[] { String.valueOf(mailboxId) },
203                     null);
204             c.moveToFirst();
205             text = c.getString(MAILBOX_UNREAD_COUNT_COLMUN);
206         } finally {
207             c.close();
208         }
209         return Integer.valueOf(text);
210     }
211 
212     /**
213      * TODO: HostAuth tests
214      */
215 
216     /**
217      * Test the various combinations of SSL, TLS, and trust-certificates encoded as Uris
218      */
219     @SuppressWarnings("deprecation")
testHostAuthSecurityUri()220     public void testHostAuthSecurityUri() {
221         HostAuth ha = ProviderTestUtils.setupHostAuth("uri-security", 1, false, mMockContext);
222 
223         final int MASK =
224             HostAuth.FLAG_SSL | HostAuth.FLAG_TLS | HostAuth.FLAG_TRUST_ALL_CERTIFICATES;
225 
226         // Set various URIs and check the resulting flags
227         ha.setStoreUri("protocol://user:password@server:123");
228         assertEquals(0, ha.mFlags & MASK);
229         ha.setStoreUri("protocol+ssl+://user:password@server:123");
230         assertEquals(HostAuth.FLAG_SSL, ha.mFlags & MASK);
231         ha.setStoreUri("protocol+ssl+trustallcerts://user:password@server:123");
232         assertEquals(HostAuth.FLAG_SSL | HostAuth.FLAG_TRUST_ALL_CERTIFICATES, ha.mFlags & MASK);
233         ha.setStoreUri("protocol+tls+://user:password@server:123");
234         assertEquals(HostAuth.FLAG_TLS, ha.mFlags & MASK);
235         ha.setStoreUri("protocol+tls+trustallcerts://user:password@server:123");
236         assertEquals(HostAuth.FLAG_TLS | HostAuth.FLAG_TRUST_ALL_CERTIFICATES, ha.mFlags & MASK);
237 
238         // Now check the retrival method (building URI from flags)
239         ha.mFlags &= ~MASK;
240         String uriString = ha.getStoreUri();
241         assertTrue(uriString.startsWith("protocol://"));
242         ha.mFlags |= HostAuth.FLAG_SSL;
243         uriString = ha.getStoreUri();
244         assertTrue(uriString.startsWith("protocol+ssl+://"));
245         ha.mFlags |= HostAuth.FLAG_TRUST_ALL_CERTIFICATES;
246         uriString = ha.getStoreUri();
247         assertTrue(uriString.startsWith("protocol+ssl+trustallcerts://"));
248         ha.mFlags &= ~MASK;
249         ha.mFlags |= HostAuth.FLAG_TLS;
250         uriString = ha.getStoreUri();
251         assertTrue(uriString.startsWith("protocol+tls+://"));
252         ha.mFlags |= HostAuth.FLAG_TRUST_ALL_CERTIFICATES;
253         uriString = ha.getStoreUri();
254         assertTrue(uriString.startsWith("protocol+tls+trustallcerts://"));
255     }
256 
257     /**
258      * Test port assignments made from Uris
259      */
260     @SuppressWarnings("deprecation")
testHostAuthPortAssignments()261     public void testHostAuthPortAssignments() {
262         HostAuth ha = ProviderTestUtils.setupHostAuth("uri-port", 1, false, mMockContext);
263 
264         // Set various URIs and check the resulting flags
265         // Hardwired port
266         ha.setStoreUri("imap://user:password@server:123");
267         assertEquals(123, ha.mPort);
268         // Auto-assigned ports
269         ha.setStoreUri("imap://user:password@server");
270         assertEquals(143, ha.mPort);
271         ha.setStoreUri("imap+ssl://user:password@server");
272         assertEquals(993, ha.mPort);
273         ha.setStoreUri("imap+ssl+trustallcerts://user:password@server");
274         assertEquals(993, ha.mPort);
275         ha.setStoreUri("imap+tls://user:password@server");
276         assertEquals(143, ha.mPort);
277         ha.setStoreUri("imap+tls+trustallcerts://user:password@server");
278         assertEquals(143, ha.mPort);
279 
280         // Hardwired port
281         ha.setStoreUri("pop3://user:password@server:123");
282         assertEquals(123, ha.mPort);
283         // Auto-assigned ports
284         ha.setStoreUri("pop3://user:password@server");
285         assertEquals(110, ha.mPort);
286         ha.setStoreUri("pop3+ssl://user:password@server");
287         assertEquals(995, ha.mPort);
288         ha.setStoreUri("pop3+ssl+trustallcerts://user:password@server");
289         assertEquals(995, ha.mPort);
290         ha.setStoreUri("pop3+tls://user:password@server");
291         assertEquals(110, ha.mPort);
292         ha.setStoreUri("pop3+tls+trustallcerts://user:password@server");
293         assertEquals(110, ha.mPort);
294 
295         // Hardwired port
296         ha.setStoreUri("eas://user:password@server:123");
297         assertEquals(123, ha.mPort);
298         // Auto-assigned ports
299         ha.setStoreUri("eas://user:password@server");
300         assertEquals(80, ha.mPort);
301         ha.setStoreUri("eas+ssl://user:password@server");
302         assertEquals(443, ha.mPort);
303         ha.setStoreUri("eas+ssl+trustallcerts://user:password@server");
304         assertEquals(443, ha.mPort);
305 
306         // Hardwired port
307         ha.setStoreUri("smtp://user:password@server:123");
308         assertEquals(123, ha.mPort);
309         // Auto-assigned ports
310         ha.setStoreUri("smtp://user:password@server");
311         assertEquals(587, ha.mPort);
312         ha.setStoreUri("smtp+ssl://user:password@server");
313         assertEquals(465, ha.mPort);
314         ha.setStoreUri("smtp+ssl+trustallcerts://user:password@server");
315         assertEquals(465, ha.mPort);
316         ha.setStoreUri("smtp+tls://user:password@server");
317         assertEquals(587, ha.mPort);
318         ha.setStoreUri("smtp+tls+trustallcerts://user:password@server");
319         assertEquals(587, ha.mPort);
320     }
321 
322     /**
323      * Test simple mailbox save/retrieve
324      */
testMailboxSave()325     public void testMailboxSave() {
326         Account account1 = ProviderTestUtils.setupAccount("mailbox-save", true, mMockContext);
327         long account1Id = account1.mId;
328         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true,
329                 mMockContext);
330         long box1Id = box1.mId;
331 
332         Mailbox box2 = EmailContent.Mailbox.restoreMailboxWithId(mMockContext, box1Id);
333 
334         ProviderTestUtils.assertMailboxEqual("testMailboxSave", box1, box2);
335     }
336 
337     private static String[] expectedAttachmentNames =
338         new String[] {"attachment1.doc", "attachment2.xls", "attachment3"};
339     // The lengths need to be kept in ascending order
340     private static long[] expectedAttachmentSizes = new long[] {31415L, 97701L, 151213L};
341 
342     /*
343      * Returns null if the message has no body.
344      */
loadBodyForMessageId(long messageId)345     private Body loadBodyForMessageId(long messageId) {
346         Cursor c = null;
347         try {
348             c = mMockContext.getContentResolver().query(
349                     EmailContent.Body.CONTENT_URI,
350                     EmailContent.Body.CONTENT_PROJECTION,
351                     EmailContent.Body.MESSAGE_KEY + "=?",
352                     new String[] {String.valueOf(messageId)},
353                     null);
354             int numBodies = c.getCount();
355             assertTrue("at most one body", numBodies < 2);
356             return c.moveToFirst() ? EmailContent.getContent(c, Body.class) : null;
357         } finally {
358             c.close();
359         }
360     }
361 
362     /**
363      * Test simple message save/retrieve
364      *
365      * TODO: serverId vs. serverIntId
366      */
testMessageSave()367     public void testMessageSave() {
368         Account account1 = ProviderTestUtils.setupAccount("message-save", true, mMockContext);
369         long account1Id = account1.mId;
370         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
371         long box1Id = box1.mId;
372 
373         // Test a simple message (saved with no body)
374         Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false,
375                 true, mMockContext);
376         long message1Id = message1.mId;
377         Message message1get = EmailContent.Message.restoreMessageWithId(mMockContext, message1Id);
378         ProviderTestUtils.assertMessageEqual("testMessageSave", message1, message1get);
379 
380         // Test a message saved with a body
381         // Note that it will read back w/o the text & html so we must extract those
382         Message message2 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, true,
383                 true, mMockContext);
384         long message2Id = message2.mId;
385         String text2 = message2.mText;
386         String html2 = message2.mHtml;
387         String textReply2 = message2.mTextReply;
388         String htmlReply2 = message2.mHtmlReply;
389         long sourceKey2 = message2.mSourceKey;
390         String introText2 = message2.mIntroText;
391         message2.mText = null;
392         message2.mHtml = null;
393         message2.mTextReply = null;
394         message2.mHtmlReply = null;
395         message2.mSourceKey = 0;
396         message2.mIntroText = null;
397         Message message2get = EmailContent.Message.restoreMessageWithId(mMockContext, message2Id);
398         ProviderTestUtils.assertMessageEqual("testMessageSave", message2, message2get);
399 
400         // Now see if there's a body saved with the right stuff
401         Body body2 = loadBodyForMessageId(message2Id);
402         assertEquals("body text", text2, body2.mTextContent);
403         assertEquals("body html", html2, body2.mHtmlContent);
404         assertEquals("reply text", textReply2, body2.mTextReply);
405         assertEquals("reply html", htmlReply2, body2.mHtmlReply);
406         assertEquals("source key", sourceKey2, body2.mSourceKey);
407         assertEquals("intro text", introText2, body2.mIntroText);
408 
409         // Message with attachments and body
410         Message message3 = ProviderTestUtils.setupMessage("message3", account1Id, box1Id, true,
411                 false, mMockContext);
412         ArrayList<Attachment> atts = new ArrayList<Attachment>();
413         for (int i = 0; i < 3; i++) {
414             atts.add(ProviderTestUtils.setupAttachment(
415                     -1, expectedAttachmentNames[i], expectedAttachmentSizes[i],
416                     false, mMockContext));
417         }
418         message3.mAttachments = atts;
419         message3.save(mMockContext);
420         long message3Id = message3.mId;
421 
422         // Now check the attachments; there should be three and they should match name and size
423         Cursor c = null;
424         try {
425             // Note that there is NO guarantee of the order of returned records in the general case,
426             // so we specifically ask for ordering by size.  The expectedAttachmentSizes array must
427             // be kept sorted by size (ascending) for this test to work properly
428             c = mMockContext.getContentResolver().query(
429                     Attachment.CONTENT_URI,
430                     Attachment.CONTENT_PROJECTION,
431                     Attachment.MESSAGE_KEY + "=?",
432                     new String[] {
433                             String.valueOf(message3Id)
434                     },
435                     Attachment.SIZE);
436             int numAtts = c.getCount();
437             assertEquals(3, numAtts);
438             int i = 0;
439             while (c.moveToNext()) {
440                 Attachment actual = EmailContent.getContent(c, Attachment.class);
441                 ProviderTestUtils.assertAttachmentEqual("save-message3", atts.get(i), actual);
442                 i++;
443             }
444         } finally {
445             c.close();
446         }
447 
448         // Message with attachments but no body
449         Message message4 = ProviderTestUtils.setupMessage("message4", account1Id, box1Id, false,
450                 false, mMockContext);
451         atts = new ArrayList<Attachment>();
452         for (int i = 0; i < 3; i++) {
453             atts.add(ProviderTestUtils.setupAttachment(
454                     -1, expectedAttachmentNames[i], expectedAttachmentSizes[i],
455                     false, mMockContext));
456         }
457         message4.mAttachments = atts;
458         message4.save(mMockContext);
459         long message4Id = message4.mId;
460 
461         // Now check the attachments; there should be three and they should match name and size
462         c = null;
463 
464         try {
465             // Note that there is NO guarantee of the order of returned records in the general case,
466             // so we specifically ask for ordering by size.  The expectedAttachmentSizes array must
467             // be kept sorted by size (ascending) for this test to work properly
468             c = mMockContext.getContentResolver().query(
469                     Attachment.CONTENT_URI,
470                     Attachment.CONTENT_PROJECTION,
471                     Attachment.MESSAGE_KEY + "=?",
472                     new String[] {
473                             String.valueOf(message4Id)
474                     },
475                     Attachment.SIZE);
476             int numAtts = c.getCount();
477             assertEquals(3, numAtts);
478             int i = 0;
479             while (c.moveToNext()) {
480                 Attachment actual = EmailContent.getContent(c, Attachment.class);
481                 ProviderTestUtils.assertAttachmentEqual("save-message4", atts.get(i), actual);
482                 i++;
483             }
484         } finally {
485             c.close();
486         }
487 
488         // test EmailContent.restoreAttachmentsWitdMessageId()
489         Attachment[] attachments =
490             Attachment.restoreAttachmentsWithMessageId(mMockContext, message4Id);
491         int size = attachments.length;
492         assertEquals(3, size);
493         for (int i = 0; i < size; ++i) {
494             ProviderTestUtils.assertAttachmentEqual("save-message4", atts.get(i), attachments[i]);
495         }
496     }
497 
498     /**
499      * TODO: update account
500      */
501 
502     /**
503      * TODO: update mailbox
504      */
505 
506     /**
507      * TODO: update message
508      */
509 
510     /**
511      * Test delete account
512      * TODO: hostauth
513      */
testAccountDelete()514     public void testAccountDelete() {
515         Account account1 = ProviderTestUtils.setupAccount("account-delete-1", true, mMockContext);
516         long account1Id = account1.mId;
517         Account account2 = ProviderTestUtils.setupAccount("account-delete-2", true, mMockContext);
518         long account2Id = account2.mId;
519 
520         // make sure there are two accounts
521         int numBoxes = EmailContent.count(mMockContext, Account.CONTENT_URI, null, null);
522         assertEquals(2, numBoxes);
523 
524         // now delete one of them
525         Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, account1Id);
526         mMockContext.getContentResolver().delete(uri, null, null);
527 
528         // make sure there's only one account now
529         numBoxes = EmailContent.count(mMockContext, Account.CONTENT_URI, null, null);
530         assertEquals(1, numBoxes);
531 
532         // now delete the other one
533         uri = ContentUris.withAppendedId(Account.CONTENT_URI, account2Id);
534         mMockContext.getContentResolver().delete(uri, null, null);
535 
536         // make sure there are no accounts now
537         numBoxes = EmailContent.count(mMockContext, Account.CONTENT_URI, null, null);
538         assertEquals(0, numBoxes);
539     }
540 
541     /**
542      * Test for Body.lookupBodyIdWithMessageId()
543      * Verifies that:
544      * - for a message without body, -1 is returned.
545      * - for a mesage with body, the id matches the one from loadBodyForMessageId.
546      */
testLookupBodyIdWithMessageId()547     public void testLookupBodyIdWithMessageId() {
548         final ContentResolver resolver = mMockContext.getContentResolver();
549         Account account1 = ProviderTestUtils.setupAccount("orphaned body", true, mMockContext);
550         long account1Id = account1.mId;
551         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
552         long box1Id = box1.mId;
553 
554         // 1. create message with no body, check that returned bodyId is -1
555         Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false,
556                 true, mMockContext);
557         long message1Id = message1.mId;
558         long bodyId1 = Body.lookupBodyIdWithMessageId(resolver, message1Id);
559         assertEquals(bodyId1, -1);
560 
561         // 2. create message with body, check that returned bodyId is correct
562         Message message2 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, true,
563                 true, mMockContext);
564         long message2Id = message2.mId;
565         long bodyId2 = Body.lookupBodyIdWithMessageId(resolver, message2Id);
566         Body body = loadBodyForMessageId(message2Id);
567         assertNotNull(body);
568         assertEquals(body.mId, bodyId2);
569     }
570 
571     /**
572      * Test for Body.updateBodyWithMessageId().
573      * 1. - create message without body,
574      *    - update its body (set TEXT_CONTENT)
575      *    - check correct updated body is read back
576      *
577      * 2. - create message with body,
578      *    - update body (set TEXT_CONTENT)
579      *    - check correct updated body is read back
580      */
testUpdateBodyWithMessageId()581     public void testUpdateBodyWithMessageId() {
582         Account account1 = ProviderTestUtils.setupAccount("orphaned body", true, mMockContext);
583         long account1Id = account1.mId;
584         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
585         long box1Id = box1.mId;
586 
587         final String textContent = "foobar some odd text";
588         final String htmlContent = "and some html";
589         final String textReply = "plain text reply";
590         final String htmlReply = "or the html reply";
591         final String introText = "fred wrote:";
592 
593         ContentValues values = new ContentValues();
594         values.put(BodyColumns.TEXT_CONTENT, textContent);
595         values.put(BodyColumns.HTML_CONTENT, htmlContent);
596         values.put(BodyColumns.TEXT_REPLY, textReply);
597         values.put(BodyColumns.HTML_REPLY, htmlReply);
598         values.put(BodyColumns.SOURCE_MESSAGE_KEY, 17);
599         values.put(BodyColumns.INTRO_TEXT, introText);
600 
601         // 1
602         Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false,
603                 true, mMockContext);
604         long message1Id = message1.mId;
605         Body body1 = loadBodyForMessageId(message1Id);
606         assertNull(body1);
607         Body.updateBodyWithMessageId(mMockContext, message1Id, values);
608         body1 = loadBodyForMessageId(message1Id);
609         assertNotNull(body1);
610         assertEquals(body1.mTextContent, textContent);
611         assertEquals(body1.mHtmlContent, htmlContent);
612         assertEquals(body1.mTextReply, textReply);
613         assertEquals(body1.mHtmlReply, htmlReply);
614         assertEquals(body1.mSourceKey, 17);
615         assertEquals(body1.mIntroText, introText);
616 
617         // 2
618         Message message2 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, true,
619                 true, mMockContext);
620         long message2Id = message2.mId;
621         Body body2 = loadBodyForMessageId(message2Id);
622         assertNotNull(body2);
623         assertTrue(!body2.mTextContent.equals(textContent));
624         Body.updateBodyWithMessageId(mMockContext, message2Id, values);
625         body2 = loadBodyForMessageId(message1Id);
626         assertNotNull(body2);
627         assertEquals(body2.mTextContent, textContent);
628         assertEquals(body2.mHtmlContent, htmlContent);
629         assertEquals(body2.mTextReply, textReply);
630         assertEquals(body2.mHtmlReply, htmlReply);
631         assertEquals(body2.mSourceKey, 17);
632         assertEquals(body2.mIntroText, introText);
633     }
634 
635     /**
636      * Test body retrieve methods
637      */
testBodyRetrieve()638     public void testBodyRetrieve() {
639         // No account needed
640         // No mailbox needed
641         Message message1 = ProviderTestUtils.setupMessage("bodyretrieve", 1, 1, true,
642                 true, mMockContext);
643         long messageId = message1.mId;
644 
645         assertEquals(message1.mText,
646                 Body.restoreBodyTextWithMessageId(mMockContext, messageId));
647         assertEquals(message1.mHtml,
648                 Body.restoreBodyHtmlWithMessageId(mMockContext, messageId));
649         assertEquals(message1.mTextReply,
650                 Body.restoreReplyTextWithMessageId(mMockContext, messageId));
651         assertEquals(message1.mHtmlReply,
652                 Body.restoreReplyHtmlWithMessageId(mMockContext, messageId));
653         assertEquals(message1.mIntroText,
654                 Body.restoreIntroTextWithMessageId(mMockContext, messageId));
655         assertEquals(message1.mSourceKey,
656                 Body.restoreBodySourceKey(mMockContext, messageId));
657     }
658 
659     /**
660      * Test delete body.
661      * 1. create message without body (message id 1)
662      * 2. create message with body (message id 2. The body has _id 1 and messageKey 2).
663      * 3. delete first message.
664      * 4. verify that body for message 2 has not been deleted.
665      * 5. delete message 2, verify body is deleted.
666      */
testDeleteBody()667     public void testDeleteBody() {
668         final ContentResolver resolver = mMockContext.getContentResolver();
669 
670         // Create account and mailboxes
671         Account account1 = ProviderTestUtils.setupAccount("orphaned body", true, mMockContext);
672         long account1Id = account1.mId;
673         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
674         long box1Id = box1.mId;
675 
676         // 1. create message without body
677         Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false,
678                 true, mMockContext);
679         long message1Id = message1.mId;
680 
681         // 2. create message with body
682         Message message2 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, true,
683                 true, mMockContext);
684         long message2Id = message2.mId;
685         // verify body is there
686         assertNotNull(loadBodyForMessageId(message2Id));
687 
688         // 3. delete first message
689         resolver.delete(ContentUris.withAppendedId(Message.CONTENT_URI, message1Id), null, null);
690 
691         // 4. verify body for second message wasn't deleted
692         assertNotNull(loadBodyForMessageId(message2Id));
693 
694         // 5. delete second message, check its body is deleted
695         resolver.delete(ContentUris.withAppendedId(Message.CONTENT_URI, message2Id), null, null);
696         assertNull(loadBodyForMessageId(message2Id));
697     }
698 
699     /**
700      * Test delete orphan bodies.
701      * 1. create message without body (message id 1)
702      * 2. create message with body (message id 2. Body has _id 1 and messageKey 2).
703      * 3. delete first message.
704      * 4. delete some other mailbox -- this triggers delete orphan bodies.
705      * 5. verify that body for message 2 has not been deleted.
706      */
testDeleteOrphanBodies()707     public void testDeleteOrphanBodies() {
708         final ContentResolver resolver = mMockContext.getContentResolver();
709 
710         // Create account and two mailboxes
711         Account account1 = ProviderTestUtils.setupAccount("orphaned body", true, mMockContext);
712         long account1Id = account1.mId;
713         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
714         long box1Id = box1.mId;
715         Mailbox box2 = ProviderTestUtils.setupMailbox("box2", account1Id, true, mMockContext);
716         long box2Id = box2.mId;
717 
718         // 1. create message without body
719         Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false,
720                 true, mMockContext);
721         long message1Id = message1.mId;
722 
723         // 2. create message with body
724         Message message2 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, true,
725                 true, mMockContext);
726         long message2Id = message2.mId;
727         //verify body is there
728         assertNotNull(loadBodyForMessageId(message2Id));
729 
730         // 3. delete first message
731         resolver.delete(ContentUris.withAppendedId(Message.CONTENT_URI, message1Id), null, null);
732 
733         // 4. delete some mailbox (because it triggers "delete orphan bodies")
734         resolver.delete(ContentUris.withAppendedId(Mailbox.CONTENT_URI, box2Id), null, null);
735 
736         // 5. verify body for second message wasn't deleted during "delete orphan bodies"
737         assertNotNull(loadBodyForMessageId(message2Id));
738     }
739 
740     /**
741      * Test delete orphan messages
742      * 1. create message without body (message id 1)
743      * 2. create message with body (message id 2. Body has _id 1 and messageKey 2).
744      * 3. delete first message.
745      * 4. delete some other mailbox -- this triggers delete orphan bodies.
746      * 5. verify that body for message 2 has not been deleted.
747      */
testDeleteOrphanMessages()748      public void testDeleteOrphanMessages() {
749         final ContentResolver resolver = mMockContext.getContentResolver();
750         final Context context = mMockContext;
751 
752         // Create account and two mailboxes
753         Account acct = ProviderTestUtils.setupAccount("orphaned body", true, context);
754         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", acct.mId, true, context);
755         Mailbox box2 = ProviderTestUtils.setupMailbox("box2", acct.mId, true, context);
756 
757         // Create 4 messages in box1
758         Message msg1_1 =
759             ProviderTestUtils.setupMessage("message1", acct.mId, box1.mId, false, true, context);
760         Message msg1_2 =
761             ProviderTestUtils.setupMessage("message2", acct.mId, box1.mId, false, true, context);
762         Message msg1_3 =
763             ProviderTestUtils.setupMessage("message3", acct.mId, box1.mId, false, true, context);
764         Message msg1_4 =
765             ProviderTestUtils.setupMessage("message4", acct.mId, box1.mId, false, true, context);
766 
767         // Create 4 messages in box2
768         Message msg2_1 =
769             ProviderTestUtils.setupMessage("message1", acct.mId, box2.mId, false, true, context);
770         Message msg2_2 =
771             ProviderTestUtils.setupMessage("message2", acct.mId, box2.mId, false, true, context);
772         Message msg2_3 =
773             ProviderTestUtils.setupMessage("message3", acct.mId, box2.mId, false, true, context);
774         Message msg2_4 =
775             ProviderTestUtils.setupMessage("message4", acct.mId, box2.mId, false, true, context);
776 
777         // Delete 2 from each mailbox
778         resolver.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg1_1.mId),
779                 null, null);
780         resolver.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg1_2.mId),
781                 null, null);
782         resolver.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg2_1.mId),
783                 null, null);
784         resolver.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg2_2.mId),
785                 null, null);
786 
787         // There should be 4 items in the deleted item table
788         assertEquals(4, EmailContent.count(context, Message.DELETED_CONTENT_URI, null, null));
789 
790         // Update 2 from each mailbox
791         ContentValues v = new ContentValues();
792         v.put(MessageColumns.DISPLAY_NAME, "--updated--");
793         resolver.update(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg1_3.mId),
794                 v, null, null);
795         resolver.update(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg1_4.mId),
796                 v, null, null);
797         resolver.update(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg2_3.mId),
798                 v, null, null);
799         resolver.update(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg2_4.mId),
800                 v, null, null);
801 
802          // There should be 4 items in the updated item table
803         assertEquals(4, EmailContent.count(context, Message.UPDATED_CONTENT_URI, null, null));
804 
805         // Manually add 2 messages from a "deleted" mailbox to deleted and updated tables
806         // Use a value > 2 for the deleted box id
807         long delBoxId = 10;
808         // Create 4 messages in the "deleted" mailbox
809         Message msgX_A =
810             ProviderTestUtils.setupMessage("messageA", acct.mId, delBoxId, false, false, context);
811         Message msgX_B =
812             ProviderTestUtils.setupMessage("messageB", acct.mId, delBoxId, false, false, context);
813         Message msgX_C =
814             ProviderTestUtils.setupMessage("messageC", acct.mId, delBoxId, false, false, context);
815         Message msgX_D =
816             ProviderTestUtils.setupMessage("messageD", acct.mId, delBoxId, false, false, context);
817 
818         ContentValues cv;
819         // We have to assign id's manually because there are no autoincrement id's for these tables
820         // Start with an id that won't exist, since id's in these tables must be unique
821         long msgId = 10;
822         // It's illegal to manually insert these, so we need to catch the exception
823         // NOTE: The insert succeeds, and then throws the exception
824         try {
825             cv = msgX_A.toContentValues();
826             cv.put(EmailContent.RECORD_ID, msgId++);
827             resolver.insert(Message.DELETED_CONTENT_URI, cv);
828         } catch (IllegalArgumentException e) {
829         }
830         try {
831             cv = msgX_B.toContentValues();
832             cv.put(EmailContent.RECORD_ID, msgId++);
833             resolver.insert(Message.DELETED_CONTENT_URI, cv);
834         } catch (IllegalArgumentException e) {
835         }
836         try {
837             cv = msgX_C.toContentValues();
838             cv.put(EmailContent.RECORD_ID, msgId++);
839             resolver.insert(Message.UPDATED_CONTENT_URI, cv);
840         } catch (IllegalArgumentException e) {
841         }
842         try {
843             cv = msgX_D.toContentValues();
844             cv.put(EmailContent.RECORD_ID, msgId++);
845             resolver.insert(Message.UPDATED_CONTENT_URI, cv);
846         } catch (IllegalArgumentException e) {
847         }
848 
849         // There should be 6 items in the deleted and updated tables
850         assertEquals(6, EmailContent.count(context, Message.UPDATED_CONTENT_URI, null, null));
851         assertEquals(6, EmailContent.count(context, Message.DELETED_CONTENT_URI, null, null));
852 
853         // Delete the orphans
854         EmailProvider.deleteOrphans(EmailProvider.getReadableDatabase(context),
855                 Message.DELETED_TABLE_NAME);
856         EmailProvider.deleteOrphans(EmailProvider.getReadableDatabase(context),
857                 Message.UPDATED_TABLE_NAME);
858 
859         // There should now be 4 messages in each of the deleted and updated tables again
860         assertEquals(4, EmailContent.count(context, Message.UPDATED_CONTENT_URI, null, null));
861         assertEquals(4, EmailContent.count(context, Message.DELETED_CONTENT_URI, null, null));
862     }
863 
864     /**
865      * Test delete mailbox
866      */
testMailboxDelete()867     public void testMailboxDelete() {
868         Account account1 = ProviderTestUtils.setupAccount("mailbox-delete", true, mMockContext);
869         long account1Id = account1.mId;
870         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
871         long box1Id = box1.mId;
872         Mailbox box2 = ProviderTestUtils.setupMailbox("box2", account1Id, true, mMockContext);
873         long box2Id = box2.mId;
874 
875         String selection = EmailContent.MailboxColumns.ACCOUNT_KEY + "=?";
876         String[] selArgs = new String[] { String.valueOf(account1Id) };
877 
878         // make sure there are two mailboxes
879         int numBoxes = EmailContent.count(mMockContext, Mailbox.CONTENT_URI, selection, selArgs);
880         assertEquals(2, numBoxes);
881 
882         // now delete one of them
883         Uri uri = ContentUris.withAppendedId(Mailbox.CONTENT_URI, box1Id);
884         mMockContext.getContentResolver().delete(uri, null, null);
885 
886         // make sure there's only one mailbox now
887         numBoxes = EmailContent.count(mMockContext, Mailbox.CONTENT_URI, selection, selArgs);
888         assertEquals(1, numBoxes);
889 
890         // now delete the other one
891         uri = ContentUris.withAppendedId(Mailbox.CONTENT_URI, box2Id);
892         mMockContext.getContentResolver().delete(uri, null, null);
893 
894         // make sure there are no mailboxes now
895         numBoxes = EmailContent.count(mMockContext, Mailbox.CONTENT_URI, selection, selArgs);
896         assertEquals(0, numBoxes);
897     }
898 
899     /**
900      * Test delete message
901      * TODO: body
902      * TODO: attachments
903      */
testMessageDelete()904     public void testMessageDelete() {
905         Account account1 = ProviderTestUtils.setupAccount("message-delete", true, mMockContext);
906         long account1Id = account1.mId;
907         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
908         long box1Id = box1.mId;
909         Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false,
910                 true, mMockContext);
911         long message1Id = message1.mId;
912         Message message2 = ProviderTestUtils.setupMessage("message2", account1Id, box1Id, false,
913                 true, mMockContext);
914         long message2Id = message2.mId;
915 
916         String selection = EmailContent.MessageColumns.ACCOUNT_KEY + "=? AND " +
917                 EmailContent.MessageColumns.MAILBOX_KEY + "=?";
918         String[] selArgs = new String[] { String.valueOf(account1Id), String.valueOf(box1Id) };
919 
920         // make sure there are two messages
921         int numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs);
922         assertEquals(2, numMessages);
923 
924         // now delete one of them
925         Uri uri = ContentUris.withAppendedId(Message.CONTENT_URI, message1Id);
926         mMockContext.getContentResolver().delete(uri, null, null);
927 
928         // make sure there's only one message now
929         numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs);
930         assertEquals(1, numMessages);
931 
932         // now delete the other one
933         uri = ContentUris.withAppendedId(Message.CONTENT_URI, message2Id);
934         mMockContext.getContentResolver().delete(uri, null, null);
935 
936         // make sure there are no messages now
937         numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs);
938         assertEquals(0, numMessages);
939     }
940 
941     /**
942      * Test delete synced message
943      * TODO: body
944      * TODO: attachments
945      */
testSyncedMessageDelete()946     public void testSyncedMessageDelete() {
947         Account account1 = ProviderTestUtils.setupAccount("synced-message-delete", true,
948                 mMockContext);
949         long account1Id = account1.mId;
950         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
951         long box1Id = box1.mId;
952         Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false,
953                 true, mMockContext);
954         long message1Id = message1.mId;
955         Message message2 = ProviderTestUtils.setupMessage("message2", account1Id, box1Id, false,
956                 true, mMockContext);
957         long message2Id = message2.mId;
958 
959         String selection = EmailContent.MessageColumns.ACCOUNT_KEY + "=? AND "
960                 + EmailContent.MessageColumns.MAILBOX_KEY + "=?";
961         String[] selArgs = new String[] {
962             String.valueOf(account1Id), String.valueOf(box1Id)
963         };
964 
965         // make sure there are two messages
966         int numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs);
967         assertEquals(2, numMessages);
968 
969         // make sure we start with no synced deletions
970         numMessages = EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection,
971                 selArgs);
972         assertEquals(0, numMessages);
973 
974         // now delete one of them SYNCED
975         Uri uri = ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message1Id);
976         mMockContext.getContentResolver().delete(uri, null, null);
977 
978         // make sure there's only one message now
979         numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs);
980         assertEquals(1, numMessages);
981 
982         // make sure there's one synced deletion now
983         numMessages = EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection,
984                 selArgs);
985         assertEquals(1, numMessages);
986 
987         // now delete the other one NOT SYNCED
988         uri = ContentUris.withAppendedId(Message.CONTENT_URI, message2Id);
989         mMockContext.getContentResolver().delete(uri, null, null);
990 
991         // make sure there are no messages now
992         numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs);
993         assertEquals(0, numMessages);
994 
995         // make sure there's still one deletion now
996         numMessages = EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection,
997                 selArgs);
998         assertEquals(1, numMessages);
999     }
1000 
1001     /**
1002      * Test message update
1003      * TODO: body
1004      * TODO: attachments
1005      */
testMessageUpdate()1006     public void testMessageUpdate() {
1007         Account account1 = ProviderTestUtils.setupAccount("message-update", true, mMockContext);
1008         long account1Id = account1.mId;
1009         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
1010         long box1Id = box1.mId;
1011         Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false,
1012                 true, mMockContext);
1013         long message1Id = message1.mId;
1014         Message message2 = ProviderTestUtils.setupMessage("message2", account1Id, box1Id, false,
1015                 true, mMockContext);
1016         long message2Id = message2.mId;
1017         ContentResolver cr = mMockContext.getContentResolver();
1018 
1019         String selection = EmailContent.MessageColumns.ACCOUNT_KEY + "=? AND "
1020                 + EmailContent.MessageColumns.MAILBOX_KEY + "=?";
1021         String[] selArgs = new String[] {
1022             String.valueOf(account1Id), String.valueOf(box1Id)
1023         };
1024 
1025         // make sure there are two messages
1026         int numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs);
1027         assertEquals(2, numMessages);
1028 
1029         // change the first one
1030         Uri uri = ContentUris.withAppendedId(Message.CONTENT_URI, message1Id);
1031         ContentValues cv = new ContentValues();
1032         cv.put(MessageColumns.FROM_LIST, "from-list");
1033         cr.update(uri, cv, null, null);
1034 
1035         // make sure there's no updated message
1036         numMessages = EmailContent.count(mMockContext, Message.UPDATED_CONTENT_URI, selection,
1037                 selArgs);
1038         assertEquals(0, numMessages);
1039 
1040         // get the message back from the provider, make sure the change "stuck"
1041         Message restoredMessage = Message.restoreMessageWithId(mMockContext, message1Id);
1042         assertEquals("from-list", restoredMessage.mFrom);
1043 
1044         // change the second one
1045         uri = ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message2Id);
1046         cv = new ContentValues();
1047         cv.put(MessageColumns.FROM_LIST, "from-list");
1048         cr.update(uri, cv, null, null);
1049 
1050         // make sure there's one updated message
1051         numMessages = EmailContent.count(mMockContext, Message.UPDATED_CONTENT_URI, selection,
1052                 selArgs);
1053         assertEquals(1, numMessages);
1054 
1055         // get the message back from the provider, make sure the change "stuck",
1056         // as before
1057         restoredMessage = Message.restoreMessageWithId(mMockContext, message2Id);
1058         assertEquals("from-list", restoredMessage.mFrom);
1059 
1060         // get the original message back from the provider
1061         Cursor c = cr.query(Message.UPDATED_CONTENT_URI, Message.CONTENT_PROJECTION, null, null,
1062                 null);
1063         try {
1064             assertTrue(c.moveToFirst());
1065             Message originalMessage = EmailContent.getContent(c, Message.class);
1066             // make sure this has the original value
1067             assertEquals("from message2", originalMessage.mFrom);
1068             // Should only be one
1069             assertFalse(c.moveToNext());
1070         } finally {
1071             c.close();
1072         }
1073 
1074         // delete the second message
1075         cr.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message2Id), null, null);
1076 
1077         // hey, presto! the change should be gone
1078         numMessages = EmailContent.count(mMockContext, Message.UPDATED_CONTENT_URI, selection,
1079                 selArgs);
1080         assertEquals(0, numMessages);
1081 
1082         // and there should now be a deleted record
1083         numMessages = EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection,
1084                 selArgs);
1085         assertEquals(1, numMessages);
1086     }
1087 
1088     /**
1089      * TODO: cascaded delete account
1090      * TODO: hostauth
1091      * TODO: body
1092      * TODO: attachments
1093      * TODO: create other account, mailbox & messages and confirm the right objects were deleted
1094      */
testCascadeDeleteAccount()1095     public void testCascadeDeleteAccount() {
1096         Account account1 = ProviderTestUtils.setupAccount("account-delete-cascade", true,
1097                 mMockContext);
1098         long account1Id = account1.mId;
1099         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
1100         long box1Id = box1.mId;
1101         /* Message message1 = */ ProviderTestUtils.setupMessage("message1", account1Id, box1Id,
1102                 false, true, mMockContext);
1103         /* Message message2 = */ ProviderTestUtils.setupMessage("message2", account1Id, box1Id,
1104                 false, true, mMockContext);
1105 
1106         // make sure there is one account, one mailbox, and two messages
1107         int numAccounts = EmailContent.count(mMockContext, Account.CONTENT_URI, null, null);
1108         assertEquals(1, numAccounts);
1109         int numBoxes = EmailContent.count(mMockContext, Mailbox.CONTENT_URI, null, null);
1110         assertEquals(1, numBoxes);
1111         int numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null);
1112         assertEquals(2, numMessages);
1113 
1114         // delete the account
1115         Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, account1Id);
1116         mMockContext.getContentResolver().delete(uri, null, null);
1117 
1118         // make sure there are no accounts, mailboxes, or messages
1119         numAccounts = EmailContent.count(mMockContext, Account.CONTENT_URI, null, null);
1120         assertEquals(0, numAccounts);
1121         numBoxes = EmailContent.count(mMockContext, Mailbox.CONTENT_URI, null, null);
1122         assertEquals(0, numBoxes);
1123         numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null);
1124         assertEquals(0, numMessages);
1125     }
1126 
1127     /**
1128      * Test cascaded delete mailbox
1129      * TODO: body
1130      * TODO: attachments
1131      * TODO: create other mailbox & messages and confirm the right objects were deleted
1132      */
testCascadeDeleteMailbox()1133     public void testCascadeDeleteMailbox() {
1134         Account account1 = ProviderTestUtils.setupAccount("mailbox-delete-cascade", true,
1135                 mMockContext);
1136         long account1Id = account1.mId;
1137         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
1138         long box1Id = box1.mId;
1139         Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id,
1140                 false, true, mMockContext);
1141         Message message2 = ProviderTestUtils.setupMessage("message2", account1Id, box1Id,
1142                 false, true, mMockContext);
1143         Message message3 = ProviderTestUtils.setupMessage("message3", account1Id, box1Id,
1144                 false, true, mMockContext);
1145         Message message4 = ProviderTestUtils.setupMessage("message4", account1Id, box1Id,
1146                 false, true, mMockContext);
1147         ProviderTestUtils.setupMessage("message5", account1Id, box1Id, false, true, mMockContext);
1148         ProviderTestUtils.setupMessage("message6", account1Id, box1Id, false, true, mMockContext);
1149 
1150         String selection = EmailContent.MessageColumns.ACCOUNT_KEY + "=? AND " +
1151                 EmailContent.MessageColumns.MAILBOX_KEY + "=?";
1152         String[] selArgs = new String[] { String.valueOf(account1Id), String.valueOf(box1Id) };
1153 
1154         // make sure there are six messages
1155         int numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs);
1156         assertEquals(6, numMessages);
1157 
1158         ContentValues cv = new ContentValues();
1159         cv.put(Message.SERVER_ID, "SERVER_ID");
1160         ContentResolver resolver = mMockContext.getContentResolver();
1161 
1162         // Update two messages
1163         resolver.update(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message1.mId),
1164                 cv, null, null);
1165         resolver.update(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message2.mId),
1166                 cv, null, null);
1167         // Delete two messages
1168         resolver.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message3.mId),
1169                 null, null);
1170         resolver.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message4.mId),
1171                 null, null);
1172 
1173         // There should now be two messages in updated/deleted, and 4 in messages
1174         numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs);
1175         assertEquals(4, numMessages);
1176         numMessages = EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection,
1177                 selArgs);
1178         assertEquals(2, numMessages);
1179         numMessages = EmailContent.count(mMockContext, Message.UPDATED_CONTENT_URI, selection,
1180                 selArgs);
1181         assertEquals(2, numMessages);
1182 
1183         // now delete the mailbox
1184         Uri uri = ContentUris.withAppendedId(Mailbox.CONTENT_URI, box1Id);
1185         resolver.delete(uri, null, null);
1186 
1187         // there should now be zero messages in all three tables
1188         numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs);
1189         assertEquals(0, numMessages);
1190         numMessages = EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection,
1191                 selArgs);
1192         assertEquals(0, numMessages);
1193         numMessages = EmailContent.count(mMockContext, Message.UPDATED_CONTENT_URI, selection,
1194                 selArgs);
1195         assertEquals(0, numMessages);
1196     }
1197 
1198     /**
1199      * Test cascaded delete message
1200      * Confirms that deleting a message will also delete its body & attachments
1201      */
testCascadeMessageDelete()1202     public void testCascadeMessageDelete() {
1203         Account account1 = ProviderTestUtils.setupAccount("message-cascade", true, mMockContext);
1204         long account1Id = account1.mId;
1205         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
1206         long box1Id = box1.mId;
1207 
1208         // Each message has a body, and also give each 2 attachments
1209         Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, true,
1210                 false, mMockContext);
1211         ArrayList<Attachment> atts = new ArrayList<Attachment>();
1212         for (int i = 0; i < 2; i++) {
1213             atts.add(ProviderTestUtils.setupAttachment(
1214                     -1, expectedAttachmentNames[i], expectedAttachmentSizes[i],
1215                     false, mMockContext));
1216         }
1217         message1.mAttachments = atts;
1218         message1.save(mMockContext);
1219         long message1Id = message1.mId;
1220 
1221         Message message2 = ProviderTestUtils.setupMessage("message2", account1Id, box1Id, true,
1222                 false, mMockContext);
1223         atts = new ArrayList<Attachment>();
1224         for (int i = 0; i < 2; i++) {
1225             atts.add(ProviderTestUtils.setupAttachment(
1226                     -1, expectedAttachmentNames[i], expectedAttachmentSizes[i],
1227                     false, mMockContext));
1228         }
1229         message2.mAttachments = atts;
1230         message2.save(mMockContext);
1231         long message2Id = message2.mId;
1232 
1233         // Set up to test total counts of bodies & attachments for our test messages
1234         String bodySelection = BodyColumns.MESSAGE_KEY + " IN (?,?)";
1235         String attachmentSelection = AttachmentColumns.MESSAGE_KEY + " IN (?,?)";
1236         String[] selArgs = new String[] { String.valueOf(message1Id), String.valueOf(message2Id) };
1237 
1238         // make sure there are two bodies
1239         int numBodies = EmailContent.count(mMockContext, Body.CONTENT_URI, bodySelection, selArgs);
1240         assertEquals(2, numBodies);
1241 
1242         // make sure there are four attachments
1243         int numAttachments = EmailContent.count(mMockContext, Attachment.CONTENT_URI,
1244                 attachmentSelection, selArgs);
1245         assertEquals(4, numAttachments);
1246 
1247         // now delete one of the messages
1248         Uri uri = ContentUris.withAppendedId(Message.CONTENT_URI, message1Id);
1249         mMockContext.getContentResolver().delete(uri, null, null);
1250 
1251         // there should be one body and two attachments
1252         numBodies = EmailContent.count(mMockContext, Body.CONTENT_URI, bodySelection, selArgs);
1253         assertEquals(1, numBodies);
1254 
1255         numAttachments = EmailContent.count(mMockContext, Attachment.CONTENT_URI,
1256                 attachmentSelection, selArgs);
1257         assertEquals(2, numAttachments);
1258 
1259         // now delete the other message
1260         uri = ContentUris.withAppendedId(Message.CONTENT_URI, message2Id);
1261         mMockContext.getContentResolver().delete(uri, null, null);
1262 
1263         // make sure there are no bodies or attachments
1264         numBodies = EmailContent.count(mMockContext, Body.CONTENT_URI, bodySelection, selArgs);
1265         assertEquals(0, numBodies);
1266 
1267         numAttachments = EmailContent.count(mMockContext, Attachment.CONTENT_URI,
1268                 attachmentSelection, selArgs);
1269         assertEquals(0, numAttachments);
1270     }
1271 
1272     /**
1273      * Test that our unique file name algorithm works as expected.  Since this test requires an
1274      * SD card, we check the environment first, and return immediately if none is mounted.
1275      * @throws IOException
1276      */
testCreateUniqueFile()1277     public void testCreateUniqueFile() throws IOException {
1278         // Delete existing files, if they exist
1279         if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
1280             return;
1281         }
1282         try {
1283             String fileName = "A11achm3n1.doc";
1284             File uniqueFile = Attachment.createUniqueFile(fileName);
1285             assertEquals(fileName, uniqueFile.getName());
1286             if (uniqueFile.createNewFile()) {
1287                 uniqueFile = Attachment.createUniqueFile(fileName);
1288                 assertEquals("A11achm3n1-2.doc", uniqueFile.getName());
1289                 if (uniqueFile.createNewFile()) {
1290                     uniqueFile = Attachment.createUniqueFile(fileName);
1291                     assertEquals("A11achm3n1-3.doc", uniqueFile.getName());
1292                 }
1293            }
1294             fileName = "A11achm3n1";
1295             uniqueFile = Attachment.createUniqueFile(fileName);
1296             assertEquals(fileName, uniqueFile.getName());
1297             if (uniqueFile.createNewFile()) {
1298                 uniqueFile = Attachment.createUniqueFile(fileName);
1299                 assertEquals("A11achm3n1-2", uniqueFile.getName());
1300             }
1301         } finally {
1302             File directory = Environment.getExternalStorageDirectory();
1303             // These are the files that should be created earlier in the test.  Make sure
1304             // they are deleted for the next go-around
1305             String[] fileNames = new String[] {"A11achm3n1.doc", "A11achm3n1-2.doc", "A11achm3n1"};
1306             int length = fileNames.length;
1307             for (int i = 0; i < length; i++) {
1308                 File file = new File(directory, fileNames[i]);
1309                 if (file.exists()) {
1310                     file.delete();
1311                 }
1312             }
1313         }
1314     }
1315 
1316     /**
1317      * Test retrieving attachments by message ID (using EmailContent.Attachment.MESSAGE_ID_URI)
1318      */
testGetAttachmentByMessageIdUri()1319     public void testGetAttachmentByMessageIdUri() {
1320 
1321         // Note, we don't strictly need accounts, mailboxes or messages to run this test.
1322         Attachment a1 = ProviderTestUtils.setupAttachment(1, "a1", 100, true, mMockContext);
1323         Attachment a2 = ProviderTestUtils.setupAttachment(1, "a2", 200, true, mMockContext);
1324         ProviderTestUtils.setupAttachment(2, "a3", 300, true, mMockContext);
1325         ProviderTestUtils.setupAttachment(2, "a4", 400, true, mMockContext);
1326 
1327         // Now ask for the attachments of message id=1
1328         // Note: Using the "sort by size" trick to bring them back in expected order
1329         Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, 1);
1330         Cursor c = mMockContext.getContentResolver().query(uri, Attachment.CONTENT_PROJECTION,
1331                 null, null, Attachment.SIZE);
1332         assertEquals(2, c.getCount());
1333 
1334         try {
1335             c.moveToFirst();
1336             Attachment a1Get = EmailContent.getContent(c, Attachment.class);
1337             ProviderTestUtils.assertAttachmentEqual("getAttachByUri-1", a1, a1Get);
1338             c.moveToNext();
1339             Attachment a2Get = EmailContent.getContent(c, Attachment.class);
1340             ProviderTestUtils.assertAttachmentEqual("getAttachByUri-2", a2, a2Get);
1341         } finally {
1342             c.close();
1343         }
1344     }
1345 
1346     /**
1347      * Test deleting attachments by message ID (using EmailContent.Attachment.MESSAGE_ID_URI)
1348      */
testDeleteAttachmentByMessageIdUri()1349     public void testDeleteAttachmentByMessageIdUri() {
1350         ContentResolver mockResolver = mMockContext.getContentResolver();
1351 
1352         // Note, we don't strictly need accounts, mailboxes or messages to run this test.
1353         ProviderTestUtils.setupAttachment(1, "a1", 100, true, mMockContext);
1354         ProviderTestUtils.setupAttachment(1, "a2", 200, true, mMockContext);
1355         Attachment a3 = ProviderTestUtils.setupAttachment(2, "a3", 300, true, mMockContext);
1356         Attachment a4 = ProviderTestUtils.setupAttachment(2, "a4", 400, true, mMockContext);
1357 
1358         // Delete all attachments for message id=1
1359         Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, 1);
1360         mockResolver.delete(uri, null, null);
1361 
1362         // Read back all attachments and confirm that we have the expected remaining attachments
1363         // (the attachments that are set for message id=2).  Note order-by size to simplify test.
1364         Cursor c = mockResolver.query(Attachment.CONTENT_URI, Attachment.CONTENT_PROJECTION,
1365                 null, null, Attachment.SIZE);
1366         assertEquals(2, c.getCount());
1367 
1368         try {
1369             c.moveToFirst();
1370             Attachment a3Get = EmailContent.getContent(c, Attachment.class);
1371             ProviderTestUtils.assertAttachmentEqual("getAttachByUri-3", a3, a3Get);
1372             c.moveToNext();
1373             Attachment a4Get = EmailContent.getContent(c, Attachment.class);
1374             ProviderTestUtils.assertAttachmentEqual("getAttachByUri-4", a4, a4Get);
1375         } finally {
1376             c.close();
1377         }
1378     }
1379 
1380     /**
1381      * Tests of default account behavior
1382      *
1383      * 1.  Simple set/get
1384      * 2.  Moving default between 3 accounts
1385      * 3.  Delete default, make sure another becomes default
1386      */
testSetGetDefaultAccount()1387     public void testSetGetDefaultAccount() {
1388         // There should be no default account if there are no accounts
1389         long defaultAccountId = Account.getDefaultAccountId(mMockContext);
1390         assertEquals(-1, defaultAccountId);
1391 
1392         Account account1 = ProviderTestUtils.setupAccount("account-default-1", true, mMockContext);
1393         long account1Id = account1.mId;
1394         Account account2 = ProviderTestUtils.setupAccount("account-default-2", true, mMockContext);
1395         long account2Id = account2.mId;
1396         Account account3 = ProviderTestUtils.setupAccount("account-default-3", true, mMockContext);
1397         long account3Id = account3.mId;
1398 
1399         // With three accounts, but none marked default, confirm that some default account
1400         // is returned.  Which one is undefined here.
1401         defaultAccountId = Account.getDefaultAccountId(mMockContext);
1402         assertTrue(defaultAccountId == account1Id
1403                     || defaultAccountId == account2Id
1404                     || defaultAccountId == account3Id);
1405 
1406         updateIsDefault(account1, true);
1407         defaultAccountId = Account.getDefaultAccountId(mMockContext);
1408         assertEquals(account1Id, defaultAccountId);
1409 
1410         updateIsDefault(account2, true);
1411         defaultAccountId = Account.getDefaultAccountId(mMockContext);
1412         assertEquals(account2Id, defaultAccountId);
1413 
1414         updateIsDefault(account3, true);
1415         defaultAccountId = Account.getDefaultAccountId(mMockContext);
1416         assertEquals(account3Id, defaultAccountId);
1417 
1418         // Now delete a non-default account and confirm no change
1419         Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, account1Id);
1420         mMockContext.getContentResolver().delete(uri, null, null);
1421 
1422         defaultAccountId = Account.getDefaultAccountId(mMockContext);
1423         assertEquals(account3Id, defaultAccountId);
1424 
1425         // Now confirm deleting the default account and it switches to another one
1426         uri = ContentUris.withAppendedId(Account.CONTENT_URI, account3Id);
1427         mMockContext.getContentResolver().delete(uri, null, null);
1428 
1429         defaultAccountId = Account.getDefaultAccountId(mMockContext);
1430         assertEquals(account2Id, defaultAccountId);
1431 
1432         // Now delete the final account and confirm there are no default accounts again
1433         uri = ContentUris.withAppendedId(Account.CONTENT_URI, account2Id);
1434         mMockContext.getContentResolver().delete(uri, null, null);
1435 
1436         defaultAccountId = Account.getDefaultAccountId(mMockContext);
1437         assertEquals(-1, defaultAccountId);
1438     }
1439 
updateIsDefault(Account account, boolean newState)1440     private void updateIsDefault(Account account, boolean newState) {
1441         account.setDefaultAccount(newState);
1442         ContentValues cv = new ContentValues();
1443         cv.put(AccountColumns.IS_DEFAULT, account.mIsDefault);
1444         account.update(mMockContext, cv);
1445     }
1446 
setupUnreadMessage(String name, long accountId, long mailboxId, boolean addBody, boolean saveIt, Context context)1447     public static Message setupUnreadMessage(String name, long accountId, long mailboxId,
1448             boolean addBody, boolean saveIt, Context context) {
1449         Message msg =
1450             ProviderTestUtils.setupMessage(name, accountId, mailboxId, addBody, false, context);
1451         msg.mFlagRead = false;
1452         if (saveIt) {
1453             msg.save(context);
1454         }
1455         return msg;
1456     }
1457 
testUnreadCountTriggers()1458     public void testUnreadCountTriggers() {
1459         // Start with one account and three mailboxes
1460         Account account = ProviderTestUtils.setupAccount("triggers", true, mMockContext);
1461         Mailbox boxA = ProviderTestUtils.setupMailbox("boxA", account.mId, true, mMockContext);
1462         Mailbox boxB = ProviderTestUtils.setupMailbox("boxB", account.mId, true, mMockContext);
1463         Mailbox boxC = ProviderTestUtils.setupMailbox("boxC", account.mId, true, mMockContext);
1464 
1465         // Make sure there are no unreads
1466         assertEquals(0, getUnreadCount(boxA.mId));
1467         assertEquals(0, getUnreadCount(boxB.mId));
1468         assertEquals(0, getUnreadCount(boxC.mId));
1469 
1470         // Create 4 unread messages (only 3 named) in boxA
1471         Message message1 = setupUnreadMessage("message1", account.mId, boxA.mId,
1472                 false, true, mMockContext);
1473         Message message2= setupUnreadMessage("message2", account.mId, boxA.mId,
1474                 false, true, mMockContext);
1475         Message message3 =  setupUnreadMessage("message3", account.mId, boxA.mId,
1476                 false, true, mMockContext);
1477         setupUnreadMessage("message4", account.mId, boxC.mId, false, true, mMockContext);
1478 
1479         // Make sure the unreads are where we expect them
1480         assertEquals(3, getUnreadCount(boxA.mId));
1481         assertEquals(0, getUnreadCount(boxB.mId));
1482         assertEquals(1, getUnreadCount(boxC.mId));
1483 
1484         // After deleting message 1, the count in box A should be decremented (to 2)
1485         ContentResolver cr = mMockContext.getContentResolver();
1486         Uri uri = ContentUris.withAppendedId(Message.CONTENT_URI, message1.mId);
1487         cr.delete(uri, null, null);
1488         assertEquals(2, getUnreadCount(boxA.mId));
1489         assertEquals(0, getUnreadCount(boxB.mId));
1490         assertEquals(1, getUnreadCount(boxC.mId));
1491 
1492         // Move message 2 to box B, leaving 1 in box A and 1 in box B
1493         message2.mMailboxKey = boxB.mId;
1494         ContentValues cv = new ContentValues();
1495         cv.put(MessageColumns.MAILBOX_KEY, boxB.mId);
1496         cr.update(ContentUris.withAppendedId(Message.CONTENT_URI, message2.mId), cv, null, null);
1497         assertEquals(1, getUnreadCount(boxA.mId));
1498         assertEquals(1, getUnreadCount(boxB.mId));
1499         assertEquals(1, getUnreadCount(boxC.mId));
1500 
1501         // Mark message 3 (from box A) read, leaving 0 in box A
1502         cv.clear();
1503         cv.put(MessageColumns.FLAG_READ, 1);
1504         cr.update(ContentUris.withAppendedId(Message.CONTENT_URI, message3.mId), cv, null, null);
1505         assertEquals(0, getUnreadCount(boxA.mId));
1506         assertEquals(1, getUnreadCount(boxB.mId));
1507         assertEquals(1, getUnreadCount(boxC.mId));
1508 
1509         // Move message 3 to box C; should be no change (it's read)
1510         message3.mMailboxKey = boxC.mId;
1511         cv.clear();
1512         cv.put(MessageColumns.MAILBOX_KEY, boxC.mId);
1513         cr.update(ContentUris.withAppendedId(Message.CONTENT_URI, message3.mId), cv, null, null);
1514         assertEquals(0, getUnreadCount(boxA.mId));
1515         assertEquals(1, getUnreadCount(boxB.mId));
1516         assertEquals(1, getUnreadCount(boxC.mId));
1517 
1518         // Mark message 3 unread; it's now in box C, so that box's count should go up to 3
1519         cv.clear();
1520         cv.put(MessageColumns.FLAG_READ, 0);
1521         cr.update(ContentUris.withAppendedId(Message.CONTENT_URI, message3.mId), cv, null, null);
1522         assertEquals(0, getUnreadCount(boxA.mId));
1523         assertEquals(1, getUnreadCount(boxB.mId));
1524         assertEquals(2, getUnreadCount(boxC.mId));
1525     }
1526 
1527     /**
1528      * Test for EmailProvider.createIndex().
1529      * Check that it returns exacly the same string as the one used previously for index creation.
1530      */
testCreateIndex()1531     public void testCreateIndex() {
1532         String oldStr = "create index message_" + MessageColumns.TIMESTAMP
1533             + " on " + Message.TABLE_NAME + " (" + MessageColumns.TIMESTAMP + ");";
1534         String newStr = EmailProvider.createIndex(Message.TABLE_NAME, MessageColumns.TIMESTAMP);
1535         assertEquals(newStr, oldStr);
1536     }
1537 
testIdAddToField()1538     public void testIdAddToField() {
1539         ContentResolver cr = mMockContext.getContentResolver();
1540         ContentValues cv = new ContentValues();
1541 
1542         // Try changing the newMessageCount of an account
1543         Account account = ProviderTestUtils.setupAccount("field-add", true, mMockContext);
1544         int startCount = account.mNewMessageCount;
1545         // "field" and "add" are the two required elements
1546         cv.put(EmailContent.FIELD_COLUMN_NAME, AccountColumns.NEW_MESSAGE_COUNT);
1547         cv.put(EmailContent.ADD_COLUMN_NAME, 17);
1548         cr.update(ContentUris.withAppendedId(Account.ADD_TO_FIELD_URI, account.mId),
1549                 cv, null, null);
1550         Account restoredAccount = Account.restoreAccountWithId(mMockContext, account.mId);
1551         assertEquals(17 + startCount, restoredAccount.mNewMessageCount);
1552         cv.put(EmailContent.ADD_COLUMN_NAME, -11);
1553         cr.update(ContentUris.withAppendedId(Account.ADD_TO_FIELD_URI, account.mId),
1554                 cv, null, null);
1555         restoredAccount = Account.restoreAccountWithId(mMockContext, account.mId);
1556         assertEquals(17 - 11 + startCount, restoredAccount.mNewMessageCount);
1557 
1558         // Now try with a mailbox
1559         Mailbox boxA = ProviderTestUtils.setupMailbox("boxA", account.mId, true, mMockContext);
1560         assertEquals(0, boxA.mUnreadCount);
1561         cv.put(EmailContent.FIELD_COLUMN_NAME, MailboxColumns.UNREAD_COUNT);
1562         cv.put(EmailContent.ADD_COLUMN_NAME, 11);
1563         cr.update(ContentUris.withAppendedId(Mailbox.ADD_TO_FIELD_URI, boxA.mId), cv, null, null);
1564         Mailbox restoredBoxA = Mailbox.restoreMailboxWithId(mMockContext, boxA.mId);
1565         assertEquals(11, restoredBoxA.mUnreadCount);
1566     }
1567 
testDatabaseCorruptionRecovery()1568     public void testDatabaseCorruptionRecovery() {
1569         final ContentResolver resolver = mMockContext.getContentResolver();
1570         final Context context = mMockContext;
1571 
1572         // Create account and two mailboxes
1573         Account acct = ProviderTestUtils.setupAccount("acct1", true, context);
1574         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", acct.mId, true, context);
1575 
1576         // Create 4 messages in box1 with bodies
1577         ProviderTestUtils.setupMessage("message1", acct.mId, box1.mId, true, true, context);
1578         ProviderTestUtils.setupMessage("message2", acct.mId, box1.mId, true, true, context);
1579         ProviderTestUtils.setupMessage("message3", acct.mId, box1.mId, true, true, context);
1580         ProviderTestUtils.setupMessage("message4", acct.mId, box1.mId, true, true, context);
1581 
1582         // Confirm there are four messages
1583         int count = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null);
1584         assertEquals(4, count);
1585         // Confirm there are four bodies
1586         count = EmailContent.count(mMockContext, Body.CONTENT_URI, null, null);
1587         assertEquals(4, count);
1588 
1589         // Find the EmailProvider.db file
1590         File dbFile = mMockContext.getDatabasePath(EmailProvider.DATABASE_NAME);
1591         // The EmailProvider.db database should exist (the provider creates it automatically)
1592         assertTrue(dbFile != null);
1593         assertTrue(dbFile.exists());
1594         // Delete it, and confirm it is gone
1595         assertTrue(dbFile.delete());
1596         assertFalse(dbFile.exists());
1597 
1598         // Find the EmailProviderBody.db file
1599         dbFile = mMockContext.getDatabasePath(EmailProvider.BODY_DATABASE_NAME);
1600         // The EmailProviderBody.db database should still exist
1601         assertTrue(dbFile != null);
1602         assertTrue(dbFile.exists());
1603 
1604         // URI to uncache the databases
1605         // This simulates the Provider starting up again (otherwise, it will still be pointing to
1606         // the already opened files)
1607         // Note that we only have access to the EmailProvider via the ContentResolver; therefore,
1608         // we cannot directly call into the provider and use a URI for this
1609         resolver.update(EmailProvider.INTEGRITY_CHECK_URI, null, null, null);
1610 
1611         // TODO We should check for the deletion of attachment files once this is implemented in
1612         // the provider
1613 
1614         // Explanation for what happens below...
1615         // The next time the database is created by the provider, it will notice that there's
1616         // already a EmailProviderBody.db file.  In this case, it will delete that database to
1617         // ensure that both are in sync (and empty)
1618 
1619         // Confirm there are no bodies
1620         count = EmailContent.count(mMockContext, Body.CONTENT_URI, null, null);
1621         assertEquals(0, count);
1622 
1623         // Confirm there are no messages
1624         count = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null);
1625         assertEquals(0, count);
1626     }
1627 
testBodyDatabaseCorruptionRecovery()1628     public void testBodyDatabaseCorruptionRecovery() {
1629         final ContentResolver resolver = mMockContext.getContentResolver();
1630         final Context context = mMockContext;
1631 
1632         // Create account and two mailboxes
1633         Account acct = ProviderTestUtils.setupAccount("acct1", true, context);
1634         Mailbox box1 = ProviderTestUtils.setupMailbox("box1", acct.mId, true, context);
1635 
1636         // Create 4 messages in box1 with bodies
1637         ProviderTestUtils.setupMessage("message1", acct.mId, box1.mId, true, true, context);
1638         ProviderTestUtils.setupMessage("message2", acct.mId, box1.mId, true, true, context);
1639         ProviderTestUtils.setupMessage("message3", acct.mId, box1.mId, true, true, context);
1640         ProviderTestUtils.setupMessage("message4", acct.mId, box1.mId, true, true, context);
1641 
1642         // Confirm there are four messages
1643         int count = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null);
1644         assertEquals(4, count);
1645         // Confirm there are four bodies
1646         count = EmailContent.count(mMockContext, Body.CONTENT_URI, null, null);
1647         assertEquals(4, count);
1648 
1649         // Find the EmailProviderBody.db file
1650         File dbFile = mMockContext.getDatabasePath(EmailProvider.BODY_DATABASE_NAME);
1651         // The EmailProviderBody.db database should exist (the provider creates it automatically)
1652         assertTrue(dbFile != null);
1653         assertTrue(dbFile.exists());
1654         // Delete it, and confirm it is gone
1655         assertTrue(dbFile.delete());
1656         assertFalse(dbFile.exists());
1657 
1658         // Find the EmailProvider.db file
1659         dbFile = mMockContext.getDatabasePath(EmailProvider.DATABASE_NAME);
1660         // The EmailProviderBody.db database should still exist
1661         assertTrue(dbFile != null);
1662         assertTrue(dbFile.exists());
1663 
1664         // URI to uncache the databases
1665         // This simulates the Provider starting up again (otherwise, it will still be pointing to
1666         // the already opened files)
1667         // Note that we only have access to the EmailProvider via the ContentResolver; therefore,
1668         // we cannot directly call into the provider and use a URI for this
1669         resolver.update(EmailProvider.INTEGRITY_CHECK_URI, null, null, null);
1670 
1671         // TODO We should check for the deletion of attachment files once this is implemented in
1672         // the provider
1673 
1674         // Explanation for what happens below...
1675         // The next time the body database is created by the provider, it will notice that there's
1676         // already a populated EmailProvider.db file.  In this case, it will delete that database to
1677         // ensure that both are in sync (and empty)
1678 
1679         // Confirm there are no messages
1680         count = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null);
1681         assertEquals(0, count);
1682 
1683         // Confirm there are no bodies
1684         count = EmailContent.count(mMockContext, Body.CONTENT_URI, null, null);
1685         assertEquals(0, count);
1686     }
1687 
testFindMailboxOfType()1688     public void testFindMailboxOfType() {
1689         final Context context = mMockContext;
1690 
1691         // Create two accounts and a variety of mailbox types
1692         Account acct1 = ProviderTestUtils.setupAccount("acct1", true, context);
1693         Mailbox acct1Inbox =
1694             ProviderTestUtils.setupMailbox("Inbox1", acct1.mId, true, context, Mailbox.TYPE_INBOX);
1695         Mailbox acct1Calendar
1696         = ProviderTestUtils.setupMailbox("Cal1", acct1.mId, true, context, Mailbox.TYPE_CALENDAR);
1697         Mailbox acct1Contacts =
1698             ProviderTestUtils.setupMailbox("Con1", acct1.mId, true, context, Mailbox.TYPE_CONTACTS);
1699         Account acct2 = ProviderTestUtils.setupAccount("acct1", true, context);
1700         Mailbox acct2Inbox =
1701             ProviderTestUtils.setupMailbox("Inbox2", acct2.mId, true, context, Mailbox.TYPE_INBOX);
1702         Mailbox acct2Calendar =
1703             ProviderTestUtils.setupMailbox("Cal2", acct2.mId, true, context, Mailbox.TYPE_CALENDAR);
1704         Mailbox acct2Contacts =
1705             ProviderTestUtils.setupMailbox("Con2", acct2.mId, true, context, Mailbox.TYPE_CONTACTS);
1706 
1707         // Check that we can find them by type
1708         assertEquals(acct1Inbox.mId,
1709                 Mailbox.findMailboxOfType(context, acct1.mId, Mailbox.TYPE_INBOX));
1710         assertEquals(acct2Inbox.mId,
1711                 Mailbox.findMailboxOfType(context, acct2.mId, Mailbox.TYPE_INBOX));
1712         assertEquals(acct1Calendar.mId,
1713                 Mailbox.findMailboxOfType(context, acct1.mId, Mailbox.TYPE_CALENDAR));
1714         assertEquals(acct2Calendar.mId,
1715                 Mailbox.findMailboxOfType(context, acct2.mId, Mailbox.TYPE_CALENDAR));
1716         assertEquals(acct1Contacts.mId,
1717                 Mailbox.findMailboxOfType(context, acct1.mId, Mailbox.TYPE_CONTACTS));
1718         assertEquals(acct2Contacts.mId,
1719                 Mailbox.findMailboxOfType(context, acct2.mId, Mailbox.TYPE_CONTACTS));
1720     }
1721 
testRestoreMailboxOfType()1722     public void testRestoreMailboxOfType() {
1723         final Context context = mMockContext;
1724 
1725         // Create two accounts and a variety of mailbox types
1726         Account acct1 = ProviderTestUtils.setupAccount("acct1", true, context);
1727         Mailbox acct1Inbox =
1728             ProviderTestUtils.setupMailbox("Inbox1", acct1.mId, true, context, Mailbox.TYPE_INBOX);
1729         Mailbox acct1Calendar
1730         = ProviderTestUtils.setupMailbox("Cal1", acct1.mId, true, context, Mailbox.TYPE_CALENDAR);
1731         Mailbox acct1Contacts =
1732             ProviderTestUtils.setupMailbox("Con1", acct1.mId, true, context, Mailbox.TYPE_CONTACTS);
1733         Account acct2 = ProviderTestUtils.setupAccount("acct1", true, context);
1734         Mailbox acct2Inbox =
1735             ProviderTestUtils.setupMailbox("Inbox2", acct2.mId, true, context, Mailbox.TYPE_INBOX);
1736         Mailbox acct2Calendar =
1737             ProviderTestUtils.setupMailbox("Cal2", acct2.mId, true, context, Mailbox.TYPE_CALENDAR);
1738         Mailbox acct2Contacts =
1739             ProviderTestUtils.setupMailbox("Con2", acct2.mId, true, context, Mailbox.TYPE_CONTACTS);
1740 
1741         // Check that we can find them by type
1742         ProviderTestUtils.assertMailboxEqual("testRestoreMailboxOfType", acct1Inbox,
1743                 Mailbox.restoreMailboxOfType(context, acct1.mId, Mailbox.TYPE_INBOX));
1744         ProviderTestUtils.assertMailboxEqual("testRestoreMailboxOfType", acct2Inbox,
1745                 Mailbox.restoreMailboxOfType(context, acct2.mId, Mailbox.TYPE_INBOX));
1746         ProviderTestUtils.assertMailboxEqual("testRestoreMailboxOfType", acct1Calendar,
1747                 Mailbox.restoreMailboxOfType(context, acct1.mId, Mailbox.TYPE_CALENDAR));
1748         ProviderTestUtils.assertMailboxEqual("testRestoreMailboxOfType", acct2Calendar,
1749                 Mailbox.restoreMailboxOfType(context, acct2.mId, Mailbox.TYPE_CALENDAR));
1750         ProviderTestUtils.assertMailboxEqual("testRestoreMailboxOfType", acct1Contacts,
1751                 Mailbox.restoreMailboxOfType(context, acct1.mId, Mailbox.TYPE_CONTACTS));
1752         ProviderTestUtils.assertMailboxEqual("testRestoreMailboxOfType", acct2Contacts,
1753                 Mailbox.restoreMailboxOfType(context, acct2.mId, Mailbox.TYPE_CONTACTS));
1754     }
1755 }
1756