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