1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 package com.android.email.provider; 18 19 import android.content.ContentResolver; 20 import android.content.ContentUris; 21 import android.content.ContentValues; 22 import android.content.Context; 23 import android.content.ContextWrapper; 24 import android.database.Cursor; 25 import android.database.sqlite.SQLiteDatabase; 26 import android.net.Uri; 27 import android.os.Bundle; 28 import android.os.Environment; 29 import android.os.Parcel; 30 import android.test.MoreAsserts; 31 import android.test.ProviderTestCase2; 32 import android.test.suitebuilder.annotation.LargeTest; 33 import android.test.suitebuilder.annotation.MediumTest; 34 import android.test.suitebuilder.annotation.SmallTest; 35 import android.test.suitebuilder.annotation.Suppress; 36 37 import com.android.email.provider.EmailProvider.EmailAttachmentService; 38 import com.android.emailcommon.provider.Account; 39 import com.android.emailcommon.provider.EmailContent; 40 import com.android.emailcommon.provider.EmailContent.AccountColumns; 41 import com.android.emailcommon.provider.EmailContent.Attachment; 42 import com.android.emailcommon.provider.EmailContent.AttachmentColumns; 43 import com.android.emailcommon.provider.EmailContent.Body; 44 import com.android.emailcommon.provider.EmailContent.BodyColumns; 45 import com.android.emailcommon.provider.EmailContent.MailboxColumns; 46 import com.android.emailcommon.provider.EmailContent.Message; 47 import com.android.emailcommon.provider.EmailContent.MessageColumns; 48 import com.android.emailcommon.provider.EmailContent.PolicyColumns; 49 import com.android.emailcommon.provider.HostAuth; 50 import com.android.emailcommon.provider.Mailbox; 51 import com.android.emailcommon.provider.Policy; 52 import com.android.emailcommon.utility.TextUtilities; 53 import com.android.emailcommon.utility.Utility; 54 55 import java.io.File; 56 import java.io.IOException; 57 import java.util.ArrayList; 58 59 /** 60 * Tests of the Email provider. 61 * 62 * You can run this entire test case with: 63 * runtest -c com.android.email.provider.ProviderTests email 64 * 65 * TODO: Add tests for cursor notification mechanism. (setNotificationUri and notifyChange) 66 * We can't test the entire notification mechanism with a mock content resolver, because which URI 67 * to notify when notifyChange() is called is in the actual content resolver. 68 * Implementing the same mechanism in a mock one is pointless. Instead what we could do is check 69 * what notification URI each cursor has, and with which URI is notified when 70 * inserting/updating/deleting. (The former require a new method from AbstractCursor) 71 */ 72 @Suppress 73 @LargeTest 74 public class ProviderTests extends ProviderTestCase2<EmailProvider> { 75 76 private EmailProvider mProvider; 77 private Context mMockContext; 78 79 public ProviderTests() { 80 super(EmailProvider.class, EmailContent.AUTHORITY); 81 } 82 83 // TODO: move this out to a common place. There are other places that have 84 // similar mocks. 85 /** 86 * Private context wrapper used to add back getPackageName() for these tests. 87 */ 88 private static class MockContext2 extends ContextWrapper { 89 90 private final Context mRealContext; 91 92 public MockContext2(Context mockContext, Context realContext) { 93 super(mockContext); 94 mRealContext = realContext; 95 } 96 97 @Override 98 public Context getApplicationContext() { 99 return this; 100 } 101 102 @Override 103 public String getPackageName() { 104 return mRealContext.getPackageName(); 105 } 106 107 @Override 108 public Object getSystemService(String name) { 109 return mRealContext.getSystemService(name); 110 } 111 } 112 113 private static final EmailAttachmentService MOCK_ATTACHMENT_SERVICE = 114 new EmailAttachmentService() { 115 @Override 116 public void attachmentChanged(Context context, long id, int flags) { 117 // Noop. Don't download attachments. 118 } 119 }; 120 121 @Override 122 public void setUp() throws Exception { 123 super.setUp(); 124 mMockContext = new MockContext2(getMockContext(), getContext()); 125 mProvider = getProvider(); 126 mProvider.injectAttachmentService(MOCK_ATTACHMENT_SERVICE); 127 // Invalidate all caches, since we reset the database for each test 128 ContentCache.invalidateAllCaches(); 129 } 130 131 @Override 132 public void tearDown() throws Exception { 133 super.tearDown(); 134 mProvider.injectAttachmentService(null); 135 } 136 137 /** 138 * TODO: Database upgrade tests 139 */ 140 141 // //////////////////////////////////////////////////////// 142 // //// Utility methods 143 // //////////////////////////////////////////////////////// 144 145 /** Sets the message count of all mailboxes to {@code -1}. */ 146 private void setMinusOneToMessageCounts() { 147 ContentValues values = new ContentValues(); 148 values.put(MailboxColumns.MESSAGE_COUNT, -1); 149 150 // EmailProvider.update() doesn't allow updating messageCount, so 151 // directly use the DB. 152 SQLiteDatabase db = getProvider().getDatabase(mMockContext); 153 db.update(Mailbox.TABLE_NAME, values, null, null); 154 } 155 156 /** Returns the number of messages in a mailbox. */ 157 private int getMessageCount(long mailboxId) { 158 return Utility.getFirstRowInt(mMockContext, 159 ContentUris.withAppendedId(Mailbox.CONTENT_URI, mailboxId), 160 new String[] {MailboxColumns.MESSAGE_COUNT}, 161 null, 162 null, 163 null, 164 0); 165 } 166 167 /** Creates a new message. */ 168 private static Message createMessage( 169 Context c, Mailbox b, boolean starred, boolean read, int flagLoaded) { 170 Message message = ProviderTestUtils.setupMessage("1", 171 b.mAccountKey, 172 b.mId, 173 true, 174 false, 175 c, 176 starred, 177 read); 178 message.mFlagLoaded = flagLoaded; 179 message.save(c); 180 return message; 181 } 182 183 // //////////////////////////////////////////////////////// 184 // //// The tests 185 // //////////////////////////////////////////////////////// 186 187 /** 188 * Test simple account save/retrieve 189 */ 190 @SmallTest 191 public void testAccountSave() { 192 Account account1 = ProviderTestUtils.setupAccount("account-save", true, mMockContext); 193 long account1Id = account1.mId; 194 195 Account account2 = Account.restoreAccountWithId(mMockContext, account1Id); 196 197 ProviderTestUtils.assertAccountEqual("testAccountSave", account1, account2); 198 } 199 200 /** 201 * Test simple account save/retrieve with predefined hostauth records 202 */ 203 @SmallTest 204 public void testAccountSaveHostAuth() { 205 Account account1 = ProviderTestUtils.setupAccount("account-hostauth", false, mMockContext); 206 // add hostauth data, which should be saved the first time 207 account1.mHostAuthRecv = 208 ProviderTestUtils.setupHostAuth("account-hostauth-recv", -1, false, mMockContext); 209 account1.mHostAuthSend = 210 ProviderTestUtils.setupHostAuth("account-hostauth-send", -1, false, mMockContext); 211 account1.save(mMockContext); 212 long account1Id = account1.mId; 213 214 // Confirm account reads back correctly 215 Account account1get = Account.restoreAccountWithId(mMockContext, account1Id); 216 ProviderTestUtils.assertAccountEqual("testAccountSave", account1, account1get); 217 218 // Confirm hostauth fields can be accessed & read back correctly 219 HostAuth hostAuth1get = 220 HostAuth.restoreHostAuthWithId(mMockContext, account1get.mHostAuthKeyRecv); 221 ProviderTestUtils.assertHostAuthEqual( 222 "testAccountSaveHostAuth-recv", account1.mHostAuthRecv, hostAuth1get); 223 HostAuth hostAuth2get = 224 HostAuth.restoreHostAuthWithId(mMockContext, account1get.mHostAuthKeySend); 225 ProviderTestUtils.assertHostAuthEqual( 226 "testAccountSaveHostAuth-send", account1.mHostAuthSend, hostAuth2get); 227 } 228 229 public void testAccountGetHostAuthSend() { 230 Account account = ProviderTestUtils.setupAccount("account-hostauth", false, mMockContext); 231 account.mHostAuthSend = 232 ProviderTestUtils.setupHostAuth("account-hostauth-send", -1, false, mMockContext); 233 account.save(mMockContext); 234 HostAuth authGet; 235 HostAuth authTest; 236 237 authTest = account.mHostAuthSend; 238 assertNotNull(authTest); 239 assertTrue(account.mHostAuthKeySend != 0); 240 241 // HostAuth is not changed 242 authGet = account.getOrCreateHostAuthSend(mMockContext); 243 assertTrue(authGet == authTest); // return the same object 244 245 // New HostAuth; based upon mHostAuthKeyRecv 246 authTest = HostAuth.restoreHostAuthWithId(mMockContext, account.mHostAuthKeySend); 247 account.mHostAuthSend = null; 248 authGet = account.getOrCreateHostAuthSend(mMockContext); 249 assertNotNull(authGet); 250 assertNotNull(account.mHostAuthSend); 251 ProviderTestUtils.assertHostAuthEqual("testAccountGetHostAuthSend-1", authTest, authGet); 252 253 // New HostAuth; completely empty 254 authTest = new HostAuth(); 255 account.mHostAuthSend = null; 256 account.mHostAuthKeySend = 0; 257 authGet = account.getOrCreateHostAuthSend(mMockContext); 258 assertNotNull(authGet); 259 assertNotNull(account.mHostAuthSend); 260 ProviderTestUtils.assertHostAuthEqual("testAccountGetHostAuthSendv-2", authTest, authGet); 261 } 262 263 public void testAccountGetHostAuthRecv() { 264 Account account = ProviderTestUtils.setupAccount("account-hostauth", false, mMockContext); 265 account.mHostAuthRecv = 266 ProviderTestUtils.setupHostAuth("account-hostauth-recv", -1, false, mMockContext); 267 account.save(mMockContext); 268 HostAuth authGet; 269 HostAuth authTest; 270 271 authTest = account.mHostAuthRecv; 272 assertNotNull(authTest); 273 assertTrue(account.mHostAuthKeyRecv != 0); 274 275 // HostAuth is not changed 276 authGet = account.getOrCreateHostAuthRecv(mMockContext); 277 assertTrue(authGet == authTest); // return the same object 278 279 // New HostAuth; based upon mHostAuthKeyRecv 280 authTest = HostAuth.restoreHostAuthWithId(mMockContext, account.mHostAuthKeyRecv); 281 account.mHostAuthRecv = null; 282 authGet = account.getOrCreateHostAuthRecv(mMockContext); 283 assertNotNull(authGet); 284 assertNotNull(account.mHostAuthRecv); 285 ProviderTestUtils.assertHostAuthEqual("testAccountGetHostAuthRecv-1", authTest, authGet); 286 287 // New HostAuth; completely empty 288 authTest = new HostAuth(); 289 account.mHostAuthRecv = null; 290 account.mHostAuthKeyRecv = 0; 291 authGet = account.getOrCreateHostAuthRecv(mMockContext); 292 assertNotNull(authGet); 293 assertNotNull(account.mHostAuthRecv); 294 ProviderTestUtils.assertHostAuthEqual("testAccountGetHostAuthRecv-2", authTest, authGet); 295 } 296 297 /** 298 * Simple test of account parceling. The rather torturous path is to ensure that the 299 * account is really flattened all the way down to a parcel and back. 300 */ 301 public void testAccountParcel() { 302 Account account1 = ProviderTestUtils.setupAccount("parcel", false, mMockContext); 303 Bundle b = new Bundle(); 304 b.putParcelable("account", account1); 305 Parcel p = Parcel.obtain(); 306 b.writeToParcel(p, 0); 307 p.setDataPosition(0); // rewind it for reading 308 Bundle b2 = new Bundle(Account.class.getClassLoader()); 309 b2.readFromParcel(p); 310 Account account2 = (Account) b2.getParcelable("account"); 311 p.recycle(); 312 313 ProviderTestUtils.assertAccountEqual("testAccountParcel", account1, account2); 314 } 315 316 private static Uri getEclairStyleShortcutUri(Account account) { 317 // We used _id instead of UUID only on Eclair(2.0-2.1). 318 return Account.CONTENT_URI.buildUpon().appendEncodedPath("" + account.mId).build(); 319 } 320 321 public void testGetProtocol() { 322 Account account1 = ProviderTestUtils.setupAccount("account-hostauth", false, mMockContext); 323 // add hostauth data, with protocol 324 account1.mHostAuthRecv = ProviderTestUtils.setupHostAuth( 325 "eas", "account-hostauth-recv", false, mMockContext); 326 // Note that getProtocol uses the receive host auth, so the protocol 327 // here shouldn't matter 328 // to the test result 329 account1.mHostAuthSend = ProviderTestUtils.setupHostAuth( 330 "foo", "account-hostauth-send", false, mMockContext); 331 account1.save(mMockContext); 332 assertEquals("eas", Account.getProtocol(mMockContext, account1.mId)); 333 assertEquals("eas", account1.getProtocol(mMockContext)); 334 Account account2 = 335 ProviderTestUtils.setupAccount("account-nohostauth", false, mMockContext); 336 account2.save(mMockContext); 337 // Make sure that we return null when there's no host auth 338 assertNull(Account.getProtocol(mMockContext, account2.mId)); 339 assertNull(account2.getProtocol(mMockContext)); 340 // And when there's no account 341 assertNull(Account.getProtocol(mMockContext, 0)); 342 } 343 344 public void testAccountIsValidId() { 345 final Account account1 = ProviderTestUtils.setupAccount("account-1", true, mMockContext); 346 final Account account2 = ProviderTestUtils.setupAccount("account-2", true, mMockContext); 347 348 assertTrue(Account.isValidId(mMockContext, account1.mId)); 349 assertTrue(Account.isValidId(mMockContext, account2.mId)); 350 351 assertFalse(Account.isValidId(mMockContext, 1234567)); // Some random ID 352 assertFalse(Account.isValidId(mMockContext, -1)); 353 assertFalse(Account.isValidId(mMockContext, -500)); 354 } 355 356 private final static String[] MAILBOX_UNREAD_COUNT_PROJECTION = 357 new String[] {MailboxColumns.UNREAD_COUNT}; 358 private final static int MAILBOX_UNREAD_COUNT_COLMUN = 0; 359 360 /** 361 * Get the value of the unread count in the mailbox of the account. 362 * This can be different from the actual number of unread messages in that mailbox. 363 */ 364 private int getUnreadCount(long mailboxId) { 365 String text = null; 366 Cursor c = null; 367 try { 368 c = mMockContext.getContentResolver().query(Mailbox.CONTENT_URI, 369 MAILBOX_UNREAD_COUNT_PROJECTION, EmailContent.RECORD_ID + "=?", 370 new String[] {String.valueOf(mailboxId)}, null); 371 c.moveToFirst(); 372 text = c.getString(MAILBOX_UNREAD_COUNT_COLMUN); 373 } finally { 374 c.close(); 375 } 376 return Integer.valueOf(text); 377 } 378 379 private static String[] expectedAttachmentNames = 380 new String[] {"attachment1.doc", "attachment2.xls", "attachment3"}; 381 // The lengths need to be kept in ascending order 382 private static long[] expectedAttachmentSizes = new long[] {31415L, 97701L, 151213L}; 383 384 /* 385 * Returns null if the message has no body. 386 */ 387 private Body loadBodyForMessageId(long messageId) { 388 Cursor c = null; 389 try { 390 c = mMockContext.getContentResolver().query(EmailContent.Body.CONTENT_URI, 391 EmailContent.Body.CONTENT_PROJECTION, BodyColumns.MESSAGE_KEY + "=?", 392 new String[] {String.valueOf(messageId)}, null); 393 int numBodies = c.getCount(); 394 assertTrue("at most one body", numBodies < 2); 395 return c.moveToFirst() ? EmailContent.getContent(mMockContext, c, Body.class) : null; 396 } finally { 397 c.close(); 398 } 399 } 400 401 /** 402 * Test simple message save/retrieve 403 * 404 * TODO: serverId vs. serverIntId 405 */ 406 @MediumTest 407 public void testMessageSave() { 408 Account account1 = ProviderTestUtils.setupAccount("message-save", true, mMockContext); 409 long account1Id = account1.mId; 410 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 411 long box1Id = box1.mId; 412 413 // Test a simple message (saved with no body) 414 Message message1 = ProviderTestUtils.setupMessage("message1", 415 account1Id, 416 box1Id, 417 false, 418 true, 419 mMockContext); 420 long message1Id = message1.mId; 421 Message message1get = EmailContent.Message.restoreMessageWithId(mMockContext, message1Id); 422 ProviderTestUtils.assertMessageEqual("testMessageSave", message1, message1get); 423 424 // Test a message saved with a body 425 // Note that it will read back w/o the text & html so we must extract 426 // those 427 Message message2 = ProviderTestUtils.setupMessage("message1", 428 account1Id, 429 box1Id, 430 true, 431 true, 432 mMockContext); 433 long message2Id = message2.mId; 434 String text2 = message2.mText; 435 String html2 = message2.mHtml; 436 long sourceKey2 = message2.mSourceKey; 437 message2.mText = null; 438 message2.mHtml = null; 439 message2.mSourceKey = 0; 440 Message message2get = EmailContent.Message.restoreMessageWithId(mMockContext, message2Id); 441 ProviderTestUtils.assertMessageEqual("testMessageSave", message2, message2get); 442 443 // Now see if there's a body saved with the right stuff 444 Body body2 = loadBodyForMessageId(message2Id); 445 assertEquals("body text", text2, body2.mTextContent); 446 assertEquals("body html", html2, body2.mHtmlContent); 447 assertEquals("source key", sourceKey2, body2.mSourceKey); 448 } 449 450 @MediumTest 451 public void testMessageWithAttachment() { 452 Account account1 = ProviderTestUtils.setupAccount("message-save", true, mMockContext); 453 long account1Id = account1.mId; 454 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 455 long box1Id = box1.mId; 456 457 // Message with attachments and body 458 Message message3 = ProviderTestUtils.setupMessage("message3", 459 account1Id, 460 box1Id, 461 true, 462 false, 463 mMockContext); 464 ArrayList<Attachment> atts = new ArrayList<Attachment>(); 465 for (int i = 0; i < 3; i++) { 466 atts.add(ProviderTestUtils.setupAttachment( 467 -1, expectedAttachmentNames[i], expectedAttachmentSizes[i], false, 468 mMockContext)); 469 } 470 message3.mAttachments = atts; 471 message3.save(mMockContext); 472 long message3Id = message3.mId; 473 474 // Now check the attachments; there should be three and they should 475 // match name and size 476 Cursor c = null; 477 try { 478 // Note that there is NO guarantee of the order of returned records 479 // in the general case, 480 // so we specifically ask for ordering by size. The 481 // expectedAttachmentSizes array must 482 // be kept sorted by size (ascending) for this test to work properly 483 c = mMockContext.getContentResolver().query(Attachment.CONTENT_URI, 484 Attachment.CONTENT_PROJECTION, AttachmentColumns.MESSAGE_KEY + "=?", 485 new String[] {String.valueOf(message3Id)}, AttachmentColumns.SIZE); 486 int numAtts = c.getCount(); 487 assertEquals(3, numAtts); 488 int i = 0; 489 while (c.moveToNext()) { 490 Attachment actual = EmailContent.getContent(mMockContext, c, Attachment.class); 491 ProviderTestUtils.assertAttachmentEqual("save-message3", atts.get(i), actual); 492 i++; 493 } 494 } finally { 495 c.close(); 496 } 497 } 498 499 500 @MediumTest 501 public void testMessageSaveWithJustAttachments() { 502 Account account1 = ProviderTestUtils.setupAccount("message-save", true, mMockContext); 503 long account1Id = account1.mId; 504 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 505 long box1Id = box1.mId; 506 Cursor c = null; 507 508 // Message with attachments but no body 509 Message message4 = ProviderTestUtils.setupMessage("message4", 510 account1Id, 511 box1Id, 512 false, 513 false, 514 mMockContext); 515 ArrayList<Attachment> atts = new ArrayList<Attachment>(); 516 for (int i = 0; i < 3; i++) { 517 atts.add(ProviderTestUtils.setupAttachment( 518 -1, expectedAttachmentNames[i], expectedAttachmentSizes[i], false, 519 mMockContext)); 520 } 521 message4.mAttachments = atts; 522 message4.save(mMockContext); 523 long message4Id = message4.mId; 524 525 // Now check the attachments; there should be three and they should 526 // match name and size 527 c = null; 528 529 try { 530 // Note that there is NO guarantee of the order of returned records 531 // in the general case, 532 // so we specifically ask for ordering by size. The 533 // expectedAttachmentSizes array must 534 // be kept sorted by size (ascending) for this test to work properly 535 c = mMockContext.getContentResolver().query(Attachment.CONTENT_URI, 536 Attachment.CONTENT_PROJECTION, AttachmentColumns.MESSAGE_KEY + "=?", 537 new String[] {String.valueOf(message4Id)}, AttachmentColumns.SIZE); 538 int numAtts = c.getCount(); 539 assertEquals(3, numAtts); 540 int i = 0; 541 while (c.moveToNext()) { 542 Attachment actual = EmailContent.getContent(mMockContext, c, Attachment.class); 543 ProviderTestUtils.assertAttachmentEqual("save-message4", atts.get(i), actual); 544 i++; 545 } 546 } finally { 547 c.close(); 548 } 549 550 // test EmailContent.restoreAttachmentsWitdMessageId() 551 Attachment[] attachments = 552 Attachment.restoreAttachmentsWithMessageId(mMockContext, message4Id); 553 int size = attachments.length; 554 assertEquals(3, size); 555 for (int i = 0; i < size; ++i) { 556 ProviderTestUtils.assertAttachmentEqual("save-message4", atts.get(i), attachments[i]); 557 } 558 } 559 560 /** 561 * Test that saving a message creates the proper snippet for that message 562 */ 563 public void testMessageSaveAddsSnippet() { 564 Account account = ProviderTestUtils.setupAccount("message-snippet", true, mMockContext); 565 Mailbox box = ProviderTestUtils.setupMailbox("box1", account.mId, true, mMockContext); 566 567 // Create a message without a body, unsaved 568 Message message = ProviderTestUtils.setupMessage("message", 569 account.mId, 570 box.mId, 571 false, 572 false, 573 mMockContext); 574 message.mText = "This is some text"; 575 message.mHtml = "<html>This is some text</html>"; 576 message.save(mMockContext); 577 Message restoredMessage = Message.restoreMessageWithId(mMockContext, message.mId); 578 // We should have the plain text as the snippet 579 assertEquals( 580 restoredMessage.mSnippet, TextUtilities.makeSnippetFromPlainText(message.mText)); 581 582 // Start again 583 message = ProviderTestUtils.setupMessage("message", 584 account.mId, 585 box.mId, 586 false, 587 false, 588 mMockContext); 589 message.mText = null; 590 message.mHtml = "<html>This is some text</html>"; 591 message.save(mMockContext); 592 restoredMessage = Message.restoreMessageWithId(mMockContext, message.mId); 593 // We should have the plain text as the snippet 594 assertEquals( 595 restoredMessage.mSnippet, TextUtilities.makeSnippetFromHtmlText(message.mHtml)); 596 } 597 598 /** 599 * TODO: update account 600 */ 601 602 /** 603 * TODO: update mailbox 604 */ 605 606 /** 607 * TODO: update message 608 */ 609 610 /** 611 * Test delete account 612 * TODO: hostauth 613 */ 614 public void testAccountDelete() { 615 Account account1 = ProviderTestUtils.setupAccount("account-delete-1", true, mMockContext); 616 long account1Id = account1.mId; 617 Account account2 = ProviderTestUtils.setupAccount("account-delete-2", true, mMockContext); 618 long account2Id = account2.mId; 619 620 // make sure there are two accounts 621 int numBoxes = EmailContent.count(mMockContext, Account.CONTENT_URI, null, null); 622 assertEquals(2, numBoxes); 623 624 // now delete one of them 625 Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, account1Id); 626 mMockContext.getContentResolver().delete(uri, null, null); 627 628 // make sure there's only one account now 629 numBoxes = EmailContent.count(mMockContext, Account.CONTENT_URI, null, null); 630 assertEquals(1, numBoxes); 631 632 // now delete the other one 633 uri = ContentUris.withAppendedId(Account.CONTENT_URI, account2Id); 634 mMockContext.getContentResolver().delete(uri, null, null); 635 636 // make sure there are no accounts now 637 numBoxes = EmailContent.count(mMockContext, Account.CONTENT_URI, null, null); 638 assertEquals(0, numBoxes); 639 } 640 641 /** 642 * Test for Body.lookupBodyIdWithMessageId() 643 * Verifies that: 644 * - for a message without body, -1 is returned. 645 * - for a mesage with body, the id matches the one from loadBodyForMessageId. 646 */ 647 public void testLookupBodyIdWithMessageId() { 648 final ContentResolver resolver = mMockContext.getContentResolver(); 649 Account account1 = ProviderTestUtils.setupAccount("orphaned body", true, mMockContext); 650 long account1Id = account1.mId; 651 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 652 long box1Id = box1.mId; 653 654 // 1. create message with no body, check that returned bodyId is -1 655 Message message1 = ProviderTestUtils.setupMessage("message1", 656 account1Id, 657 box1Id, 658 false, 659 true, 660 mMockContext); 661 long message1Id = message1.mId; 662 long bodyId1 = Body.lookupBodyIdWithMessageId(mMockContext, message1Id); 663 assertEquals(bodyId1, -1); 664 665 // 2. create message with body, check that returned bodyId is correct 666 Message message2 = ProviderTestUtils.setupMessage("message1", 667 account1Id, 668 box1Id, 669 true, 670 true, 671 mMockContext); 672 long message2Id = message2.mId; 673 long bodyId2 = Body.lookupBodyIdWithMessageId(mMockContext, message2Id); 674 Body body = loadBodyForMessageId(message2Id); 675 assertNotNull(body); 676 assertEquals(body.mId, bodyId2); 677 } 678 679 /** 680 * Test for Body.updateBodyWithMessageId(). 681 * 1. - create message without body, 682 * - update its body (set TEXT_CONTENT) 683 * - check correct updated body is read back 684 * 685 * 2. - create message with body, 686 * - update body (set TEXT_CONTENT) 687 * - check correct updated body is read back 688 */ 689 public void testUpdateBodyWithMessageId() { 690 Account account1 = ProviderTestUtils.setupAccount("orphaned body", true, mMockContext); 691 long account1Id = account1.mId; 692 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 693 long box1Id = box1.mId; 694 695 final String textContent = "foobar some odd text"; 696 final String htmlContent = "and some html"; 697 698 ContentValues values = new ContentValues(); 699 values.put(BodyColumns.TEXT_CONTENT, textContent); 700 values.put(BodyColumns.HTML_CONTENT, htmlContent); 701 values.put(BodyColumns.SOURCE_MESSAGE_KEY, 17); 702 703 // 1 704 Message message1 = ProviderTestUtils.setupMessage("message1", 705 account1Id, 706 box1Id, 707 false, 708 true, 709 mMockContext); 710 long message1Id = message1.mId; 711 Body body1 = loadBodyForMessageId(message1Id); 712 assertNull(body1); 713 Body.updateBodyWithMessageId(mMockContext, message1Id, values); 714 body1 = loadBodyForMessageId(message1Id); 715 assertNotNull(body1); 716 assertEquals(body1.mTextContent, textContent); 717 assertEquals(body1.mHtmlContent, htmlContent); 718 assertEquals(body1.mSourceKey, 17); 719 720 // 2 721 Message message2 = ProviderTestUtils.setupMessage("message1", 722 account1Id, 723 box1Id, 724 true, 725 true, 726 mMockContext); 727 long message2Id = message2.mId; 728 Body body2 = loadBodyForMessageId(message2Id); 729 assertNotNull(body2); 730 assertTrue(!body2.mTextContent.equals(textContent)); 731 Body.updateBodyWithMessageId(mMockContext, message2Id, values); 732 body2 = loadBodyForMessageId(message1Id); 733 assertNotNull(body2); 734 assertEquals(body2.mTextContent, textContent); 735 assertEquals(body2.mHtmlContent, htmlContent); 736 assertEquals(body2.mSourceKey, 17); 737 } 738 739 /** 740 * Test body retrieve methods 741 */ 742 public void testBodyRetrieve() { 743 // No account needed 744 // No mailbox needed 745 Message message1 = 746 ProviderTestUtils.setupMessage("bodyretrieve", 1, 1, true, true, mMockContext); 747 long messageId = message1.mId; 748 749 assertEquals(message1.mText, Body.restoreBodyTextWithMessageId(mMockContext, messageId)); 750 assertEquals(message1.mHtml, Body.restoreBodyHtmlWithMessageId(mMockContext, messageId)); 751 assertEquals(message1.mSourceKey, Body.restoreBodySourceKey(mMockContext, messageId)); 752 } 753 754 /** 755 * Test delete body. 756 * 1. create message without body (message id 1) 757 * 2. create message with body (message id 2. The body has _id 1 and messageKey 2). 758 * 3. delete first message. 759 * 4. verify that body for message 2 has not been deleted. 760 * 5. delete message 2, verify body is deleted. 761 */ 762 public void testDeleteBody() { 763 final ContentResolver resolver = mMockContext.getContentResolver(); 764 765 // Create account and mailboxes 766 Account account1 = ProviderTestUtils.setupAccount("orphaned body", true, mMockContext); 767 long account1Id = account1.mId; 768 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 769 long box1Id = box1.mId; 770 771 // 1. create message without body 772 Message message1 = ProviderTestUtils.setupMessage("message1", 773 account1Id, 774 box1Id, 775 false, 776 true, 777 mMockContext); 778 long message1Id = message1.mId; 779 780 // 2. create message with body 781 Message message2 = ProviderTestUtils.setupMessage("message1", 782 account1Id, 783 box1Id, 784 true, 785 true, 786 mMockContext); 787 long message2Id = message2.mId; 788 // verify body is there 789 assertNotNull(loadBodyForMessageId(message2Id)); 790 791 // 3. delete first message 792 resolver.delete(ContentUris.withAppendedId(Message.CONTENT_URI, message1Id), null, null); 793 794 // 4. verify body for second message wasn't deleted 795 assertNotNull(loadBodyForMessageId(message2Id)); 796 797 // 5. delete second message, check its body is deleted 798 resolver.delete(ContentUris.withAppendedId(Message.CONTENT_URI, message2Id), null, null); 799 assertNull(loadBodyForMessageId(message2Id)); 800 } 801 802 /** 803 * Test delete orphan bodies. 804 * 1. create message without body (message id 1) 805 * 2. create message with body (message id 2. Body has _id 1 and messageKey 2). 806 * 3. delete first message. 807 * 4. delete some other mailbox -- this triggers delete orphan bodies. 808 * 5. verify that body for message 2 has not been deleted. 809 */ 810 public void testDeleteOrphanBodies() { 811 final ContentResolver resolver = mMockContext.getContentResolver(); 812 813 // Create account and two mailboxes 814 Account account1 = ProviderTestUtils.setupAccount("orphaned body", true, mMockContext); 815 long account1Id = account1.mId; 816 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 817 long box1Id = box1.mId; 818 Mailbox box2 = ProviderTestUtils.setupMailbox("box2", account1Id, true, mMockContext); 819 long box2Id = box2.mId; 820 821 // 1. create message without body 822 Message message1 = ProviderTestUtils.setupMessage("message1", 823 account1Id, 824 box1Id, 825 false, 826 true, 827 mMockContext); 828 long message1Id = message1.mId; 829 830 // 2. create message with body 831 Message message2 = ProviderTestUtils.setupMessage("message1", 832 account1Id, 833 box1Id, 834 true, 835 true, 836 mMockContext); 837 long message2Id = message2.mId; 838 // verify body is there 839 assertNotNull(loadBodyForMessageId(message2Id)); 840 841 // 3. delete first message 842 resolver.delete(ContentUris.withAppendedId(Message.CONTENT_URI, message1Id), null, null); 843 844 // 4. delete some mailbox (because it triggers "delete orphan bodies") 845 resolver.delete(ContentUris.withAppendedId(Mailbox.CONTENT_URI, box2Id), null, null); 846 847 // 5. verify body for second message wasn't deleted during 848 // "delete orphan bodies" 849 assertNotNull(loadBodyForMessageId(message2Id)); 850 } 851 852 /** 853 * Note that we can't use EmailContent.count() here because it uses a projection including 854 * count(*), and count(*) is incompatible with a LIMIT (i.e. the limit would be applied to the 855 * single column returned with count(*), rather than to the query itself) 856 */ 857 private int count(Context context, Uri uri, String selection, String[] selectionArgs) { 858 Cursor c = context.getContentResolver() 859 .query(uri, EmailContent.ID_PROJECTION, selection, selectionArgs, null); 860 try { 861 return c.getCount(); 862 } finally { 863 c.close(); 864 } 865 } 866 867 public void testMessageQueryWithLimit() { 868 final Context context = mMockContext; 869 870 // Create account and two mailboxes 871 Account acct = ProviderTestUtils.setupAccount("orphaned body", true, context); 872 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", acct.mId, true, context); 873 Mailbox box2 = ProviderTestUtils.setupMailbox("box2", acct.mId, true, context); 874 875 // Create 4 messages in box1 876 ProviderTestUtils.setupMessage("message1", acct.mId, box1.mId, false, true, context); 877 ProviderTestUtils.setupMessage("message2", acct.mId, box1.mId, false, true, context); 878 ProviderTestUtils.setupMessage("message3", acct.mId, box1.mId, false, true, context); 879 ProviderTestUtils.setupMessage("message4", acct.mId, box1.mId, false, true, context); 880 881 // Create 4 messages in box2 882 ProviderTestUtils.setupMessage("message1", acct.mId, box2.mId, false, true, context); 883 ProviderTestUtils.setupMessage("message2", acct.mId, box2.mId, false, true, context); 884 ProviderTestUtils.setupMessage("message3", acct.mId, box2.mId, false, true, context); 885 ProviderTestUtils.setupMessage("message4", acct.mId, box2.mId, false, true, context); 886 887 // Check normal case, special case (limit 1), and arbitrary limits 888 assertEquals(8, count(mMockContext, Message.CONTENT_URI, null, null)); 889 assertEquals(1, 890 count(mMockContext, EmailContent.uriWithLimit(Message.CONTENT_URI, 1), null, null)); 891 assertEquals(3, 892 count(mMockContext, EmailContent.uriWithLimit(Message.CONTENT_URI, 3), null, null)); 893 assertEquals(8, count(mMockContext, EmailContent.uriWithLimit(Message.CONTENT_URI, 100), 894 null, null)); 895 896 // Check that it works with selection/selection args 897 String[] args = new String[] {Long.toString(box1.mId)}; 898 assertEquals(4, 899 count(mMockContext, Message.CONTENT_URI, MessageColumns.MAILBOX_KEY + "=?", args)); 900 assertEquals(1, count(mMockContext, EmailContent.uriWithLimit(Message.CONTENT_URI, 1), 901 MessageColumns.MAILBOX_KEY + "=?", args)); 902 } 903 904 /** 905 * Test delete orphan messages 906 * 1. create message without body (message id 1) 907 * 2. create message with body (message id 2. Body has _id 1 and messageKey 2). 908 * 3. delete first message. 909 * 4. delete some other mailbox -- this triggers delete orphan bodies. 910 * 5. verify that body for message 2 has not been deleted. 911 */ 912 public void testDeleteOrphanMessages() { 913 final ContentResolver resolver = mMockContext.getContentResolver(); 914 final Context context = mMockContext; 915 916 // Create account and two mailboxes 917 Account acct = ProviderTestUtils.setupAccount("orphaned body", true, context); 918 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", acct.mId, true, context); 919 Mailbox box2 = ProviderTestUtils.setupMailbox("box2", acct.mId, true, context); 920 921 // Create 4 messages in box1 922 Message msg1_1 = ProviderTestUtils.setupMessage("message1", 923 acct.mId, 924 box1.mId, 925 false, 926 true, 927 context); 928 Message msg1_2 = ProviderTestUtils.setupMessage("message2", 929 acct.mId, 930 box1.mId, 931 false, 932 true, 933 context); 934 Message msg1_3 = ProviderTestUtils.setupMessage("message3", 935 acct.mId, 936 box1.mId, 937 false, 938 true, 939 context); 940 Message msg1_4 = ProviderTestUtils.setupMessage("message4", 941 acct.mId, 942 box1.mId, 943 false, 944 true, 945 context); 946 947 // Create 4 messages in box2 948 Message msg2_1 = ProviderTestUtils.setupMessage("message1", 949 acct.mId, 950 box2.mId, 951 false, 952 true, 953 context); 954 Message msg2_2 = ProviderTestUtils.setupMessage("message2", 955 acct.mId, 956 box2.mId, 957 false, 958 true, 959 context); 960 Message msg2_3 = ProviderTestUtils.setupMessage("message3", 961 acct.mId, 962 box2.mId, 963 false, 964 true, 965 context); 966 Message msg2_4 = ProviderTestUtils.setupMessage("message4", 967 acct.mId, 968 box2.mId, 969 false, 970 true, 971 context); 972 973 // Delete 2 from each mailbox 974 resolver.delete( 975 ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg1_1.mId), null, null); 976 resolver.delete( 977 ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg1_2.mId), null, null); 978 resolver.delete( 979 ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg2_1.mId), null, null); 980 resolver.delete( 981 ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg2_2.mId), null, null); 982 983 // There should be 4 items in the deleted item table 984 assertEquals(4, EmailContent.count(context, Message.DELETED_CONTENT_URI, null, null)); 985 986 // Update 2 from each mailbox 987 ContentValues v = new ContentValues(); 988 v.put(MessageColumns.DISPLAY_NAME, "--updated--"); 989 resolver.update( 990 ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg1_3.mId), v, null, null); 991 resolver.update( 992 ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg1_4.mId), v, null, null); 993 resolver.update( 994 ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg2_3.mId), v, null, null); 995 resolver.update( 996 ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, msg2_4.mId), v, null, null); 997 998 // There should be 4 items in the updated item table 999 assertEquals(4, EmailContent.count(context, Message.UPDATED_CONTENT_URI, null, null)); 1000 1001 // Manually add 2 messages from a "deleted" mailbox to deleted and 1002 // updated tables 1003 // Use a value > 2 for the deleted box id 1004 long delBoxId = 10; 1005 // Create 4 messages in the "deleted" mailbox 1006 Message msgX_A = ProviderTestUtils.setupMessage("messageA", 1007 acct.mId, 1008 delBoxId, 1009 false, 1010 false, 1011 context); 1012 Message msgX_B = ProviderTestUtils.setupMessage("messageB", 1013 acct.mId, 1014 delBoxId, 1015 false, 1016 false, 1017 context); 1018 Message msgX_C = ProviderTestUtils.setupMessage("messageC", 1019 acct.mId, 1020 delBoxId, 1021 false, 1022 false, 1023 context); 1024 Message msgX_D = ProviderTestUtils.setupMessage("messageD", 1025 acct.mId, 1026 delBoxId, 1027 false, 1028 false, 1029 context); 1030 1031 ContentValues cv; 1032 // We have to assign id's manually because there are no autoincrement 1033 // id's for these tables 1034 // Start with an id that won't exist, since id's in these tables must be 1035 // unique 1036 long msgId = 10; 1037 // It's illegal to manually insert these, so we need to catch the 1038 // exception 1039 // NOTE: The insert succeeds, and then throws the exception 1040 try { 1041 cv = msgX_A.toContentValues(); 1042 cv.put(EmailContent.RECORD_ID, msgId++); 1043 resolver.insert(Message.DELETED_CONTENT_URI, cv); 1044 } catch (IllegalArgumentException e) { 1045 } 1046 try { 1047 cv = msgX_B.toContentValues(); 1048 cv.put(EmailContent.RECORD_ID, msgId++); 1049 resolver.insert(Message.DELETED_CONTENT_URI, cv); 1050 } catch (IllegalArgumentException e) { 1051 } 1052 try { 1053 cv = msgX_C.toContentValues(); 1054 cv.put(EmailContent.RECORD_ID, msgId++); 1055 resolver.insert(Message.UPDATED_CONTENT_URI, cv); 1056 } catch (IllegalArgumentException e) { 1057 } 1058 try { 1059 cv = msgX_D.toContentValues(); 1060 cv.put(EmailContent.RECORD_ID, msgId++); 1061 resolver.insert(Message.UPDATED_CONTENT_URI, cv); 1062 } catch (IllegalArgumentException e) { 1063 } 1064 1065 // There should be 6 items in the deleted and updated tables 1066 assertEquals(6, EmailContent.count(context, Message.UPDATED_CONTENT_URI, null, null)); 1067 assertEquals(6, EmailContent.count(context, Message.DELETED_CONTENT_URI, null, null)); 1068 1069 // Delete the orphans 1070 EmailProvider.deleteMessageOrphans( 1071 getProvider().getDatabase(context), Message.DELETED_TABLE_NAME); 1072 EmailProvider.deleteMessageOrphans( 1073 getProvider().getDatabase(context), Message.UPDATED_TABLE_NAME); 1074 1075 // There should now be 4 messages in each of the deleted and updated 1076 // tables again 1077 assertEquals(4, EmailContent.count(context, Message.UPDATED_CONTENT_URI, null, null)); 1078 assertEquals(4, EmailContent.count(context, Message.DELETED_CONTENT_URI, null, null)); 1079 } 1080 1081 /** 1082 * Test delete message 1083 * TODO: body 1084 * TODO: attachments 1085 */ 1086 public void testMessageDelete() { 1087 Account account1 = ProviderTestUtils.setupAccount("message-delete", true, mMockContext); 1088 long account1Id = account1.mId; 1089 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 1090 long box1Id = box1.mId; 1091 Message message1 = ProviderTestUtils.setupMessage("message1", 1092 account1Id, 1093 box1Id, 1094 false, 1095 true, 1096 mMockContext); 1097 long message1Id = message1.mId; 1098 Message message2 = ProviderTestUtils.setupMessage("message2", 1099 account1Id, 1100 box1Id, 1101 false, 1102 true, 1103 mMockContext); 1104 long message2Id = message2.mId; 1105 1106 String selection = EmailContent.MessageColumns.ACCOUNT_KEY + "=? AND " 1107 + EmailContent.MessageColumns.MAILBOX_KEY + "=?"; 1108 String[] selArgs = new String[] {String.valueOf(account1Id), String.valueOf(box1Id)}; 1109 1110 // make sure there are two messages 1111 int numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs); 1112 assertEquals(2, numMessages); 1113 1114 // now delete one of them 1115 Uri uri = ContentUris.withAppendedId(Message.CONTENT_URI, message1Id); 1116 mMockContext.getContentResolver().delete(uri, null, null); 1117 1118 // make sure there's only one message now 1119 numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs); 1120 assertEquals(1, numMessages); 1121 1122 // now delete the other one 1123 uri = ContentUris.withAppendedId(Message.CONTENT_URI, message2Id); 1124 mMockContext.getContentResolver().delete(uri, null, null); 1125 1126 // make sure there are no messages now 1127 numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs); 1128 assertEquals(0, numMessages); 1129 } 1130 1131 /** 1132 * Test delete synced message 1133 * TODO: body 1134 * TODO: attachments 1135 */ 1136 public void testSyncedMessageDelete() { 1137 Account account1 = 1138 ProviderTestUtils.setupAccount("synced-message-delete", true, mMockContext); 1139 long account1Id = account1.mId; 1140 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 1141 long box1Id = box1.mId; 1142 Message message1 = ProviderTestUtils.setupMessage("message1", 1143 account1Id, 1144 box1Id, 1145 false, 1146 true, 1147 mMockContext); 1148 long message1Id = message1.mId; 1149 Message message2 = ProviderTestUtils.setupMessage("message2", 1150 account1Id, 1151 box1Id, 1152 false, 1153 true, 1154 mMockContext); 1155 long message2Id = message2.mId; 1156 1157 String selection = EmailContent.MessageColumns.ACCOUNT_KEY + "=? AND " 1158 + EmailContent.MessageColumns.MAILBOX_KEY + "=?"; 1159 String[] selArgs = new String[] {String.valueOf(account1Id), String.valueOf(box1Id)}; 1160 1161 // make sure there are two messages 1162 int numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs); 1163 assertEquals(2, numMessages); 1164 1165 // make sure we start with no synced deletions 1166 numMessages = 1167 EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection, selArgs); 1168 assertEquals(0, numMessages); 1169 1170 // now delete one of them SYNCED 1171 Uri uri = ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message1Id); 1172 mMockContext.getContentResolver().delete(uri, null, null); 1173 1174 // make sure there's only one message now 1175 numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs); 1176 assertEquals(1, numMessages); 1177 1178 // make sure there's one synced deletion now 1179 numMessages = 1180 EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection, selArgs); 1181 assertEquals(1, numMessages); 1182 1183 // now delete the other one NOT SYNCED 1184 uri = ContentUris.withAppendedId(Message.CONTENT_URI, message2Id); 1185 mMockContext.getContentResolver().delete(uri, null, null); 1186 1187 // make sure there are no messages now 1188 numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs); 1189 assertEquals(0, numMessages); 1190 1191 // make sure there's still one deletion now 1192 numMessages = 1193 EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection, selArgs); 1194 assertEquals(1, numMessages); 1195 } 1196 1197 /** 1198 * Test message update 1199 * TODO: body 1200 * TODO: attachments 1201 */ 1202 public void testMessageUpdate() { 1203 Account account1 = ProviderTestUtils.setupAccount("message-update", true, mMockContext); 1204 long account1Id = account1.mId; 1205 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 1206 long box1Id = box1.mId; 1207 Message message1 = ProviderTestUtils.setupMessage("message1", 1208 account1Id, 1209 box1Id, 1210 false, 1211 true, 1212 mMockContext); 1213 long message1Id = message1.mId; 1214 Message message2 = ProviderTestUtils.setupMessage("message2", 1215 account1Id, 1216 box1Id, 1217 false, 1218 true, 1219 mMockContext); 1220 long message2Id = message2.mId; 1221 ContentResolver cr = mMockContext.getContentResolver(); 1222 1223 String selection = EmailContent.MessageColumns.ACCOUNT_KEY + "=? AND " 1224 + EmailContent.MessageColumns.MAILBOX_KEY + "=?"; 1225 String[] selArgs = new String[] {String.valueOf(account1Id), String.valueOf(box1Id)}; 1226 1227 // make sure there are two messages 1228 int numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs); 1229 assertEquals(2, numMessages); 1230 1231 // change the first one 1232 Uri uri = ContentUris.withAppendedId(Message.CONTENT_URI, message1Id); 1233 ContentValues cv = new ContentValues(); 1234 cv.put(MessageColumns.FROM_LIST, "from-list"); 1235 cr.update(uri, cv, null, null); 1236 1237 // make sure there's no updated message 1238 numMessages = 1239 EmailContent.count(mMockContext, Message.UPDATED_CONTENT_URI, selection, selArgs); 1240 assertEquals(0, numMessages); 1241 1242 // get the message back from the provider, make sure the change "stuck" 1243 Message restoredMessage = Message.restoreMessageWithId(mMockContext, message1Id); 1244 assertEquals("from-list", restoredMessage.mFrom); 1245 1246 // change the second one 1247 uri = ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message2Id); 1248 cv = new ContentValues(); 1249 cv.put(MessageColumns.FROM_LIST, "from-list"); 1250 cr.update(uri, cv, null, null); 1251 1252 // make sure there's one updated message 1253 numMessages = 1254 EmailContent.count(mMockContext, Message.UPDATED_CONTENT_URI, selection, selArgs); 1255 assertEquals(1, numMessages); 1256 1257 // get the message back from the provider, make sure the change "stuck", 1258 // as before 1259 restoredMessage = Message.restoreMessageWithId(mMockContext, message2Id); 1260 assertEquals("from-list", restoredMessage.mFrom); 1261 1262 // get the original message back from the provider 1263 Cursor c = 1264 cr.query(Message.UPDATED_CONTENT_URI, Message.CONTENT_PROJECTION, null, null, null); 1265 try { 1266 assertTrue(c.moveToFirst()); 1267 Message originalMessage = EmailContent.getContent(mMockContext, c, Message.class); 1268 // make sure this has the original value 1269 assertEquals("from message2", originalMessage.mFrom); 1270 // Should only be one 1271 assertFalse(c.moveToNext()); 1272 } finally { 1273 c.close(); 1274 } 1275 1276 // delete the second message 1277 cr.delete(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message2Id), null, null); 1278 1279 // hey, presto! the change should be gone 1280 numMessages = 1281 EmailContent.count(mMockContext, Message.UPDATED_CONTENT_URI, selection, selArgs); 1282 assertEquals(0, numMessages); 1283 1284 // and there should now be a deleted record 1285 numMessages = 1286 EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection, selArgs); 1287 assertEquals(1, numMessages); 1288 } 1289 1290 /** 1291 * TODO: cascaded delete account 1292 * TODO: hostauth 1293 * TODO: body 1294 * TODO: attachments 1295 * TODO: create other account, mailbox & messages and confirm the right objects were deleted 1296 */ 1297 public void testCascadeDeleteAccount() { 1298 Account account1 = 1299 ProviderTestUtils.setupAccount("account-delete-cascade", true, mMockContext); 1300 long account1Id = account1.mId; 1301 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 1302 long box1Id = box1.mId; 1303 /* Message message1 = */ProviderTestUtils.setupMessage("message1", 1304 account1Id, 1305 box1Id, 1306 false, 1307 true, 1308 mMockContext); 1309 /* Message message2 = */ProviderTestUtils.setupMessage("message2", 1310 account1Id, 1311 box1Id, 1312 false, 1313 true, 1314 mMockContext); 1315 1316 // make sure there is one account, one mailbox, and two messages 1317 int numAccounts = EmailContent.count(mMockContext, Account.CONTENT_URI, null, null); 1318 assertEquals(1, numAccounts); 1319 int numBoxes = EmailContent.count(mMockContext, Mailbox.CONTENT_URI, null, null); 1320 assertEquals(1, numBoxes); 1321 int numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null); 1322 assertEquals(2, numMessages); 1323 1324 // delete the account 1325 Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, account1Id); 1326 mMockContext.getContentResolver().delete(uri, null, null); 1327 1328 // make sure there are no accounts, mailboxes, or messages 1329 numAccounts = EmailContent.count(mMockContext, Account.CONTENT_URI, null, null); 1330 assertEquals(0, numAccounts); 1331 numBoxes = EmailContent.count(mMockContext, Mailbox.CONTENT_URI, null, null); 1332 assertEquals(0, numBoxes); 1333 numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null); 1334 assertEquals(0, numMessages); 1335 } 1336 1337 /** 1338 * Test cascaded delete mailbox 1339 * TODO: body 1340 * TODO: attachments 1341 * TODO: create other mailbox & messages and confirm the right objects were deleted 1342 */ 1343 public void testCascadeDeleteMailbox() { 1344 Account account1 = 1345 ProviderTestUtils.setupAccount("mailbox-delete-cascade", true, mMockContext); 1346 long account1Id = account1.mId; 1347 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 1348 long box1Id = box1.mId; 1349 Message message1 = ProviderTestUtils.setupMessage("message1", 1350 account1Id, 1351 box1Id, 1352 false, 1353 true, 1354 mMockContext); 1355 Message message2 = ProviderTestUtils.setupMessage("message2", 1356 account1Id, 1357 box1Id, 1358 false, 1359 true, 1360 mMockContext); 1361 Message message3 = ProviderTestUtils.setupMessage("message3", 1362 account1Id, 1363 box1Id, 1364 false, 1365 true, 1366 mMockContext); 1367 Message message4 = ProviderTestUtils.setupMessage("message4", 1368 account1Id, 1369 box1Id, 1370 false, 1371 true, 1372 mMockContext); 1373 ProviderTestUtils.setupMessage("message5", account1Id, box1Id, false, true, mMockContext); 1374 ProviderTestUtils.setupMessage("message6", account1Id, box1Id, false, true, mMockContext); 1375 1376 String selection = EmailContent.MessageColumns.ACCOUNT_KEY + "=? AND " 1377 + EmailContent.MessageColumns.MAILBOX_KEY + "=?"; 1378 String[] selArgs = new String[] {String.valueOf(account1Id), String.valueOf(box1Id)}; 1379 1380 // make sure there are six messages 1381 int numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs); 1382 assertEquals(6, numMessages); 1383 1384 ContentValues cv = new ContentValues(); 1385 cv.put(MessageColumns.SERVER_ID, "SERVER_ID"); 1386 ContentResolver resolver = mMockContext.getContentResolver(); 1387 1388 // Update two messages 1389 resolver.update(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message1.mId), cv, 1390 null, null); 1391 resolver.update(ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message2.mId), cv, 1392 null, null); 1393 // Delete two messages 1394 resolver.delete( 1395 ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message3.mId), null, null); 1396 resolver.delete( 1397 ContentUris.withAppendedId(Message.SYNCED_CONTENT_URI, message4.mId), null, null); 1398 1399 // There should now be two messages in updated/deleted, and 4 in 1400 // messages 1401 numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs); 1402 assertEquals(4, numMessages); 1403 numMessages = 1404 EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection, selArgs); 1405 assertEquals(2, numMessages); 1406 numMessages = 1407 EmailContent.count(mMockContext, Message.UPDATED_CONTENT_URI, selection, selArgs); 1408 assertEquals(2, numMessages); 1409 1410 // now delete the mailbox 1411 Uri uri = ContentUris.withAppendedId(Mailbox.CONTENT_URI, box1Id); 1412 resolver.delete(uri, null, null); 1413 1414 // there should now be zero messages in all three tables 1415 numMessages = EmailContent.count(mMockContext, Message.CONTENT_URI, selection, selArgs); 1416 assertEquals(0, numMessages); 1417 numMessages = 1418 EmailContent.count(mMockContext, Message.DELETED_CONTENT_URI, selection, selArgs); 1419 assertEquals(0, numMessages); 1420 numMessages = 1421 EmailContent.count(mMockContext, Message.UPDATED_CONTENT_URI, selection, selArgs); 1422 assertEquals(0, numMessages); 1423 } 1424 1425 /** 1426 * Test cascaded delete message 1427 * Confirms that deleting a message will also delete its body & attachments 1428 */ 1429 public void testCascadeMessageDelete() { 1430 Account account1 = ProviderTestUtils.setupAccount("message-cascade", true, mMockContext); 1431 long account1Id = account1.mId; 1432 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext); 1433 long box1Id = box1.mId; 1434 1435 // Each message has a body, and also give each 2 attachments 1436 Message message1 = ProviderTestUtils.setupMessage("message1", 1437 account1Id, 1438 box1Id, 1439 true, 1440 false, 1441 mMockContext); 1442 ArrayList<Attachment> atts = new ArrayList<Attachment>(); 1443 for (int i = 0; i < 2; i++) { 1444 atts.add(ProviderTestUtils.setupAttachment( 1445 -1, expectedAttachmentNames[i], expectedAttachmentSizes[i], false, 1446 mMockContext)); 1447 } 1448 message1.mAttachments = atts; 1449 message1.save(mMockContext); 1450 long message1Id = message1.mId; 1451 1452 Message message2 = ProviderTestUtils.setupMessage("message2", 1453 account1Id, 1454 box1Id, 1455 true, 1456 false, 1457 mMockContext); 1458 atts = new ArrayList<Attachment>(); 1459 for (int i = 0; i < 2; i++) { 1460 atts.add(ProviderTestUtils.setupAttachment( 1461 -1, expectedAttachmentNames[i], expectedAttachmentSizes[i], false, 1462 mMockContext)); 1463 } 1464 message2.mAttachments = atts; 1465 message2.save(mMockContext); 1466 long message2Id = message2.mId; 1467 1468 // Set up to test total counts of bodies & attachments for our test 1469 // messages 1470 String bodySelection = BodyColumns.MESSAGE_KEY + " IN (?,?)"; 1471 String attachmentSelection = AttachmentColumns.MESSAGE_KEY + " IN (?,?)"; 1472 String[] selArgs = new String[] {String.valueOf(message1Id), String.valueOf(message2Id)}; 1473 1474 // make sure there are two bodies 1475 int numBodies = EmailContent.count(mMockContext, Body.CONTENT_URI, bodySelection, selArgs); 1476 assertEquals(2, numBodies); 1477 1478 // make sure there are four attachments 1479 int numAttachments = EmailContent.count( 1480 mMockContext, Attachment.CONTENT_URI, attachmentSelection, selArgs); 1481 assertEquals(4, numAttachments); 1482 1483 // now delete one of the messages 1484 Uri uri = ContentUris.withAppendedId(Message.CONTENT_URI, message1Id); 1485 mMockContext.getContentResolver().delete(uri, null, null); 1486 1487 // there should be one body and two attachments 1488 numBodies = EmailContent.count(mMockContext, Body.CONTENT_URI, bodySelection, selArgs); 1489 assertEquals(1, numBodies); 1490 1491 numAttachments = EmailContent.count( 1492 mMockContext, Attachment.CONTENT_URI, attachmentSelection, selArgs); 1493 assertEquals(2, numAttachments); 1494 1495 // now delete the other message 1496 uri = ContentUris.withAppendedId(Message.CONTENT_URI, message2Id); 1497 mMockContext.getContentResolver().delete(uri, null, null); 1498 1499 // make sure there are no bodies or attachments 1500 numBodies = EmailContent.count(mMockContext, Body.CONTENT_URI, bodySelection, selArgs); 1501 assertEquals(0, numBodies); 1502 1503 numAttachments = EmailContent.count( 1504 mMockContext, Attachment.CONTENT_URI, attachmentSelection, selArgs); 1505 assertEquals(0, numAttachments); 1506 } 1507 1508 /** 1509 * Test that our unique file name algorithm works as expected. Since this test requires an 1510 * SD card, we check the environment first, and return immediately if none is mounted. 1511 * @throws IOException 1512 */ 1513 public void testCreateUniqueFile() throws IOException { 1514 // Delete existing files, if they exist 1515 if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 1516 return; 1517 } 1518 try { 1519 String fileName = "A11achm3n1.doc"; 1520 File uniqueFile = Attachment.createUniqueFile(fileName); 1521 assertEquals(fileName, uniqueFile.getName()); 1522 if (uniqueFile.createNewFile()) { 1523 uniqueFile = Attachment.createUniqueFile(fileName); 1524 assertEquals("A11achm3n1-2.doc", uniqueFile.getName()); 1525 if (uniqueFile.createNewFile()) { 1526 uniqueFile = Attachment.createUniqueFile(fileName); 1527 assertEquals("A11achm3n1-3.doc", uniqueFile.getName()); 1528 } 1529 } 1530 fileName = "A11achm3n1"; 1531 uniqueFile = Attachment.createUniqueFile(fileName); 1532 assertEquals(fileName, uniqueFile.getName()); 1533 if (uniqueFile.createNewFile()) { 1534 uniqueFile = Attachment.createUniqueFile(fileName); 1535 assertEquals("A11achm3n1-2", uniqueFile.getName()); 1536 } 1537 } finally { 1538 File directory = Environment.getExternalStorageDirectory(); 1539 // These are the files that should be created earlier in the test. 1540 // Make sure 1541 // they are deleted for the next go-around 1542 String[] fileNames = new String[] {"A11achm3n1.doc", "A11achm3n1-2.doc", "A11achm3n1"}; 1543 int length = fileNames.length; 1544 for (int i = 0; i < length; i++) { 1545 File file = new File(directory, fileNames[i]); 1546 if (file.exists()) { 1547 file.delete(); 1548 } 1549 } 1550 } 1551 } 1552 1553 /** 1554 * Test retrieving attachments by message ID (using EmailContent.Attachment.MESSAGE_ID_URI) 1555 */ 1556 public void testGetAttachmentByMessageIdUri() { 1557 1558 // Note, we don't strictly need accounts, mailboxes or messages to run 1559 // this test. 1560 Attachment a1 = ProviderTestUtils.setupAttachment(1, "a1", 100, true, mMockContext); 1561 Attachment a2 = ProviderTestUtils.setupAttachment(1, "a2", 200, true, mMockContext); 1562 ProviderTestUtils.setupAttachment(2, "a3", 300, true, mMockContext); 1563 ProviderTestUtils.setupAttachment(2, "a4", 400, true, mMockContext); 1564 1565 // Now ask for the attachments of message id=1 1566 // Note: Using the "sort by size" trick to bring them back in expected 1567 // order 1568 Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, 1); 1569 Cursor c = mMockContext.getContentResolver() 1570 .query(uri, Attachment.CONTENT_PROJECTION, null, null, AttachmentColumns.SIZE); 1571 assertEquals(2, c.getCount()); 1572 1573 try { 1574 c.moveToFirst(); 1575 Attachment a1Get = EmailContent.getContent(mMockContext, c, Attachment.class); 1576 ProviderTestUtils.assertAttachmentEqual("getAttachByUri-1", a1, a1Get); 1577 c.moveToNext(); 1578 Attachment a2Get = EmailContent.getContent(mMockContext, c, Attachment.class); 1579 ProviderTestUtils.assertAttachmentEqual("getAttachByUri-2", a2, a2Get); 1580 } finally { 1581 c.close(); 1582 } 1583 } 1584 1585 /** 1586 * Test deleting attachments by message ID (using EmailContent.Attachment.MESSAGE_ID_URI) 1587 */ 1588 public void testDeleteAttachmentByMessageIdUri() { 1589 ContentResolver mockResolver = mMockContext.getContentResolver(); 1590 1591 // Note, we don't strictly need accounts, mailboxes or messages to run 1592 // this test. 1593 ProviderTestUtils.setupAttachment(1, "a1", 100, true, mMockContext); 1594 ProviderTestUtils.setupAttachment(1, "a2", 200, true, mMockContext); 1595 Attachment a3 = ProviderTestUtils.setupAttachment(2, "a3", 300, true, mMockContext); 1596 Attachment a4 = ProviderTestUtils.setupAttachment(2, "a4", 400, true, mMockContext); 1597 1598 // Delete all attachments for message id=1 1599 Uri uri = ContentUris.withAppendedId(Attachment.MESSAGE_ID_URI, 1); 1600 mockResolver.delete(uri, null, null); 1601 1602 // Read back all attachments and confirm that we have the expected 1603 // remaining attachments 1604 // (the attachments that are set for message id=2). Note order-by size 1605 // to simplify test. 1606 Cursor c = mockResolver.query( 1607 Attachment.CONTENT_URI, Attachment.CONTENT_PROJECTION, null, null, 1608 AttachmentColumns.SIZE); 1609 assertEquals(2, c.getCount()); 1610 1611 try { 1612 c.moveToFirst(); 1613 Attachment a3Get = EmailContent.getContent(mMockContext, c, Attachment.class); 1614 ProviderTestUtils.assertAttachmentEqual("getAttachByUri-3", a3, a3Get); 1615 c.moveToNext(); 1616 Attachment a4Get = EmailContent.getContent(mMockContext, c, Attachment.class); 1617 ProviderTestUtils.assertAttachmentEqual("getAttachByUri-4", a4, a4Get); 1618 } finally { 1619 c.close(); 1620 } 1621 } 1622 1623 @SmallTest 1624 public void testGetDefaultAccountNoneExplicitlySet() { 1625 Account account1 = ProviderTestUtils.setupAccount("account-default-1", false, mMockContext); 1626 account1.save(mMockContext); 1627 1628 // We should find account1 as default 1629 long defaultAccountId = Account.getDefaultAccountId(mMockContext, Account.NO_ACCOUNT); 1630 assertEquals(defaultAccountId, account1.mId); 1631 1632 Account account2 = ProviderTestUtils.setupAccount("account-default-2", false, mMockContext); 1633 account2.save(mMockContext); 1634 1635 Account account3 = ProviderTestUtils.setupAccount("account-default-3", false, mMockContext); 1636 account3.save(mMockContext); 1637 1638 // We should find the earliest one as the default, so that it can be 1639 // consistent on 1640 // repeated calls. 1641 defaultAccountId = Account.getDefaultAccountId(mMockContext, Account.NO_ACCOUNT); 1642 assertTrue(defaultAccountId == account1.mId); 1643 } 1644 1645 /** 1646 * Tests of default account behavior. Note that default account behavior is handled differently 1647 * now. If there is no last used account, the first account found by our account query is the 1648 * default. If there is a last used account, the last used account is our default. 1649 * 1650 * 1. Simple set/get 1651 * 2. Moving default between 3 accounts 1652 * 3. Delete default, make sure another becomes default 1653 */ 1654 public void testGetDefaultAccountWithLastUsedAccount() { 1655 long lastUsedAccountId = Account.NO_ACCOUNT; 1656 1657 // There should be no default account if there are no accounts 1658 long defaultAccountId = Account.getDefaultAccountId(mMockContext, lastUsedAccountId); 1659 assertEquals(Account.NO_ACCOUNT, defaultAccountId); 1660 1661 Account account1 = ProviderTestUtils.setupAccount("account-default-1", false, mMockContext); 1662 account1.save(mMockContext); 1663 long account1Id = account1.mId; 1664 Account account2 = ProviderTestUtils.setupAccount("account-default-2", false, mMockContext); 1665 account2.save(mMockContext); 1666 long account2Id = account2.mId; 1667 Account account3 = ProviderTestUtils.setupAccount("account-default-3", false, mMockContext); 1668 account3.save(mMockContext); 1669 long account3Id = account3.mId; 1670 1671 // With three accounts, but none marked default, confirm that the first 1672 // one is the default. 1673 defaultAccountId = Account.getDefaultAccountId(mMockContext, lastUsedAccountId); 1674 assertTrue(defaultAccountId == account1Id); 1675 1676 // updating lastUsedAccountId locally instead of updating through 1677 // Preferences 1678 lastUsedAccountId = defaultAccountId; 1679 defaultAccountId = Account.getDefaultAccountId(mMockContext, lastUsedAccountId); 1680 assertEquals(account1Id, defaultAccountId); 1681 1682 // updating lastUsedAccountId locally instead of updating through 1683 // Preferences 1684 lastUsedAccountId = account2Id; 1685 defaultAccountId = Account.getDefaultAccountId(mMockContext, lastUsedAccountId); 1686 assertEquals(account2Id, defaultAccountId); 1687 1688 // updating lastUsedAccountId locally instead of updating through 1689 // Preferences 1690 lastUsedAccountId = account3Id; 1691 defaultAccountId = Account.getDefaultAccountId(mMockContext, lastUsedAccountId); 1692 assertEquals(account3Id, defaultAccountId); 1693 1694 // Now delete a non-default account and confirm no change 1695 Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, account1Id); 1696 mMockContext.getContentResolver().delete(uri, null, null); 1697 1698 defaultAccountId = Account.getDefaultAccountId(mMockContext, lastUsedAccountId); 1699 assertEquals(account3Id, defaultAccountId); 1700 1701 // Now confirm deleting the default account and it switches to another 1702 // one 1703 uri = ContentUris.withAppendedId(Account.CONTENT_URI, account3Id); 1704 mMockContext.getContentResolver().delete(uri, null, null); 1705 1706 defaultAccountId = Account.getDefaultAccountId(mMockContext, lastUsedAccountId); 1707 assertEquals(account2Id, defaultAccountId); 1708 1709 // updating lastUsedAccountId locally instead of updating through 1710 // Preferences 1711 lastUsedAccountId = defaultAccountId; 1712 1713 // Now delete the final account and confirm there are no default 1714 // accounts again 1715 uri = ContentUris.withAppendedId(Account.CONTENT_URI, account2Id); 1716 mMockContext.getContentResolver().delete(uri, null, null); 1717 1718 defaultAccountId = Account.getDefaultAccountId(mMockContext, lastUsedAccountId); 1719 assertEquals(Account.NO_ACCOUNT, defaultAccountId); 1720 } 1721 1722 public static Message setupUnreadMessage(String name, 1723 long accountId, 1724 long mailboxId, 1725 boolean addBody, 1726 boolean saveIt, 1727 Context context) { 1728 Message msg = 1729 ProviderTestUtils.setupMessage(name, accountId, mailboxId, addBody, false, context); 1730 msg.mFlagRead = false; 1731 if (saveIt) { 1732 msg.save(context); 1733 } 1734 return msg; 1735 } 1736 1737 public void testUnreadCountTriggers() { 1738 // Start with one account and three mailboxes 1739 Account account = ProviderTestUtils.setupAccount("triggers", true, mMockContext); 1740 Mailbox boxA = ProviderTestUtils.setupMailbox("boxA", account.mId, true, mMockContext); 1741 Mailbox boxB = ProviderTestUtils.setupMailbox("boxB", account.mId, true, mMockContext); 1742 Mailbox boxC = ProviderTestUtils.setupMailbox("boxC", account.mId, true, mMockContext); 1743 1744 // Make sure there are no unreads 1745 assertEquals(0, getUnreadCount(boxA.mId)); 1746 assertEquals(0, getUnreadCount(boxB.mId)); 1747 assertEquals(0, getUnreadCount(boxC.mId)); 1748 1749 // Create 4 unread messages (only 3 named) in boxA 1750 Message message1 = 1751 setupUnreadMessage("message1", account.mId, boxA.mId, false, true, mMockContext); 1752 Message message2 = 1753 setupUnreadMessage("message2", account.mId, boxA.mId, false, true, mMockContext); 1754 Message message3 = 1755 setupUnreadMessage("message3", account.mId, boxA.mId, false, true, mMockContext); 1756 setupUnreadMessage("message4", account.mId, boxC.mId, false, true, mMockContext); 1757 1758 // Make sure the unreads are where we expect them 1759 assertEquals(3, getUnreadCount(boxA.mId)); 1760 assertEquals(0, getUnreadCount(boxB.mId)); 1761 assertEquals(1, getUnreadCount(boxC.mId)); 1762 1763 // After deleting message 1, the count in box A should be decremented 1764 // (to 2) 1765 ContentResolver cr = mMockContext.getContentResolver(); 1766 Uri uri = ContentUris.withAppendedId(Message.CONTENT_URI, message1.mId); 1767 cr.delete(uri, null, null); 1768 assertEquals(2, getUnreadCount(boxA.mId)); 1769 assertEquals(0, getUnreadCount(boxB.mId)); 1770 assertEquals(1, getUnreadCount(boxC.mId)); 1771 1772 // Move message 2 to box B, leaving 1 in box A and 1 in box B 1773 message2.mMailboxKey = boxB.mId; 1774 ContentValues cv = new ContentValues(); 1775 cv.put(MessageColumns.MAILBOX_KEY, boxB.mId); 1776 cr.update(ContentUris.withAppendedId(Message.CONTENT_URI, message2.mId), cv, null, null); 1777 assertEquals(1, getUnreadCount(boxA.mId)); 1778 assertEquals(1, getUnreadCount(boxB.mId)); 1779 assertEquals(1, getUnreadCount(boxC.mId)); 1780 1781 // Mark message 3 (from box A) read, leaving 0 in box A 1782 cv.clear(); 1783 cv.put(MessageColumns.FLAG_READ, 1); 1784 cr.update(ContentUris.withAppendedId(Message.CONTENT_URI, message3.mId), cv, null, null); 1785 assertEquals(0, getUnreadCount(boxA.mId)); 1786 assertEquals(1, getUnreadCount(boxB.mId)); 1787 assertEquals(1, getUnreadCount(boxC.mId)); 1788 1789 // Move message 3 to box C; should be no change (it's read) 1790 message3.mMailboxKey = boxC.mId; 1791 cv.clear(); 1792 cv.put(MessageColumns.MAILBOX_KEY, boxC.mId); 1793 cr.update(ContentUris.withAppendedId(Message.CONTENT_URI, message3.mId), cv, null, null); 1794 assertEquals(0, getUnreadCount(boxA.mId)); 1795 assertEquals(1, getUnreadCount(boxB.mId)); 1796 assertEquals(1, getUnreadCount(boxC.mId)); 1797 1798 // Mark message 3 unread; it's now in box C, so that box's count should 1799 // go up to 3 1800 cv.clear(); 1801 cv.put(MessageColumns.FLAG_READ, 0); 1802 cr.update(ContentUris.withAppendedId(Message.CONTENT_URI, message3.mId), cv, null, null); 1803 assertEquals(0, getUnreadCount(boxA.mId)); 1804 assertEquals(1, getUnreadCount(boxB.mId)); 1805 assertEquals(2, getUnreadCount(boxC.mId)); 1806 } 1807 1808 /** 1809 * Test for EmailProvider.createIndex(). 1810 * Check that it returns exacly the same string as the one used previously for index creation. 1811 */ 1812 public void testCreateIndex() { 1813 String oldStr = "create index message_" + MessageColumns.TIMESTAMP + " on " 1814 + Message.TABLE_NAME + " (" + MessageColumns.TIMESTAMP + ");"; 1815 String newStr = DBHelper.createIndex(Message.TABLE_NAME, MessageColumns.TIMESTAMP); 1816 assertEquals(newStr, oldStr); 1817 } 1818 1819 public void testDatabaseCorruptionRecovery() { 1820 final ContentResolver resolver = mMockContext.getContentResolver(); 1821 final Context context = mMockContext; 1822 1823 // Create account and two mailboxes 1824 Account acct = ProviderTestUtils.setupAccount("acct1", true, context); 1825 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", acct.mId, true, context); 1826 1827 // Create 4 messages in box1 with bodies 1828 ProviderTestUtils.setupMessage("message1", acct.mId, box1.mId, true, true, context); 1829 ProviderTestUtils.setupMessage("message2", acct.mId, box1.mId, true, true, context); 1830 ProviderTestUtils.setupMessage("message3", acct.mId, box1.mId, true, true, context); 1831 ProviderTestUtils.setupMessage("message4", acct.mId, box1.mId, true, true, context); 1832 1833 // Confirm there are four messages 1834 int count = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null); 1835 assertEquals(4, count); 1836 // Confirm there are four bodies 1837 count = EmailContent.count(mMockContext, Body.CONTENT_URI, null, null); 1838 assertEquals(4, count); 1839 1840 // Find the EmailProvider.db file 1841 File dbFile = mMockContext.getDatabasePath(EmailProvider.DATABASE_NAME); 1842 // The EmailProvider.db database should exist (the provider creates it 1843 // automatically) 1844 assertTrue(dbFile != null); 1845 assertTrue(dbFile.exists()); 1846 // Delete it, and confirm it is gone 1847 assertTrue(dbFile.delete()); 1848 assertFalse(dbFile.exists()); 1849 1850 // Find the EmailProviderBody.db file 1851 dbFile = mMockContext.getDatabasePath(EmailProvider.BODY_DATABASE_NAME); 1852 // The EmailProviderBody.db database should still exist 1853 assertTrue(dbFile != null); 1854 assertTrue(dbFile.exists()); 1855 1856 // URI to uncache the databases 1857 // This simulates the Provider starting up again (otherwise, it will 1858 // still be pointing to 1859 // the already opened files) 1860 // Note that we only have access to the EmailProvider via the 1861 // ContentResolver; therefore, 1862 // we cannot directly call into the provider and use a URI for this 1863 resolver.update(EmailProvider.INTEGRITY_CHECK_URI, null, null, null); 1864 1865 // TODO We should check for the deletion of attachment files once this 1866 // is implemented in 1867 // the provider 1868 1869 // Explanation for what happens below... 1870 // The next time the database is created by the provider, it will notice 1871 // that there's 1872 // already a EmailProviderBody.db file. In this case, it will delete 1873 // that database to 1874 // ensure that both are in sync (and empty) 1875 1876 // Confirm there are no bodies 1877 count = EmailContent.count(mMockContext, Body.CONTENT_URI, null, null); 1878 assertEquals(0, count); 1879 1880 // Confirm there are no messages 1881 count = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null); 1882 assertEquals(0, count); 1883 } 1884 1885 public void testBodyDatabaseCorruptionRecovery() { 1886 final ContentResolver resolver = mMockContext.getContentResolver(); 1887 final Context context = mMockContext; 1888 1889 // Create account and two mailboxes 1890 Account acct = ProviderTestUtils.setupAccount("acct1", true, context); 1891 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", acct.mId, true, context); 1892 1893 // Create 4 messages in box1 with bodies 1894 ProviderTestUtils.setupMessage("message1", acct.mId, box1.mId, true, true, context); 1895 ProviderTestUtils.setupMessage("message2", acct.mId, box1.mId, true, true, context); 1896 ProviderTestUtils.setupMessage("message3", acct.mId, box1.mId, true, true, context); 1897 ProviderTestUtils.setupMessage("message4", acct.mId, box1.mId, true, true, context); 1898 1899 // Confirm there are four messages 1900 int count = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null); 1901 assertEquals(4, count); 1902 // Confirm there are four bodies 1903 count = EmailContent.count(mMockContext, Body.CONTENT_URI, null, null); 1904 assertEquals(4, count); 1905 1906 // Find the EmailProviderBody.db file 1907 File dbFile = mMockContext.getDatabasePath(EmailProvider.BODY_DATABASE_NAME); 1908 // The EmailProviderBody.db database should exist (the provider creates 1909 // it automatically) 1910 assertTrue(dbFile != null); 1911 assertTrue(dbFile.exists()); 1912 // Delete it, and confirm it is gone 1913 assertTrue(dbFile.delete()); 1914 assertFalse(dbFile.exists()); 1915 1916 // Find the EmailProvider.db file 1917 dbFile = mMockContext.getDatabasePath(EmailProvider.DATABASE_NAME); 1918 // The EmailProviderBody.db database should still exist 1919 assertTrue(dbFile != null); 1920 assertTrue(dbFile.exists()); 1921 1922 // URI to uncache the databases 1923 // This simulates the Provider starting up again (otherwise, it will 1924 // still be pointing to 1925 // the already opened files) 1926 // Note that we only have access to the EmailProvider via the 1927 // ContentResolver; therefore, 1928 // we cannot directly call into the provider and use a URI for this 1929 resolver.update(EmailProvider.INTEGRITY_CHECK_URI, null, null, null); 1930 1931 // TODO We should check for the deletion of attachment files once this 1932 // is implemented in 1933 // the provider 1934 1935 // Explanation for what happens below... 1936 // The next time the body database is created by the provider, it will 1937 // notice that there's 1938 // already a populated EmailProvider.db file. In this case, it will 1939 // delete that database to 1940 // ensure that both are in sync (and empty) 1941 1942 // Confirm there are no messages 1943 count = EmailContent.count(mMockContext, Message.CONTENT_URI, null, null); 1944 assertEquals(0, count); 1945 1946 // Confirm there are no bodies 1947 count = EmailContent.count(mMockContext, Body.CONTENT_URI, null, null); 1948 assertEquals(0, count); 1949 } 1950 1951 public void testAccountIsSecurityHold() { 1952 final Context context = mMockContext; 1953 Account acct1 = ProviderTestUtils.setupAccount("acct1", true, context); 1954 1955 Account acct2 = ProviderTestUtils.setupAccount("acct2", false, context); 1956 acct2.mFlags |= Account.FLAGS_SECURITY_HOLD; 1957 acct2.save(context); 1958 1959 assertFalse(Account.isSecurityHold(context, acct1.mId)); 1960 assertTrue(Account.isSecurityHold(context, acct2.mId)); 1961 assertFalse(Account.isSecurityHold(context, 9999999)); // No such 1962 // account 1963 } 1964 1965 public void testClearAccountHoldFlags() { 1966 Account a1 = ProviderTestUtils.setupAccount("holdflag-1", false, mMockContext); 1967 a1.mFlags = Account.FLAGS_SUPPORTS_SEARCH; 1968 a1.mPolicy = new Policy(); 1969 a1.save(mMockContext); 1970 Account a2 = ProviderTestUtils.setupAccount("holdflag-2", false, mMockContext); 1971 a2.mFlags = Account.FLAGS_SUPPORTS_SMART_FORWARD | Account.FLAGS_SECURITY_HOLD; 1972 a2.mPolicy = new Policy(); 1973 a2.save(mMockContext); 1974 1975 // bulk clear 1976 Account.clearSecurityHoldOnAllAccounts(mMockContext); 1977 1978 // confirm new values as expected - no hold flags; other flags 1979 // unmolested 1980 Account a1a = Account.restoreAccountWithId(mMockContext, a1.mId); 1981 assertEquals(Account.FLAGS_SUPPORTS_SEARCH, a1a.mFlags); 1982 Account a2a = Account.restoreAccountWithId(mMockContext, a2.mId); 1983 assertEquals(Account.FLAGS_SUPPORTS_SMART_FORWARD, a2a.mFlags); 1984 } 1985 1986 private static Message createMessage(Context c, Mailbox b, boolean starred, boolean read) { 1987 return ProviderTestUtils.setupMessage("1", 1988 b.mAccountKey, 1989 b.mId, 1990 true, 1991 true, 1992 c, 1993 starred, 1994 read); 1995 } 1996 1997 public void testGetKeyColumnLong() { 1998 final Context c = mMockContext; 1999 Account a = ProviderTestUtils.setupAccount("acct", true, c); 2000 Mailbox b1 = ProviderTestUtils.setupMailbox("box1", a.mId, true, c, Mailbox.TYPE_MAIL); 2001 Mailbox b2 = ProviderTestUtils.setupMailbox("box2", a.mId, true, c, Mailbox.TYPE_MAIL); 2002 Message m1 = createMessage(c, b1, false, false); 2003 Message m2 = createMessage(c, b2, false, false); 2004 assertEquals(a.mId, Message.getKeyColumnLong(c, m1.mId, MessageColumns.ACCOUNT_KEY)); 2005 assertEquals(a.mId, Message.getKeyColumnLong(c, m2.mId, MessageColumns.ACCOUNT_KEY)); 2006 assertEquals(b1.mId, Message.getKeyColumnLong(c, m1.mId, MessageColumns.MAILBOX_KEY)); 2007 assertEquals(b2.mId, Message.getKeyColumnLong(c, m2.mId, MessageColumns.MAILBOX_KEY)); 2008 } 2009 2010 public void testGetAccountIdForMessageId() { 2011 final Context c = mMockContext; 2012 Account a1 = ProviderTestUtils.setupAccount("acct1", true, c); 2013 Account a2 = ProviderTestUtils.setupAccount("acct2", true, c); 2014 Mailbox b1 = ProviderTestUtils.setupMailbox("box1", a1.mId, true, c, Mailbox.TYPE_MAIL); 2015 Mailbox b2 = ProviderTestUtils.setupMailbox("box2", a2.mId, true, c, Mailbox.TYPE_MAIL); 2016 Message m1 = createMessage(c, b1, false, false); 2017 Message m2 = createMessage(c, b2, false, false); 2018 2019 assertEquals(a1.mId, Account.getAccountIdForMessageId(c, m1.mId)); 2020 assertEquals(a2.mId, Account.getAccountIdForMessageId(c, m2.mId)); 2021 2022 // message desn't exist 2023 assertEquals(-1, Account.getAccountIdForMessageId(c, 12345)); 2024 } 2025 2026 public void testGetAccountForMessageId() { 2027 final Context c = mMockContext; 2028 Account a = ProviderTestUtils.setupAccount("acct", true, c); 2029 Message m1 = ProviderTestUtils.setupMessage("1", a.mId, 1, true, true, c, false, false); 2030 Message m2 = ProviderTestUtils.setupMessage("1", a.mId, 2, true, true, c, false, false); 2031 ProviderTestUtils.assertAccountEqual("x", a, Account.getAccountForMessageId(c, m1.mId)); 2032 ProviderTestUtils.assertAccountEqual("x", a, Account.getAccountForMessageId(c, m2.mId)); 2033 } 2034 2035 public void testGetAccountGetInboxIdTest() { 2036 final Context c = mMockContext; 2037 2038 // Prepare some data with red-herrings. 2039 Account a2 = ProviderTestUtils.setupAccount("acct2", true, c); 2040 Mailbox b2i = ProviderTestUtils.setupMailbox("b2b", a2.mId, true, c, Mailbox.TYPE_INBOX); 2041 2042 assertEquals(b2i.mId, Account.getInboxId(c, a2.mId)); 2043 2044 // No account found. 2045 assertEquals(-1, Account.getInboxId(c, 999999)); 2046 } 2047 2048 /** 2049 * Check that we're handling illegal uri's properly (by throwing an exception unless it's a 2050 * query for an id of -1, in which case we return a zero-length cursor) 2051 */ 2052 public void testIllegalUri() { 2053 final ContentResolver cr = mMockContext.getContentResolver(); 2054 2055 ContentValues cv = new ContentValues(); 2056 Uri uri = Uri.parse("content://" + EmailContent.AUTHORITY + "/fooble"); 2057 try { 2058 cr.insert(uri, cv); 2059 fail("Insert should have thrown exception"); 2060 } catch (IllegalArgumentException e) { 2061 } 2062 try { 2063 cr.update(uri, cv, null, null); 2064 fail("Update should have thrown exception"); 2065 } catch (IllegalArgumentException e) { 2066 } 2067 try { 2068 cr.delete(uri, null, null); 2069 fail("Delete should have thrown exception"); 2070 } catch (IllegalArgumentException e) { 2071 } 2072 try { 2073 cr.query(uri, EmailContent.ID_PROJECTION, null, null, null); 2074 fail("Query should have thrown exception"); 2075 } catch (IllegalArgumentException e) { 2076 } 2077 uri = Uri.parse("content://" + EmailContent.AUTHORITY + "/mailbox/fred"); 2078 try { 2079 cr.query(uri, EmailContent.ID_PROJECTION, null, null, null); 2080 fail("Query should have thrown exception"); 2081 } catch (IllegalArgumentException e) { 2082 } 2083 uri = Uri.parse("content://" + EmailContent.AUTHORITY + "/mailbox/-1"); 2084 Cursor c = cr.query(uri, EmailContent.ID_PROJECTION, null, null, null); 2085 assertNotNull(c); 2086 assertEquals(0, c.getCount()); 2087 c.close(); 2088 } 2089 2090 /** 2091 * Verify {@link EmailProvider#recalculateMessageCount(android.database.sqlite.SQLiteDatabase)} 2092 */ 2093 public void testRecalculateMessageCounts() { 2094 final Context c = mMockContext; 2095 2096 // Create accounts 2097 Account a1 = ProviderTestUtils.setupAccount("holdflag-1", true, c); 2098 Account a2 = ProviderTestUtils.setupAccount("holdflag-2", true, c); 2099 2100 // Create mailboxes for each account 2101 Mailbox b1 = ProviderTestUtils.setupMailbox("box1", a1.mId, true, c, Mailbox.TYPE_INBOX); 2102 Mailbox b2 = ProviderTestUtils.setupMailbox("box2", a1.mId, true, c, Mailbox.TYPE_OUTBOX); 2103 Mailbox b3 = ProviderTestUtils.setupMailbox("box3", a2.mId, true, c, Mailbox.TYPE_INBOX); 2104 Mailbox b4 = ProviderTestUtils.setupMailbox("box4", a2.mId, true, c, Mailbox.TYPE_OUTBOX); 2105 Mailbox bt = ProviderTestUtils.setupMailbox("boxT", a2.mId, true, c, Mailbox.TYPE_TRASH); 2106 2107 // Create some messages 2108 // b1 (account 1, inbox): 1 message, including 1 starred 2109 Message m11 = createMessage(c, b1, true, false, Message.FLAG_LOADED_COMPLETE); 2110 2111 // b2 (account 1, outbox): 2 message, including 1 starred 2112 Message m21 = createMessage(c, b2, false, false, Message.FLAG_LOADED_COMPLETE); 2113 Message m22 = createMessage(c, b2, true, true, Message.FLAG_LOADED_COMPLETE); 2114 2115 // b3 (account 2, inbox): 3 message, including 1 starred 2116 Message m31 = createMessage(c, b3, false, false, Message.FLAG_LOADED_COMPLETE); 2117 Message m32 = createMessage(c, b3, false, false, Message.FLAG_LOADED_COMPLETE); 2118 Message m33 = createMessage(c, b3, true, true, Message.FLAG_LOADED_COMPLETE); 2119 2120 // b4 (account 2, outbox) has no messages. 2121 2122 // bt (account 2, trash) has 3 messages, including 2 starred 2123 Message mt1 = createMessage(c, bt, true, false, Message.FLAG_LOADED_COMPLETE); 2124 Message mt2 = createMessage(c, bt, true, false, Message.FLAG_LOADED_COMPLETE); 2125 Message mt3 = createMessage(c, bt, false, false, Message.FLAG_LOADED_COMPLETE); 2126 2127 // Verifiy initial message counts 2128 assertEquals(1, getMessageCount(b1.mId)); 2129 assertEquals(2, getMessageCount(b2.mId)); 2130 assertEquals(3, getMessageCount(b3.mId)); 2131 assertEquals(0, getMessageCount(b4.mId)); 2132 assertEquals(3, getMessageCount(bt.mId)); 2133 2134 // Whew. The setup is done; now let's actually get to the test 2135 2136 // First, invalidate the message counts. 2137 setMinusOneToMessageCounts(); 2138 assertEquals(-1, getMessageCount(b1.mId)); 2139 assertEquals(-1, getMessageCount(b2.mId)); 2140 assertEquals(-1, getMessageCount(b3.mId)); 2141 assertEquals(-1, getMessageCount(b4.mId)); 2142 assertEquals(-1, getMessageCount(bt.mId)); 2143 2144 // Batch update. 2145 SQLiteDatabase db = getProvider().getDatabase(mMockContext); 2146 DBHelper.recalculateMessageCount(db); 2147 2148 // Check message counts are valid again 2149 assertEquals(1, getMessageCount(b1.mId)); 2150 assertEquals(2, getMessageCount(b2.mId)); 2151 assertEquals(3, getMessageCount(b3.mId)); 2152 assertEquals(0, getMessageCount(b4.mId)); 2153 assertEquals(3, getMessageCount(bt.mId)); 2154 } 2155 2156 /** Creates an account */ 2157 private Account createAccount(Context c, String name, HostAuth recvAuth, HostAuth sendAuth) { 2158 Account account = ProviderTestUtils.setupAccount(name, false, c); 2159 if (recvAuth != null) { 2160 account.mHostAuthKeyRecv = recvAuth.mId; 2161 if (sendAuth == null) { 2162 account.mHostAuthKeySend = recvAuth.mId; 2163 } 2164 } 2165 if (sendAuth != null) { 2166 account.mHostAuthKeySend = sendAuth.mId; 2167 } 2168 account.save(c); 2169 return account; 2170 } 2171 2172 /** Creates a mailbox; redefine as we need version 17 mailbox values */ 2173 private Mailbox createMailbox( 2174 Context c, String displayName, String serverId, long parentKey, long accountId) { 2175 Mailbox box = new Mailbox(); 2176 2177 box.mDisplayName = displayName; 2178 box.mServerId = serverId; 2179 box.mParentKey = parentKey; 2180 box.mAccountKey = accountId; 2181 // Don't care about the fields below ... set them for giggles 2182 box.mType = Mailbox.TYPE_MAIL; 2183 box.mDelimiter = '/'; 2184 box.mSyncKey = "sync-key"; 2185 box.mSyncLookback = 2; 2186 box.mSyncInterval = Account.CHECK_INTERVAL_NEVER; 2187 box.mSyncTime = 3; 2188 box.mFlagVisible = true; 2189 box.mFlags = 5; 2190 box.save(c); 2191 return box; 2192 } 2193 2194 /** 2195 * Asserts equality between two mailboxes. We define this as we don't have implementations 2196 * for Mailbox#equals(). 2197 */ 2198 private void assertEquals(Mailbox expected, Mailbox actual) { 2199 if (expected == null && actual == null) return; 2200 assertTrue(expected != null && actual != null); 2201 assertEqualsExceptServerId(expected, actual, expected.mServerId); 2202 } 2203 2204 /** 2205 * Asserts equality between the two mailboxes EXCEPT for the server id. The given server 2206 * ID is the expected value. 2207 */ 2208 private void assertEqualsExceptServerId(Mailbox expected, Mailbox actual, String serverId) { 2209 if (expected == null && actual == null) return; 2210 2211 assertTrue(expected != null && actual != null); 2212 assertEquals(expected.mDisplayName, actual.mDisplayName); 2213 assertEquals(serverId, actual.mServerId); 2214 assertEquals(expected.mParentKey, actual.mParentKey); 2215 assertEquals(expected.mAccountKey, actual.mAccountKey); 2216 } 2217 2218 /** 2219 * Determine whether a list of AccountManager accounts includes a given EmailProvider account 2220 * @param amAccountList a list of AccountManager accounts 2221 * @param account an EmailProvider account 2222 * @param context the caller's context (our test provider's context) 2223 * @return whether or not the EmailProvider account is represented in AccountManager 2224 */ 2225 private boolean amAccountListHasAccount( 2226 android.accounts.Account[] amAccountList, Account account, Context context) { 2227 String email = account.mEmailAddress; 2228 for (android.accounts.Account amAccount : amAccountList) { 2229 if (amAccount.name.equals(email)) { 2230 return true; 2231 } 2232 } 2233 return false; 2234 } 2235 2236 /** Creates a mailbox; redefine as we need version 17 mailbox values */ 2237 private Mailbox createTypeMailbox(Context c, long accountId, int type) { 2238 Mailbox box = new Mailbox(); 2239 2240 box.mDisplayName = "foo"; 2241 box.mServerId = "1:1"; 2242 box.mParentKey = 0; 2243 box.mAccountKey = accountId; 2244 // Don't care about the fields below ... set them for giggles 2245 box.mType = type; 2246 box.save(c); 2247 return box; 2248 } 2249 2250 public void testCleanupOrphans() { 2251 EmailProvider ep = getProvider(); 2252 SQLiteDatabase db = ep.getDatabase(mMockContext); 2253 2254 Account a = ProviderTestUtils.setupAccount("account1", true, mMockContext); 2255 // Mailbox a1 and a3 won't have a valid account 2256 Mailbox a1 = createTypeMailbox(mMockContext, -1, Mailbox.TYPE_INBOX); 2257 Mailbox a2 = createTypeMailbox(mMockContext, a.mId, Mailbox.TYPE_MAIL); 2258 Mailbox a3 = createTypeMailbox(mMockContext, -1, Mailbox.TYPE_DRAFTS); 2259 Mailbox a4 = createTypeMailbox(mMockContext, a.mId, Mailbox.TYPE_SENT); 2260 Mailbox a5 = createTypeMailbox(mMockContext, a.mId, Mailbox.TYPE_TRASH); 2261 // Mailbox ax isn't even saved; use an obviously invalid id 2262 Mailbox ax = new Mailbox(); 2263 ax.mId = 69105; 2264 2265 // Message mt2 is an orphan, as is mt4 2266 Message m1 = createMessage(mMockContext, a1, true, false, Message.FLAG_LOADED_COMPLETE); 2267 Message m2 = createMessage(mMockContext, a2, true, false, Message.FLAG_LOADED_COMPLETE); 2268 Message m3 = createMessage(mMockContext, a3, true, false, Message.FLAG_LOADED_COMPLETE); 2269 Message m4 = createMessage(mMockContext, a4, true, false, Message.FLAG_LOADED_COMPLETE); 2270 Message m5 = createMessage(mMockContext, a5, true, false, Message.FLAG_LOADED_COMPLETE); 2271 Message mx = createMessage(mMockContext, ax, true, false, Message.FLAG_LOADED_COMPLETE); 2272 2273 // Two orphan policies 2274 Policy p1 = new Policy(); 2275 p1.save(mMockContext); 2276 Policy p2 = new Policy(); 2277 p2.save(mMockContext); 2278 2279 // We don't want anything cached or the tests below won't work. Note 2280 // that 2281 // deleteUnlinked is only called by EmailProvider when the caches are 2282 // empty 2283 ContentCache.invalidateAllCaches(); 2284 // Delete orphaned mailboxes/messages/policies 2285 EmailProvider.deleteUnlinked(db, Mailbox.TABLE_NAME, MailboxColumns.ACCOUNT_KEY, 2286 AccountColumns._ID, Account.TABLE_NAME); 2287 EmailProvider.deleteUnlinked(db, Message.TABLE_NAME, MessageColumns.ACCOUNT_KEY, 2288 AccountColumns._ID, Account.TABLE_NAME); 2289 EmailProvider.deleteUnlinked(db, Policy.TABLE_NAME, PolicyColumns._ID, 2290 AccountColumns.POLICY_KEY, Account.TABLE_NAME); 2291 2292 // Make sure the orphaned mailboxes are gone 2293 assertNull(Mailbox.restoreMailboxWithId(mMockContext, a1.mId)); 2294 assertNotNull(Mailbox.restoreMailboxWithId(mMockContext, a2.mId)); 2295 assertNull(Mailbox.restoreMailboxWithId(mMockContext, a3.mId)); 2296 assertNotNull(Mailbox.restoreMailboxWithId(mMockContext, a4.mId)); 2297 assertNotNull(Mailbox.restoreMailboxWithId(mMockContext, a5.mId)); 2298 assertNull(Mailbox.restoreMailboxWithId(mMockContext, ax.mId)); 2299 2300 // Make sure orphaned messages are gone 2301 assertNull(Message.restoreMessageWithId(mMockContext, m1.mId)); 2302 assertNotNull(Message.restoreMessageWithId(mMockContext, m2.mId)); 2303 assertNull(Message.restoreMessageWithId(mMockContext, m3.mId)); 2304 assertNotNull(Message.restoreMessageWithId(mMockContext, m4.mId)); 2305 assertNotNull(Message.restoreMessageWithId(mMockContext, m5.mId)); 2306 assertNull(Message.restoreMessageWithId(mMockContext, mx.mId)); 2307 2308 // Make sure orphaned policies are gone 2309 assertNull(Policy.restorePolicyWithId(mMockContext, p1.mId)); 2310 assertNull(Policy.restorePolicyWithId(mMockContext, p2.mId)); 2311 a = Account.restoreAccountWithId(mMockContext, a.mId); 2312 assertNotNull(Policy.restorePolicyWithId(mMockContext, a.mPolicyKey)); 2313 } 2314 } 2315