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 ProviderTests()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 MockContext2(Context mockContext, Context realContext)92 public MockContext2(Context mockContext, Context realContext) { 93 super(mockContext); 94 mRealContext = realContext; 95 } 96 97 @Override getApplicationContext()98 public Context getApplicationContext() { 99 return this; 100 } 101 102 @Override getPackageName()103 public String getPackageName() { 104 return mRealContext.getPackageName(); 105 } 106 107 @Override getSystemService(String name)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 setUp()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 tearDown()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}. */ setMinusOneToMessageCounts()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. */ getMessageCount(long mailboxId)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. */ createMessage( Context c, Mailbox b, boolean starred, boolean read, int flagLoaded)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 testAccountSave()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 testAccountSaveHostAuth()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 testAccountGetHostAuthSend()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 testAccountGetHostAuthRecv()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 */ testAccountParcel()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 getEclairStyleShortcutUri(Account account)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 testGetProtocol()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 testAccountIsValidId()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 */ getUnreadCount(long mailboxId)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 */ loadBodyForMessageId(long messageId)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 testMessageSave()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 testMessageWithAttachment()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 testMessageSaveWithJustAttachments()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 */ testMessageSaveAddsSnippet()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 */ testAccountDelete()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 */ testLookupBodyIdWithMessageId()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 */ testUpdateBodyWithMessageId()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 */ testBodyRetrieve()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 */ testDeleteBody()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 */ testDeleteOrphanBodies()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 */ count(Context context, Uri uri, String selection, String[] selectionArgs)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 testMessageQueryWithLimit()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 */ testDeleteOrphanMessages()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 */ testMessageDelete()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 */ testSyncedMessageDelete()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 */ testMessageUpdate()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 */ testCascadeDeleteAccount()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 */ testCascadeDeleteMailbox()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 */ testCascadeMessageDelete()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 */ testCreateUniqueFile()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 */ testGetAttachmentByMessageIdUri()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 */ testDeleteAttachmentByMessageIdUri()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 testGetDefaultAccountNoneExplicitlySet()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 */ testGetDefaultAccountWithLastUsedAccount()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 setupUnreadMessage(String name, long accountId, long mailboxId, boolean addBody, boolean saveIt, Context context)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 testUnreadCountTriggers()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 */ testCreateIndex()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 testDatabaseCorruptionRecovery()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 testBodyDatabaseCorruptionRecovery()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 testAccountIsSecurityHold()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 testClearAccountHoldFlags()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 createMessage(Context c, Mailbox b, boolean starred, boolean read)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 testGetKeyColumnLong()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 testGetAccountIdForMessageId()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 testGetAccountForMessageId()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 testGetAccountGetInboxIdTest()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 */ testIllegalUri()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 */ testRecalculateMessageCounts()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 */ createAccount(Context c, String name, HostAuth recvAuth, HostAuth sendAuth)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 */ createMailbox( Context c, String displayName, String serverId, long parentKey, long accountId)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 */ assertEquals(Mailbox expected, Mailbox actual)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 */ assertEqualsExceptServerId(Mailbox expected, Mailbox actual, String serverId)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 */ amAccountListHasAccount( android.accounts.Account[] amAccountList, Account account, Context context)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 */ createTypeMailbox(Context c, long accountId, int type)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 testCleanupOrphans()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