MailboxFinderTest.java revision a7bc0319a75184ad706bb35c049af107ac3688e6
1/* 2 * Copyright (C) 2010 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.activity; 18 19import com.android.email.Controller; 20import com.android.email.DBTestHelper; 21import com.android.email.Email; 22import com.android.email.TestUtils; 23import com.android.email.provider.ProviderTestUtils; 24import com.android.emailcommon.mail.MessagingException; 25import com.android.emailcommon.provider.EmailContent; 26import com.android.emailcommon.provider.EmailContent.Account; 27import com.android.emailcommon.provider.EmailContent.Mailbox; 28 29import android.content.Context; 30import android.test.InstrumentationTestCase; 31import android.test.ProviderTestCase2; 32import android.test.suitebuilder.annotation.LargeTest; 33 34/** 35 * Test case for {@link MailboxFinder}. 36 * 37 * We need to use {@link InstrumentationTestCase} so that we can create AsyncTasks on the UI thread 38 * using {@link InstrumentationTestCase#runTestOnUiThread}. This class also needs an isolated 39 * context, which is provided by {@link ProviderTestCase2}. We can't derive from two classes, 40 * so we just copy the code for an isolate context to here. 41 */ 42@LargeTest 43public class MailboxFinderTest extends InstrumentationTestCase { 44 private static final int TIMEOUT = 10; // in seconds 45 46 // Test target 47 private MailboxFinder mMailboxFinder; 48 49 // Isolted Context for providers. 50 private Context mProviderContext; 51 52 // Mock to track callback invocations. 53 private MockController mMockController; 54 private MockCallback mCallback; 55 56 private Context getContext() { 57 return getInstrumentation().getTargetContext(); 58 } 59 60 @Override 61 protected void setUp() throws Exception { 62 super.setUp(); 63 64 mProviderContext = DBTestHelper.ProviderContextSetupHelper.getProviderContext( 65 getInstrumentation().getTargetContext()); 66 mCallback = new MockCallback(); 67 mMockController = new MockController(getContext()); 68 Controller.injectMockControllerForTest(mMockController); 69 assertEquals(0, mMockController.getResultCallbacksForTest().size()); 70 } 71 72 @Override 73 protected void tearDown() throws Exception { 74 super.tearDown(); 75 if (mMailboxFinder != null) { 76 mMailboxFinder.cancel(); 77 78 // MailboxFinder should unregister its listener when closed. 79 checkControllerResultRemoved(mMockController); 80 } 81 mMockController.cleanupForTest(); 82 Controller.injectMockControllerForTest(null); 83 } 84 85 /** 86 * Make sure no {@link MailboxFinder.Callback} is left registered to the controller. 87 */ 88 private static void checkControllerResultRemoved(Controller controller) { 89 for (Controller.Result callback : controller.getResultCallbacksForTest()) { 90 assertFalse(callback instanceof MailboxFinder.Callback); 91 } 92 } 93 94 /** 95 * Create an account and returns the ID. 96 */ 97 private long createAccount(boolean securityHold) { 98 Account acct = ProviderTestUtils.setupAccount("acct1", false, mProviderContext); 99 if (securityHold) { 100 acct.mFlags |= Account.FLAGS_SECURITY_HOLD; 101 } 102 acct.save(mProviderContext); 103 return acct.mId; 104 } 105 106 /** 107 * Create a mailbox and return the ID. 108 */ 109 private long createMailbox(long accountId, int mailboxType) { 110 EmailContent.Mailbox box = new EmailContent.Mailbox(); 111 box.mDisplayName = "mailbox"; 112 box.mAccountKey = accountId; 113 box.mType = mailboxType; 114 box.mFlagVisible = true; 115 box.mVisibleLimit = Email.VISIBLE_LIMIT_DEFAULT; 116 box.save(mProviderContext); 117 return box.mId; 118 } 119 120 /** 121 * Create a {@link MailboxFinder} and kick it. 122 */ 123 private void createAndStartFinder(final long accountId, final int mailboxType) 124 throws Throwable { 125 runTestOnUiThread(new Runnable() { 126 @Override 127 public void run() { 128 mMailboxFinder = new MailboxFinder(mProviderContext, accountId, mailboxType, 129 mCallback); 130 mMailboxFinder.startLookup(); 131 assertTrue(mMailboxFinder.isStartedForTest()); 132 } 133 }); 134 } 135 136 /** 137 * Wait until any of the {@link MailboxFinder.Callback} method or 138 * {@link Controller#updateMailboxList} is called. 139 */ 140 private void waitUntilCallbackCalled() { 141 TestUtils.waitUntil("", new TestUtils.Condition() { 142 @Override 143 public boolean isMet() { 144 return mCallback.isAnyMethodCalled() || mMockController.mCalledUpdateMailboxList; 145 } 146 }, TIMEOUT); 147 } 148 149 /** 150 * Test: Account is on security hold. 151 */ 152 public void testSecurityHold() throws Throwable { 153 final long accountId = createAccount(true); 154 155 createAndStartFinder(accountId, Mailbox.TYPE_INBOX); 156 waitUntilCallbackCalled(); 157 158 assertFalse(mCallback.mCalledAccountNotFound); 159 assertTrue(mCallback.mCalledAccountSecurityHold); 160 assertFalse(mCallback.mCalledMailboxFound); 161 assertFalse(mCallback.mCalledMailboxNotFound); 162 assertFalse(mMockController.mCalledUpdateMailboxList); 163 164 assertTrue(mMailboxFinder.isReallyClosedForTest()); 165 } 166 167 /** 168 * Test: Account does not exist. 169 */ 170 public void testAccountNotFound() throws Throwable { 171 createAndStartFinder(123456, Mailbox.TYPE_INBOX); // No such account. 172 waitUntilCallbackCalled(); 173 174 assertTrue(mCallback.mCalledAccountNotFound); 175 assertFalse(mCallback.mCalledAccountSecurityHold); 176 assertFalse(mCallback.mCalledMailboxFound); 177 assertFalse(mCallback.mCalledMailboxNotFound); 178 assertFalse(mMockController.mCalledUpdateMailboxList); 179 180 assertTrue(mMailboxFinder.isReallyClosedForTest()); 181 } 182 183 /** 184 * Test: Mailbox found 185 */ 186 public void testMailboxFound() throws Throwable { 187 final long accountId = createAccount(false); 188 final long mailboxId = createMailbox(accountId, Mailbox.TYPE_INBOX); 189 190 createAndStartFinder(accountId, Mailbox.TYPE_INBOX); 191 waitUntilCallbackCalled(); 192 193 assertFalse(mCallback.mCalledAccountNotFound); 194 assertFalse(mCallback.mCalledAccountSecurityHold); 195 assertTrue(mCallback.mCalledMailboxFound); 196 assertFalse(mCallback.mCalledMailboxNotFound); 197 assertFalse(mMockController.mCalledUpdateMailboxList); 198 199 assertEquals(accountId, mCallback.mAccountId); 200 assertEquals(mailboxId, mCallback.mMailboxId); 201 202 assertTrue(mMailboxFinder.isReallyClosedForTest()); 203 } 204 205 /** 206 * Common initialization for tests that involves network-lookup. 207 */ 208 private void prepareForNetworkLookupTest(final long accountId) throws Throwable { 209 // Look for non-existing mailbox. 210 createAndStartFinder(accountId, Mailbox.TYPE_INBOX); 211 waitUntilCallbackCalled(); 212 213 // Mailbox not found, so the finder should try network-looking up. 214 assertFalse(mCallback.mCalledAccountNotFound); 215 assertFalse(mCallback.mCalledAccountSecurityHold); 216 assertFalse(mCallback.mCalledMailboxFound); 217 assertFalse(mCallback.mCalledMailboxNotFound); 218 219 // Controller.updateMailboxList() should have been called, with the account id. 220 assertTrue(mMockController.mCalledUpdateMailboxList); 221 assertEquals(accountId, mMockController.mPassedAccountId); 222 223 mMockController.reset(); 224 225 assertFalse(mMailboxFinder.isReallyClosedForTest()); // Not closed yet 226 } 227 228 /** 229 * Test: Account exists, but mailbox doesn't -> Get {@link Controller} to update the mailbox 230 * list -> mailbox still doesn't exist. 231 */ 232 public void testMailboxNotFound() throws Throwable { 233 final long accountId = createAccount(false); 234 235 prepareForNetworkLookupTest(accountId); 236 237 // Imitate the mCallback... 238 runTestOnUiThread(new Runnable() { 239 @Override 240 public void run() { 241 mMailboxFinder.getControllerResultsForTest().updateMailboxListCallback( 242 null, accountId, 100); 243 } 244 }); 245 246 // Task should have started, so wait for the response... 247 waitUntilCallbackCalled(); 248 249 assertFalse(mCallback.mCalledAccountNotFound); 250 assertFalse(mCallback.mCalledAccountSecurityHold); 251 assertFalse(mCallback.mCalledMailboxFound); 252 assertTrue(mCallback.mCalledMailboxNotFound); 253 assertFalse(mMockController.mCalledUpdateMailboxList); 254 255 assertTrue(mMailboxFinder.isReallyClosedForTest()); 256 } 257 258 /** 259 * Test: Account exists, but mailbox doesn't -> Get {@link Controller} to update the mailbox 260 * list -> found mailbox this time. 261 */ 262 public void testMailboxFoundOnNetwork() throws Throwable { 263 final long accountId = createAccount(false); 264 265 prepareForNetworkLookupTest(accountId); 266 267 // Create mailbox at this point. 268 final long mailboxId = createMailbox(accountId, Mailbox.TYPE_INBOX); 269 270 // Imitate the mCallback... 271 runTestOnUiThread(new Runnable() { 272 @Override 273 public void run() { 274 mMailboxFinder.getControllerResultsForTest().updateMailboxListCallback( 275 null, accountId, 100); 276 } 277 }); 278 279 // Task should have started, so wait for the response... 280 waitUntilCallbackCalled(); 281 282 assertFalse(mCallback.mCalledAccountNotFound); 283 assertFalse(mCallback.mCalledAccountSecurityHold); 284 assertTrue(mCallback.mCalledMailboxFound); 285 assertFalse(mCallback.mCalledMailboxNotFound); 286 assertFalse(mMockController.mCalledUpdateMailboxList); 287 288 assertEquals(accountId, mCallback.mAccountId); 289 assertEquals(mailboxId, mCallback.mMailboxId); 290 291 assertTrue(mMailboxFinder.isReallyClosedForTest()); 292 } 293 294 /** 295 * Test: Account exists, but mailbox doesn't -> Get {@link Controller} to update the mailbox 296 * list -> network error. 297 */ 298 public void testMailboxNotFoundNetworkError() throws Throwable { 299 final long accountId = createAccount(false); 300 301 prepareForNetworkLookupTest(accountId); 302 303 // Imitate the mCallback... 304 runTestOnUiThread(new Runnable() { 305 @Override 306 public void run() { 307 // network error. 308 mMailboxFinder.getControllerResultsForTest().updateMailboxListCallback( 309 new MessagingException("Network error"), accountId, 0); 310 } 311 }); 312 313 assertFalse(mCallback.mCalledAccountNotFound); 314 assertFalse(mCallback.mCalledAccountSecurityHold); 315 assertFalse(mCallback.mCalledMailboxFound); 316 assertTrue(mCallback.mCalledMailboxNotFound); 317 assertFalse(mMockController.mCalledUpdateMailboxList); 318 319 assertTrue(mMailboxFinder.isReallyClosedForTest()); 320 } 321 322 /** 323 * Test: updateMailboxListCallback won't respond to update of a non-target account. 324 */ 325 public void testUpdateMailboxListCallbackNonTarget() throws Throwable { 326 final long accountId = createAccount(false); 327 328 prepareForNetworkLookupTest(accountId); 329 330 // Callback from Controller, but for a different account. 331 runTestOnUiThread(new Runnable() { 332 @Override 333 public void run() { 334 long nonTargetAccountId = accountId + 1; 335 mMailboxFinder.getControllerResultsForTest().updateMailboxListCallback( 336 new MessagingException("Network error"), nonTargetAccountId, 0); 337 } 338 }); 339 340 // Nothing happened. 341 assertFalse(mCallback.mCalledAccountNotFound); 342 assertFalse(mCallback.mCalledAccountSecurityHold); 343 assertFalse(mCallback.mCalledMailboxFound); 344 assertFalse(mCallback.mCalledMailboxNotFound); 345 assertFalse(mMockController.mCalledUpdateMailboxList); 346 347 assertFalse(mMailboxFinder.isReallyClosedForTest()); // Not closed yet 348 } 349 350 /** 351 * Test: Mailbox not found (mailbox of different type exists) 352 */ 353 public void testMailboxNotFound2() throws Throwable { 354 final long accountId = createAccount(false); 355 final long mailboxId = createMailbox(accountId, Mailbox.TYPE_DRAFTS); 356 357 createAndStartFinder(accountId, Mailbox.TYPE_INBOX); 358 waitUntilCallbackCalled(); 359 360 assertFalse(mCallback.mCalledAccountNotFound); 361 assertFalse(mCallback.mCalledAccountSecurityHold); 362 assertFalse(mCallback.mCalledMailboxFound); 363 assertFalse(mCallback.mCalledMailboxNotFound); 364 assertTrue(mMockController.mCalledUpdateMailboxList); 365 366 assertFalse(mMailboxFinder.isReallyClosedForTest()); // Not closed yet -- network lookup. 367 } 368 369 /** 370 * Test: Call {@link MailboxFinder#startLookup()} twice, which should throw an ISE. 371 */ 372 public void testRunTwice() throws Throwable { 373 final long accountId = createAccount(true); 374 375 createAndStartFinder(accountId, Mailbox.TYPE_INBOX); 376 try { 377 mMailboxFinder.startLookup(); 378 fail("Expected exception not thrown"); 379 } catch (IllegalStateException ok) { 380 } 381 } 382 383 public void testCancel() throws Throwable { 384 final long accountId = createAccount(true); 385 386 createAndStartFinder(accountId, Mailbox.TYPE_INBOX); 387 mMailboxFinder.cancel(); 388 assertTrue(mMailboxFinder.isReallyClosedForTest()); 389 } 390 391 /** 392 * A {@link Controller} that remembers if updateMailboxList has been called. 393 */ 394 private static class MockController extends Controller { 395 public volatile long mPassedAccountId; 396 public volatile boolean mCalledUpdateMailboxList; 397 398 public void reset() { 399 mPassedAccountId = -1; 400 mCalledUpdateMailboxList = false; 401 } 402 403 protected MockController(Context context) { 404 super(context); 405 } 406 407 @Override 408 public void updateMailboxList(long accountId) { 409 mCalledUpdateMailboxList = true; 410 mPassedAccountId = accountId; 411 } 412 } 413 414 /** 415 * Callback that logs what method is called with what arguments. 416 */ 417 private static class MockCallback implements MailboxFinder.Callback { 418 public volatile boolean mCalledAccountNotFound; 419 public volatile boolean mCalledAccountSecurityHold; 420 public volatile boolean mCalledMailboxFound; 421 public volatile boolean mCalledMailboxNotFound; 422 423 public volatile long mAccountId = -1; 424 public volatile long mMailboxId = -1; 425 426 public boolean isAnyMethodCalled() { 427 return mCalledAccountNotFound || mCalledAccountSecurityHold || mCalledMailboxFound 428 || mCalledMailboxNotFound; 429 } 430 431 @Override 432 public void onAccountNotFound() { 433 mCalledAccountNotFound = true; 434 } 435 436 @Override 437 public void onAccountSecurityHold(long accountId) { 438 mCalledAccountSecurityHold = true; 439 mAccountId = accountId; 440 } 441 442 @Override 443 public void onMailboxFound(long accountId, long mailboxId) { 444 mCalledMailboxFound = true; 445 mAccountId = accountId; 446 mMailboxId = mailboxId; 447 } 448 449 @Override 450 public void onMailboxNotFound(long accountId) { 451 mCalledMailboxNotFound = true; 452 mAccountId = accountId; 453 } 454 } 455} 456