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