1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.email; 18 19 import android.content.Context; 20 import android.net.Uri; 21 import android.test.ProviderTestCase2; 22 23 import com.android.email.provider.ContentCache; 24 import com.android.email.provider.EmailProvider; 25 import com.android.email.provider.ProviderTestUtils; 26 import com.android.emailcommon.provider.Account; 27 import com.android.emailcommon.provider.EmailContent; 28 import com.android.emailcommon.provider.EmailContent.Body; 29 import com.android.emailcommon.provider.EmailContent.Message; 30 import com.android.emailcommon.provider.HostAuth; 31 import com.android.emailcommon.provider.Mailbox; 32 33 import java.util.Locale; 34 import java.util.concurrent.ExecutionException; 35 36 /** 37 * Tests of the Controller class that depend on the underlying provider. 38 * 39 * NOTE: It would probably make sense to rewrite this using a MockProvider, instead of the 40 * ProviderTestCase (which is a real provider running on a temp database). This would be more of 41 * a true "unit test". 42 * 43 * You can run this entire test case with: 44 * runtest -c com.android.email.ControllerProviderOpsTests email 45 */ 46 public class ControllerProviderOpsTests extends ProviderTestCase2<EmailProvider> { 47 48 private Context mProviderContext; 49 private Context mContext; 50 private TestController mTestController; 51 52 53 public ControllerProviderOpsTests() { 54 super(EmailProvider.class, EmailContent.AUTHORITY); 55 } 56 57 @Override 58 public void setUp() throws Exception { 59 super.setUp(); 60 mProviderContext = getMockContext(); 61 mContext = getContext(); 62 mTestController = new TestController(mProviderContext, mContext); 63 // Invalidate all caches, since we reset the database for each test 64 ContentCache.invalidateAllCaches(); 65 } 66 67 @Override 68 public void tearDown() throws Exception { 69 super.tearDown(); 70 mTestController.cleanupForTest(); 71 } 72 73 /** 74 * Lightweight subclass of the Controller class allows injection of mock context 75 */ 76 public static class TestController extends Controller { 77 78 protected TestController(Context providerContext, Context systemContext) { 79 super(systemContext); 80 setProviderContext(providerContext); 81 } 82 } 83 84 /** 85 * These are strings that should not change per locale. 86 */ 87 public void testGetMailboxServerName() { 88 assertEquals("", Controller.getMailboxServerName(mContext, -1)); 89 90 assertEquals("Inbox", Controller.getMailboxServerName(mContext, Mailbox.TYPE_INBOX)); 91 assertEquals("Outbox", Controller.getMailboxServerName(mContext, Mailbox.TYPE_OUTBOX)); 92 assertEquals("Trash", Controller.getMailboxServerName(mContext, Mailbox.TYPE_TRASH)); 93 assertEquals("Sent", Controller.getMailboxServerName(mContext, Mailbox.TYPE_SENT)); 94 assertEquals("Junk", Controller.getMailboxServerName(mContext, Mailbox.TYPE_JUNK)); 95 96 // Now try again with translation 97 Locale savedLocale = Locale.getDefault(); 98 Locale.setDefault(Locale.FRANCE); 99 assertEquals("Inbox", Controller.getMailboxServerName(mContext, Mailbox.TYPE_INBOX)); 100 assertEquals("Outbox", Controller.getMailboxServerName(mContext, Mailbox.TYPE_OUTBOX)); 101 assertEquals("Trash", Controller.getMailboxServerName(mContext, Mailbox.TYPE_TRASH)); 102 assertEquals("Sent", Controller.getMailboxServerName(mContext, Mailbox.TYPE_SENT)); 103 assertEquals("Junk", Controller.getMailboxServerName(mContext, Mailbox.TYPE_JUNK)); 104 Locale.setDefault(savedLocale); 105 } 106 107 /** 108 * Test of Controller.createMailbox(). 109 * Sunny day test only - creates a mailbox that does not exist. 110 * Does not test duplication, bad accountID, or any other bad input. 111 */ 112 public void testCreateMailbox() { 113 // safety check that system mailboxes don't exist ... 114 assertEquals(Mailbox.NO_MAILBOX, 115 Mailbox.findMailboxOfType(mProviderContext, 1L, Mailbox.TYPE_DRAFTS)); 116 assertEquals(Mailbox.NO_MAILBOX, 117 Mailbox.findMailboxOfType(mProviderContext, 1L, Mailbox.TYPE_SENT)); 118 119 long testMailboxId; 120 Mailbox testMailbox; 121 122 // Test creating "drafts" mailbox 123 mTestController.createMailbox(1L, Mailbox.TYPE_DRAFTS); 124 testMailboxId = Mailbox.findMailboxOfType(mProviderContext, 1L, Mailbox.TYPE_DRAFTS); 125 assertTrue(testMailboxId != Mailbox.NO_MAILBOX); 126 testMailbox = Mailbox.restoreMailboxWithId(mProviderContext, testMailboxId); 127 assertNotNull(testMailbox); 128 assertEquals(8, testMailbox.mFlags); // Flags should be "holds mail" 129 assertEquals(-1L, testMailbox.mParentKey); // Parent is off the top-level 130 131 // Test creating "sent" mailbox; same as drafts 132 mTestController.createMailbox(1L, Mailbox.TYPE_SENT); 133 testMailboxId = Mailbox.findMailboxOfType(mProviderContext, 1L, Mailbox.TYPE_SENT); 134 assertTrue(testMailboxId != Mailbox.NO_MAILBOX); 135 testMailbox = Mailbox.restoreMailboxWithId(mProviderContext, testMailboxId); 136 assertNotNull(testMailbox); 137 assertEquals(8, testMailbox.mFlags); // Flags should be "holds mail" 138 assertEquals(-1L, testMailbox.mParentKey); // Parent is off the top-level 139 } 140 141 /** 142 * Test of Controller.findOrCreateMailboxOfType(). 143 * Checks: 144 * - finds correctly the ID of existing mailbox 145 * - creates non-existing mailbox 146 * - creates only once a new mailbox 147 * - when accountId or mailboxType are -1, returns NO_MAILBOX 148 */ 149 public void testFindOrCreateMailboxOfType() { 150 Account account = ProviderTestUtils.setupAccount("mailboxid", true, mProviderContext); 151 long accountId = account.mId; 152 Mailbox box = ProviderTestUtils.setupMailbox("box", accountId, false, mProviderContext); 153 final int boxType = Mailbox.TYPE_TRASH; 154 box.mType = boxType; 155 box.save(mProviderContext); 156 long boxId = box.mId; 157 158 long testBoxId = mTestController.findOrCreateMailboxOfType(accountId, boxType); 159 160 // check it found the right mailbox id 161 assertEquals(boxId, testBoxId); 162 163 long boxId2 = mTestController.findOrCreateMailboxOfType(accountId, Mailbox.TYPE_DRAFTS); 164 assertTrue("mailbox created", boxId2 != Mailbox.NO_MAILBOX); 165 assertTrue("with different id", testBoxId != boxId2); 166 167 // check it doesn't create twice when existing 168 long boxId3 = mTestController.findOrCreateMailboxOfType(accountId, Mailbox.TYPE_DRAFTS); 169 assertEquals("don't create if exists", boxId3, boxId2); 170 171 // check invalid aruments 172 assertEquals(Mailbox.NO_MAILBOX, 173 mTestController.findOrCreateMailboxOfType(-1, Mailbox.TYPE_DRAFTS)); 174 assertEquals(Mailbox.NO_MAILBOX, mTestController.findOrCreateMailboxOfType(accountId, -1)); 175 } 176 177 /** 178 * Test the "move message" function. 179 */ 180 public void testMoveMessage() throws InterruptedException, ExecutionException { 181 Account account1 = ProviderTestUtils.setupAccount("message-move", true, mProviderContext); 182 long account1Id = account1.mId; 183 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mProviderContext); 184 long box1Id = box1.mId; 185 Mailbox box2 = ProviderTestUtils.setupMailbox("box2", account1Id, true, mProviderContext); 186 long box2Id = box2.mId; 187 Mailbox boxDest = ProviderTestUtils.setupMailbox("d", account1Id, true, mProviderContext); 188 long boxDestId = boxDest.mId; 189 190 Message message1 = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, 191 true, mProviderContext); 192 Message message2 = ProviderTestUtils.setupMessage("message2", account1Id, box2Id, false, 193 true, mProviderContext); 194 long message1Id = message1.mId; 195 long message2Id = message2.mId; 196 197 // Because moveMessage runs asynchronously, call get() to force it to complete 198 mTestController.moveMessages(new long[] { message1Id, message2Id }, boxDestId).get(); 199 200 // now read back a fresh copy and confirm it's in the trash 201 assertEquals(boxDestId, EmailContent.Message.restoreMessageWithId(mProviderContext, 202 message1Id).mMailboxKey); 203 assertEquals(boxDestId, EmailContent.Message.restoreMessageWithId(mProviderContext, 204 message2Id).mMailboxKey); 205 } 206 207 /** 208 * Test the "delete message" function. Sunny day: 209 * - message/mailbox/account all exist 210 * - trash mailbox exists 211 */ 212 public void testDeleteMessage() { 213 Account account1 = ProviderTestUtils.setupAccount("message-delete", true, mProviderContext); 214 long account1Id = account1.mId; 215 Mailbox box = ProviderTestUtils.setupMailbox("box1", account1Id, true, mProviderContext); 216 long boxId = box.mId; 217 218 Mailbox trashBox = ProviderTestUtils.setupMailbox("box2", account1Id, false, 219 mProviderContext); 220 trashBox.mType = Mailbox.TYPE_TRASH; 221 trashBox.save(mProviderContext); 222 long trashBoxId = trashBox.mId; 223 224 Mailbox draftBox = ProviderTestUtils.setupMailbox("box3", account1Id, false, 225 mProviderContext); 226 draftBox.mType = Mailbox.TYPE_DRAFTS; 227 draftBox.save(mProviderContext); 228 long draftBoxId = draftBox.mId; 229 230 { 231 // Case 1: Message in a regular mailbox, account known. 232 Message message = ProviderTestUtils.setupMessage("message1", account1Id, boxId, false, 233 true, mProviderContext); 234 long messageId = message.mId; 235 236 mTestController.deleteMessageSync(messageId); 237 238 // now read back a fresh copy and confirm it's in the trash 239 Message restored = EmailContent.Message.restoreMessageWithId(mProviderContext, 240 messageId); 241 assertEquals(trashBoxId, restored.mMailboxKey); 242 } 243 244 { 245 // Case 2: Already in trash 246 Message message = ProviderTestUtils.setupMessage("message3", account1Id, trashBoxId, 247 false, true, mProviderContext); 248 long messageId = message.mId; 249 250 mTestController.deleteMessageSync(messageId); 251 252 // Message should be deleted. 253 assertNull(EmailContent.Message.restoreMessageWithId(mProviderContext, messageId)); 254 } 255 256 { 257 // Case 3: Draft 258 Message message = ProviderTestUtils.setupMessage("message3", account1Id, draftBoxId, 259 false, true, mProviderContext); 260 long messageId = message.mId; 261 262 mTestController.deleteMessageSync(messageId); 263 264 // Message should be deleted. 265 assertNull(EmailContent.Message.restoreMessageWithId(mProviderContext, messageId)); 266 } 267 } 268 269 /** 270 * Test deleting message when there is no trash mailbox 271 */ 272 public void testDeleteMessageNoTrash() { 273 Account account1 = 274 ProviderTestUtils.setupAccount("message-delete-notrash", true, mProviderContext); 275 long account1Id = account1.mId; 276 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mProviderContext); 277 long box1Id = box1.mId; 278 279 Message message1 = 280 ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, true, 281 mProviderContext); 282 long message1Id = message1.mId; 283 284 mTestController.deleteMessageSync(message1Id); 285 286 // now read back a fresh copy and confirm it's in the trash 287 Message message1get = 288 EmailContent.Message.restoreMessageWithId(mProviderContext, message1Id); 289 290 // check the new mailbox and see if it looks right 291 assertFalse(-1 == message1get.mMailboxKey); 292 assertFalse(box1Id == message1get.mMailboxKey); 293 Mailbox mailbox2get = Mailbox.restoreMailboxWithId(mProviderContext, 294 message1get.mMailboxKey); 295 assertEquals(Mailbox.TYPE_TRASH, mailbox2get.mType); 296 } 297 298 /** 299 * Test read/unread flag 300 */ 301 public void testReadUnread() throws InterruptedException, ExecutionException { 302 Account account1 = ProviderTestUtils.setupAccount("read-unread", false, mProviderContext); 303 account1.mHostAuthRecv 304 = ProviderTestUtils.setupHostAuth("read-unread", 0, false, mProviderContext); 305 account1.save(mProviderContext); 306 long account1Id = account1.mId; 307 long box1Id = 2; 308 309 Message message1 = 310 ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, true, 311 mProviderContext); 312 long message1Id = message1.mId; 313 314 // test setting to "read" 315 mTestController.setMessageRead(message1Id, true).get(); 316 Message message1get = Message.restoreMessageWithId(mProviderContext, message1Id); 317 assertTrue(message1get.mFlagRead); 318 319 // test setting to "unread" 320 mTestController.setMessageRead(message1Id, false).get(); 321 message1get = Message.restoreMessageWithId(mProviderContext, message1Id); 322 assertFalse(message1get.mFlagRead); 323 324 // test setting to "read" 325 mTestController.setMessageRead(message1Id, true).get(); 326 message1get = Message.restoreMessageWithId(mProviderContext, message1Id); 327 assertTrue(message1get.mFlagRead); 328 } 329 330 /** 331 * Test favorites flag 332 */ 333 public void testFavorites() throws InterruptedException, ExecutionException { 334 Account account1 = ProviderTestUtils.setupAccount("favorites", false, mProviderContext); 335 account1.mHostAuthRecv 336 = ProviderTestUtils.setupHostAuth("favorites", 0, false, mProviderContext); 337 account1.save(mProviderContext); 338 long account1Id = account1.mId; 339 long box1Id = 2; 340 341 Message message1 = 342 ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, true, 343 mProviderContext); 344 long message1Id = message1.mId; 345 346 // test setting to "favorite" 347 mTestController.setMessageFavorite(message1Id, true).get(); 348 Message message1get = Message.restoreMessageWithId(mProviderContext, message1Id); 349 assertTrue(message1get.mFlagFavorite); 350 351 // test setting to "not favorite" 352 mTestController.setMessageFavorite(message1Id, false).get(); 353 message1get = Message.restoreMessageWithId(mProviderContext, message1Id); 354 assertFalse(message1get.mFlagFavorite); 355 356 // test setting to "favorite" 357 mTestController.setMessageFavorite(message1Id, true).get(); 358 message1get = Message.restoreMessageWithId(mProviderContext, message1Id); 359 assertTrue(message1get.mFlagFavorite); 360 } 361 362 public void testGetAndDeleteAttachmentMailbox() { 363 Mailbox box = mTestController.getAttachmentMailbox(); 364 assertNotNull(box); 365 Mailbox anotherBox = mTestController.getAttachmentMailbox(); 366 assertNotNull(anotherBox); 367 // We should always get back the same Mailbox row 368 assertEquals(box.mId, anotherBox.mId); 369 // Add two messages to this mailbox 370 ProviderTestUtils.setupMessage("message1", 0, box.mId, false, true, 371 mProviderContext); 372 ProviderTestUtils.setupMessage("message2", 0, box.mId, false, true, 373 mProviderContext); 374 // Make sure we can find them where they are expected 375 assertEquals(2, EmailContent.count(mProviderContext, Message.CONTENT_URI, 376 Message.MAILBOX_KEY + "=?", new String[] {Long.toString(box.mId)})); 377 // Delete them 378 mTestController.deleteAttachmentMessages(); 379 // Make sure they're gone 380 assertEquals(0, EmailContent.count(mProviderContext, Message.CONTENT_URI, 381 Message.MAILBOX_KEY + "=?", new String[] {Long.toString(box.mId)})); 382 } 383 384 /** 385 * Test wiping an account's synced data. Everything should go, but account & empty inbox. 386 * Also ensures that the remaining account and the remaining inbox have cleared their 387 * server sync keys, to force refresh eventually. 388 */ 389 public void testWipeSyncedData() { 390 Account account1 = ProviderTestUtils.setupAccount("wipe-synced-1", false, mProviderContext); 391 account1.mSyncKey = "account-1-sync-key"; 392 account1.save(mProviderContext); 393 long account1Id = account1.mId; 394 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, false, mProviderContext); 395 box1.mType = Mailbox.TYPE_INBOX; 396 box1.mSyncKey = "box-1-sync-key"; 397 box1.save(mProviderContext); 398 long box1Id = box1.mId; 399 Mailbox box2 = ProviderTestUtils.setupMailbox("box2", account1Id, true, mProviderContext); 400 long box2Id = box2.mId; 401 // An EAS account mailbox 402 Mailbox eas = ProviderTestUtils.setupMailbox("eas", account1Id, false, mProviderContext); 403 eas.mType = Mailbox.TYPE_EAS_ACCOUNT_MAILBOX; 404 eas.save(mProviderContext); 405 406 Account account2 = ProviderTestUtils.setupAccount("wipe-synced-2", false, mProviderContext); 407 account2.mSyncKey = "account-2-sync-key"; 408 account2.save(mProviderContext); 409 long account2Id = account2.mId; 410 Mailbox box3 = ProviderTestUtils.setupMailbox("box3", account2Id, false, mProviderContext); 411 box3.mSyncKey = "box-3-sync-key"; 412 box3.mType = Mailbox.TYPE_INBOX; 413 box3.save(mProviderContext); 414 long box3Id = box3.mId; 415 Mailbox box4 = ProviderTestUtils.setupMailbox("box4", account2Id, true, mProviderContext); 416 long box4Id = box4.mId; 417 418 // Now populate the 4 non-account boxes with messages 419 Message message = ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, 420 true, mProviderContext); 421 long message1Id = message.mId; 422 message = ProviderTestUtils.setupMessage("message2", account1Id, box2Id, false, 423 true, mProviderContext); 424 long message2Id = message.mId; 425 message = ProviderTestUtils.setupMessage("message3", account2Id, box3Id, false, 426 true, mProviderContext); 427 long message3Id = message.mId; 428 message = ProviderTestUtils.setupMessage("message4", account2Id, box4Id, false, 429 true, mProviderContext); 430 long message4Id = message.mId; 431 432 // Now wipe account 1's data 433 mTestController.deleteSyncedDataSync(account1Id); 434 435 // Confirm: Mailboxes gone (except account box), all messages gone, account survives 436 assertNull(Mailbox.restoreMailboxWithId(mProviderContext, box1Id)); 437 assertNull(Mailbox.restoreMailboxWithId(mProviderContext, box2Id)); 438 assertNotNull(Mailbox.restoreMailboxWithId(mProviderContext, eas.mId)); 439 assertNull(Message.restoreMessageWithId(mProviderContext, message1Id)); 440 assertNull(Message.restoreMessageWithId(mProviderContext, message2Id)); 441 account1 = Account.restoreAccountWithId(mProviderContext, account1Id); 442 assertNotNull(account1); 443 assertNull(account1.mSyncKey); 444 445 // Confirm: Other account survived 446 assertNotNull(Mailbox.restoreMailboxWithId(mProviderContext, box3Id)); 447 assertNotNull(Mailbox.restoreMailboxWithId(mProviderContext, box4Id)); 448 assertNotNull(Message.restoreMessageWithId(mProviderContext, message3Id)); 449 assertNotNull(Message.restoreMessageWithId(mProviderContext, message4Id)); 450 assertNotNull(Account.restoreAccountWithId(mProviderContext, account2Id)); 451 } 452 453 public void testLoadMessageFromUri() throws Exception { 454 // Create a simple message 455 Message msg = new Message(); 456 String text = "This is some text"; 457 msg.mText = text; 458 String sender = "sender (at) host.com"; 459 msg.mFrom = sender; 460 // Save this away 461 msg.save(mProviderContext); 462 463 Uri fileUri = ProviderTestUtils.createTempEmlFile(mProviderContext, msg, 464 mContext.getFilesDir()); 465 466 // Load the message via Controller and a Uri 467 Message loadedMsg = mTestController.loadMessageFromUri(fileUri); 468 469 // Check server id, mailbox key, account key, and from 470 assertNotNull(loadedMsg); 471 assertTrue(loadedMsg.mServerId.startsWith(Controller.ATTACHMENT_MESSAGE_UID_PREFIX)); 472 Mailbox box = mTestController.getAttachmentMailbox(); 473 assertNotNull(box); 474 assertEquals(box.mId, loadedMsg.mMailboxKey); 475 assertEquals(0, loadedMsg.mAccountKey); 476 assertEquals(loadedMsg.mFrom, sender); 477 // Check body text 478 String loadedMsgText = Body.restoreBodyTextWithMessageId(mProviderContext, loadedMsg.mId); 479 assertEquals(text, loadedMsgText); 480 } 481 482 /** 483 * Create a simple HostAuth with protocol 484 */ 485 private HostAuth setupSimpleHostAuth(String protocol) { 486 HostAuth hostAuth = new HostAuth(); 487 hostAuth.mProtocol = protocol; 488 return hostAuth; 489 } 490 491 public void testIsMessagingController() { 492 Account account1 = ProviderTestUtils.setupAccount("account1", false, 493 mProviderContext); 494 account1.mHostAuthRecv = setupSimpleHostAuth("eas"); 495 account1.save(mProviderContext); 496 assertFalse(mTestController.isMessagingController(account1)); 497 Account account2 = ProviderTestUtils.setupAccount("account2", false, 498 mProviderContext); 499 account2.mHostAuthRecv = setupSimpleHostAuth("imap"); 500 account2.save(mProviderContext); 501 assertTrue(mTestController.isMessagingController(account2)); 502 Account account3 = ProviderTestUtils.setupAccount("account3", false, 503 mProviderContext); 504 account3.mHostAuthRecv = setupSimpleHostAuth("pop3"); 505 account3.save(mProviderContext); 506 assertTrue(mTestController.isMessagingController(account3)); 507 Account account4 = ProviderTestUtils.setupAccount("account4", false, 508 mProviderContext); 509 account4.mHostAuthRecv = setupSimpleHostAuth("smtp"); 510 account4.save(mProviderContext); 511 assertFalse(mTestController.isMessagingController(account4)); 512 // There should be values for all of these accounts in the legacy map 513 assertNotNull(mTestController.mLegacyControllerMap.get(account1.mId)); 514 assertNotNull(mTestController.mLegacyControllerMap.get(account2.mId)); 515 assertNotNull(mTestController.mLegacyControllerMap.get(account3.mId)); 516 assertNotNull(mTestController.mLegacyControllerMap.get(account4.mId)); 517 // The map should have the expected values 518 assertFalse(mTestController.mLegacyControllerMap.get(account1.mId)); 519 assertTrue(mTestController.mLegacyControllerMap.get(account2.mId)); 520 assertTrue(mTestController.mLegacyControllerMap.get(account3.mId)); 521 assertFalse(mTestController.mLegacyControllerMap.get(account4.mId)); 522 // This second pass should pull values from the cache 523 assertFalse(mTestController.isMessagingController(account1)); 524 assertTrue(mTestController.isMessagingController(account2)); 525 assertTrue(mTestController.isMessagingController(account3)); 526 assertFalse(mTestController.isMessagingController(account4)); 527 } 528 529 /** 530 * TODO: releasing associated data (e.g. attachments, embedded images) 531 */ 532 } 533