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