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