Home | History | Annotate | Download | only in email
      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;
     18 
     19 import com.android.email.provider.ProviderTestUtils;
     20 import com.android.emailcommon.Logging;
     21 import com.android.emailcommon.mail.MessagingException;
     22 import com.android.emailcommon.provider.Account;
     23 
     24 import android.content.Context;
     25 import android.test.InstrumentationTestCase;
     26 import android.test.suitebuilder.annotation.LargeTest;
     27 
     28 import junit.framework.Assert;
     29 
     30 @LargeTest
     31 public class RefreshManagerTest extends InstrumentationTestCase {
     32     private static final int WAIT_UNTIL_TIMEOUT_SECONDS = 15;
     33     private MockClock mClock;
     34     private MockController mController;
     35     private RefreshManager mTarget;
     36     private RefreshListener mListener;
     37 
     38     private Context mContext;
     39 
     40     // Isolated Context for providers.
     41     private Context mProviderContext;
     42 
     43     private static final MessagingException EXCEPTION = new MessagingException("test");
     44 
     45     // Looks silly, but it'll make it more readable.
     46     private static final long ACCOUNT_1 = 1;
     47     private static final long ACCOUNT_2 = 2;
     48     private static final long MAILBOX_1 = 3;
     49     private static final long MAILBOX_2 = 4;
     50 
     51     @Override
     52     protected void setUp() throws Exception {
     53         super.setUp();
     54 
     55         mClock = new MockClock();
     56         mContext = getInstrumentation().getTargetContext();
     57         mController = new MockController(mContext);
     58         mListener = new RefreshListener();
     59         mProviderContext = DBTestHelper.ProviderContextSetupHelper.getProviderContext(mContext);
     60         mTarget = new RefreshManager(mProviderContext, mController, mClock, null);
     61         mTarget.registerListener(mListener);
     62     }
     63 
     64     @Override
     65     protected void tearDown() throws Exception {
     66         super.tearDown();
     67         mController.cleanupForTest();
     68     }
     69 
     70     public void testRegisterUnregisterListener() {
     71         // mListener is already registered
     72         assertEquals(1, mTarget.getListenersForTest().size());
     73 
     74         mTarget.unregisterListener(mListener);
     75         assertEquals(0, mTarget.getListenersForTest().size());
     76     }
     77 
     78     public void testRefreshStatus() {
     79         RefreshManager.Status s = new RefreshManager.Status();
     80         assertFalse(s.isRefreshing());
     81         assertTrue(s.canRefresh());
     82         assertEquals(0, s.getLastRefreshTime());
     83 
     84         // Request refresh
     85         s.onRefreshRequested();
     86         assertTrue(s.isRefreshing());
     87         assertFalse(s.canRefresh());
     88         assertEquals(0, s.getLastRefreshTime());
     89 
     90         // Refresh start
     91         s.onCallback(null, 0, mClock);
     92         assertTrue(s.isRefreshing());
     93         assertFalse(s.canRefresh());
     94         assertEquals(0, s.getLastRefreshTime());
     95 
     96         // Refresh 50% done -- nothing changes
     97         s.onCallback(null, 50, mClock);
     98         assertTrue(s.isRefreshing());
     99         assertFalse(s.canRefresh());
    100         assertEquals(0, s.getLastRefreshTime());
    101 
    102         // Refresh finish
    103         s.onCallback(null, 100, mClock);
    104         assertFalse(s.isRefreshing());
    105         assertTrue(s.canRefresh());
    106         assertEquals(mClock.mTime, s.getLastRefreshTime());
    107 
    108         // Refresh start without request
    109         s.onCallback(null, 0, mClock);
    110         assertTrue(s.isRefreshing());
    111         assertFalse(s.canRefresh());
    112         assertEquals(mClock.mTime, s.getLastRefreshTime());
    113 
    114         mClock.advance();
    115 
    116         // Refresh finish with error.
    117         s.onCallback(EXCEPTION, 0, mClock);
    118         assertFalse(s.isRefreshing());
    119         assertTrue(s.canRefresh());
    120         assertEquals(mClock.mTime, s.getLastRefreshTime());
    121     }
    122 
    123     public void testRefreshMailboxList() {
    124         // request refresh for account 1
    125         assertTrue(mTarget.refreshMailboxList(ACCOUNT_1));
    126 
    127         assertTrue(mListener.mCalledOnRefreshStatusChanged);
    128         assertFalse(mListener.mCalledOnConnectionError);
    129         assertEquals(ACCOUNT_1, mListener.mAccountId);
    130         assertEquals(-1, mListener.mMailboxId);
    131         mListener.reset();
    132         assertTrue(mController.mCalledUpdateMailboxList);
    133         assertEquals(ACCOUNT_1, mController.mAccountId);
    134         assertEquals(-1, mController.mMailboxId);
    135         mController.reset();
    136         assertTrue(mTarget.isMailboxListRefreshing(ACCOUNT_1));
    137         assertTrue(mTarget.isRefreshingAnyMailboxListForTest());
    138 
    139         // Request again -- shouldn't be accepted.
    140         assertFalse(mTarget.refreshMailboxList(ACCOUNT_1));
    141 
    142         assertFalse(mListener.mCalledOnRefreshStatusChanged);
    143         assertFalse(mListener.mCalledOnConnectionError);
    144         mListener.reset();
    145         assertFalse(mController.mCalledUpdateMailboxList);
    146         mController.reset();
    147 
    148         // request refresh for account 2
    149         assertTrue(mTarget.refreshMailboxList(ACCOUNT_2));
    150 
    151         assertTrue(mListener.mCalledOnRefreshStatusChanged);
    152         assertFalse(mListener.mCalledOnConnectionError);
    153         assertEquals(ACCOUNT_2, mListener.mAccountId);
    154         assertEquals(-1, mListener.mMailboxId);
    155         mListener.reset();
    156         assertTrue(mController.mCalledUpdateMailboxList);
    157         assertEquals(ACCOUNT_2, mController.mAccountId);
    158         assertEquals(-1, mController.mMailboxId);
    159         mController.reset();
    160         assertTrue(mTarget.isMailboxListRefreshing(ACCOUNT_2));
    161         assertTrue(mTarget.isRefreshingAnyMailboxListForTest());
    162 
    163         // Refreshing for account 1...
    164         mController.mListener.updateMailboxListCallback(null, ACCOUNT_1, 0);
    165 
    166         assertTrue(mListener.mCalledOnRefreshStatusChanged);
    167         assertFalse(mListener.mCalledOnConnectionError);
    168         assertEquals(ACCOUNT_1, mListener.mAccountId);
    169         assertEquals(-1, mListener.mMailboxId);
    170         mListener.reset();
    171         assertTrue(mTarget.isMailboxListRefreshing(ACCOUNT_1));
    172         assertEquals(0, mTarget.getMailboxListStatusForTest(ACCOUNT_1).getLastRefreshTime());
    173 
    174         // Done.
    175         LogUtils.w(Logging.LOG_TAG, "" + mController.mListener.getClass());
    176         mController.mListener.updateMailboxListCallback(null, ACCOUNT_1, 100);
    177 
    178         assertTrue(mListener.mCalledOnRefreshStatusChanged);
    179         assertFalse(mListener.mCalledOnConnectionError);
    180         assertEquals(ACCOUNT_1, mListener.mAccountId);
    181         assertEquals(-1, mListener.mMailboxId);
    182         mListener.reset();
    183         assertFalse(mTarget.isMailboxListRefreshing(ACCOUNT_1));
    184         assertEquals(mClock.mTime, mTarget.getMailboxListStatusForTest(ACCOUNT_1)
    185                 .getLastRefreshTime());
    186 
    187         // Check "any" method.
    188         assertTrue(mTarget.isRefreshingAnyMailboxListForTest()); // still refreshing account 2
    189 
    190         // Refreshing for account 2...
    191         mClock.advance();
    192 
    193         mController.mListener.updateMailboxListCallback(null, ACCOUNT_2, 0);
    194 
    195         assertTrue(mListener.mCalledOnRefreshStatusChanged);
    196         assertFalse(mListener.mCalledOnConnectionError);
    197         assertEquals(ACCOUNT_2, mListener.mAccountId);
    198         assertEquals(-1, mListener.mMailboxId);
    199         mListener.reset();
    200         assertTrue(mTarget.isMailboxListRefreshing(ACCOUNT_2));
    201         assertEquals(0, mTarget.getMailboxListStatusForTest(ACCOUNT_2).getLastRefreshTime());
    202 
    203         // Done with exception.
    204         mController.mListener.updateMailboxListCallback(EXCEPTION, ACCOUNT_2, 0);
    205 
    206         assertTrue(mListener.mCalledOnRefreshStatusChanged);
    207         assertTrue(mListener.mCalledOnConnectionError);
    208         assertEquals(ACCOUNT_2, mListener.mAccountId);
    209         assertEquals(-1, mListener.mMailboxId);
    210         assertEquals(MessagingExceptionStrings.getErrorString(mContext, EXCEPTION),
    211                 mListener.mMessage);
    212         mListener.reset();
    213         assertFalse(mTarget.isMailboxListRefreshing(ACCOUNT_2));
    214         assertEquals(mClock.mTime, mTarget.getMailboxListStatusForTest(ACCOUNT_2)
    215                 .getLastRefreshTime());
    216 
    217         // Check "any" method.
    218         assertFalse(mTarget.isRefreshingAnyMailboxListForTest());
    219     }
    220 
    221     public void testRefreshMessageList() {
    222         // request refresh mailbox 1
    223         assertTrue(mTarget.refreshMessageList(ACCOUNT_1, MAILBOX_1, false));
    224 
    225         assertTrue(mListener.mCalledOnRefreshStatusChanged);
    226         assertFalse(mListener.mCalledOnConnectionError);
    227         assertEquals(ACCOUNT_1, mListener.mAccountId);
    228         assertEquals(MAILBOX_1, mListener.mMailboxId);
    229         mListener.reset();
    230         assertTrue(mController.mCalledUpdateMailbox);
    231         assertEquals(ACCOUNT_1, mController.mAccountId);
    232         assertEquals(MAILBOX_1, mController.mMailboxId);
    233         mController.reset();
    234         assertTrue(mTarget.isMessageListRefreshing(MAILBOX_1));
    235         assertTrue(mTarget.isRefreshingAnyMessageListForTest());
    236 
    237         // Request again -- shouldn't be accepted.
    238         assertFalse(mTarget.refreshMessageList(ACCOUNT_1, MAILBOX_1, false));
    239 
    240         assertFalse(mListener.mCalledOnRefreshStatusChanged);
    241         assertFalse(mListener.mCalledOnConnectionError);
    242         mListener.reset();
    243         assertFalse(mController.mCalledUpdateMailbox);
    244         mController.reset();
    245 
    246         // request refresh mailbox 2
    247         assertTrue(mTarget.refreshMessageList(ACCOUNT_2, MAILBOX_2, false));
    248 
    249         assertTrue(mListener.mCalledOnRefreshStatusChanged);
    250         assertFalse(mListener.mCalledOnConnectionError);
    251         assertEquals(ACCOUNT_2, mListener.mAccountId);
    252         assertEquals(MAILBOX_2, mListener.mMailboxId);
    253         mListener.reset();
    254         assertTrue(mController.mCalledUpdateMailbox);
    255         assertEquals(ACCOUNT_2, mController.mAccountId);
    256         assertEquals(MAILBOX_2, mController.mMailboxId);
    257         mController.reset();
    258         assertTrue(mTarget.isMessageListRefreshing(MAILBOX_2));
    259         assertTrue(mTarget.isRefreshingAnyMessageListForTest());
    260 
    261         // Refreshing mailbox 1...
    262         mController.mListener.updateMailboxCallback(null, ACCOUNT_1, MAILBOX_1, 0, 0, null);
    263 
    264         assertTrue(mListener.mCalledOnRefreshStatusChanged);
    265         assertFalse(mListener.mCalledOnConnectionError);
    266         assertEquals(ACCOUNT_1, mListener.mAccountId);
    267         assertEquals(MAILBOX_1, mListener.mMailboxId);
    268         mListener.reset();
    269         assertTrue(mTarget.isMessageListRefreshing(MAILBOX_1));
    270         assertEquals(0, mTarget.getMessageListStatusForTest(MAILBOX_1).getLastRefreshTime());
    271 
    272         // Done.
    273         LogUtils.w(Logging.LOG_TAG, "" + mController.mListener.getClass());
    274         mController.mListener.updateMailboxCallback(null, ACCOUNT_1, MAILBOX_1, 100, 0, null);
    275 
    276         assertTrue(mListener.mCalledOnRefreshStatusChanged);
    277         assertFalse(mListener.mCalledOnConnectionError);
    278         assertEquals(ACCOUNT_1, mListener.mAccountId);
    279         assertEquals(MAILBOX_1, mListener.mMailboxId);
    280         mListener.reset();
    281         assertFalse(mTarget.isMessageListRefreshing(MAILBOX_1));
    282         assertEquals(mClock.mTime, mTarget.getMessageListStatusForTest(MAILBOX_1)
    283                 .getLastRefreshTime());
    284 
    285         // Check "any" method.
    286         assertTrue(mTarget.isRefreshingAnyMessageListForTest()); // still refreshing mailbox 2
    287 
    288         // Refreshing mailbox 2...
    289         mClock.advance();
    290 
    291         mController.mListener.updateMailboxCallback(null, ACCOUNT_2, MAILBOX_2, 0, 0, null);
    292 
    293         assertTrue(mListener.mCalledOnRefreshStatusChanged);
    294         assertFalse(mListener.mCalledOnConnectionError);
    295         assertEquals(ACCOUNT_2, mListener.mAccountId);
    296         assertEquals(MAILBOX_2, mListener.mMailboxId);
    297         mListener.reset();
    298         assertTrue(mTarget.isMessageListRefreshing(MAILBOX_2));
    299         assertEquals(0, mTarget.getMessageListStatusForTest(MAILBOX_2).getLastRefreshTime());
    300 
    301         // Done with exception.
    302         mController.mListener.updateMailboxCallback(EXCEPTION, ACCOUNT_2, MAILBOX_2, 0, 0, null);
    303 
    304         assertTrue(mListener.mCalledOnRefreshStatusChanged);
    305         assertTrue(mListener.mCalledOnConnectionError);
    306         assertEquals(ACCOUNT_2, mListener.mAccountId);
    307         assertEquals(MAILBOX_2, mListener.mMailboxId);
    308         assertEquals(MessagingExceptionStrings.getErrorString(mContext, EXCEPTION),
    309                 mListener.mMessage);
    310         mListener.reset();
    311         assertFalse(mTarget.isMessageListRefreshing(MAILBOX_2));
    312         assertEquals(mClock.mTime, mTarget.getMessageListStatusForTest(MAILBOX_2)
    313                 .getLastRefreshTime());
    314 
    315         // Check "any" method.
    316         assertFalse(mTarget.isRefreshingAnyMessageListForTest());
    317     }
    318 
    319     public void testSendPendingMessages() {
    320         // request sending for account 1
    321         assertTrue(mTarget.sendPendingMessages(ACCOUNT_1));
    322 
    323         assertTrue(mListener.mCalledOnRefreshStatusChanged);
    324         assertFalse(mListener.mCalledOnConnectionError);
    325         assertEquals(ACCOUNT_1, mListener.mAccountId);
    326         assertEquals(-1, mListener.mMailboxId);
    327         mListener.reset();
    328         assertTrue(mController.mCalledSendPendingMessages);
    329         assertEquals(ACCOUNT_1, mController.mAccountId);
    330         assertEquals(-1, mController.mMailboxId);
    331         mController.reset();
    332 
    333         // request sending for account 2
    334         assertTrue(mTarget.sendPendingMessages(ACCOUNT_2));
    335 
    336         assertFalse(mListener.mCalledOnConnectionError);
    337         assertEquals(ACCOUNT_2, mListener.mAccountId);
    338         assertEquals(-1, mListener.mMailboxId);
    339         mListener.reset();
    340         assertTrue(mController.mCalledSendPendingMessages);
    341         assertEquals(ACCOUNT_2, mController.mAccountId);
    342         assertEquals(-1, mController.mMailboxId);
    343         mController.reset();
    344 
    345         // Sending start for account 1...
    346         // batch send start.  (message id == -1, progress == 0)
    347         mController.mListener.sendMailCallback(null, ACCOUNT_1, -1, 0);
    348 
    349         assertFalse(mListener.mCalledOnConnectionError);
    350         mListener.reset();
    351 
    352         // Per message callback
    353         mController.mListener.sendMailCallback(null, ACCOUNT_1, 100, 0);
    354         mController.mListener.sendMailCallback(null, ACCOUNT_1, 101, 0);
    355 
    356         assertFalse(mListener.mCalledOnConnectionError);
    357         mListener.reset();
    358 
    359         // Exception -- first error will be reported.
    360         mController.mListener.sendMailCallback(EXCEPTION, ACCOUNT_1, 102, 0);
    361 
    362         assertTrue(mListener.mCalledOnConnectionError);
    363         assertEquals(MessagingExceptionStrings.getErrorString(mContext, EXCEPTION),
    364                 mListener.mMessage);
    365         mListener.reset();
    366 
    367         // Exception again -- no more error callbacks
    368         mController.mListener.sendMailCallback(null, ACCOUNT_1, 103, 0);
    369         mController.mListener.sendMailCallback(EXCEPTION, ACCOUNT_1, 104, 0);
    370 
    371         assertFalse(mListener.mCalledOnConnectionError);
    372         mListener.reset();
    373 
    374         // Done.
    375         LogUtils.w(Logging.LOG_TAG, "" + mController.mListener.getClass());
    376         mController.mListener.sendMailCallback(null, ACCOUNT_1, -1, 100);
    377 
    378         assertFalse(mListener.mCalledOnConnectionError);
    379         mListener.reset();
    380     }
    381 
    382     public void testSendPendingMessagesForAllAccounts() throws Throwable {
    383         Account acct1 = ProviderTestUtils.setupAccount("acct1", true, mProviderContext);
    384         Account acct2 = ProviderTestUtils.setupAccount("acct2", true, mProviderContext);
    385 
    386         // AsyncTask needs to be created on the UI thread.
    387         runTestOnUiThread(new Runnable() {
    388             @Override
    389             public void run() {
    390                 mTarget.sendPendingMessagesForAllAccounts();
    391             }
    392         });
    393 
    394         // sendPendingMessagesForAllAccounts uses Utility.ForEachAccount, which has it's own test,
    395         // so we don't really have to check everything.
    396         // Here, we just check if sendPendingMessages() has been called at least for once,
    397         // which is a enough check.
    398         TestUtils.waitUntil(new TestUtils.Condition() {
    399             @Override
    400             public boolean isMet() {
    401                 // The write to this is done on the UI thread, but we're checking it here
    402                 // on the test thread, so mCalledSendPendingMessages needs to be volatile.
    403                 return mController.mCalledSendPendingMessages;
    404             }
    405         }, WAIT_UNTIL_TIMEOUT_SECONDS);
    406     }
    407 
    408     public void testLoadMoreMessages() {
    409         final long ACCOUNT_ID = 123;
    410         final long MAILBOX_ID = 456;
    411 
    412         mTarget.loadMoreMessages(ACCOUNT_ID, MAILBOX_ID);
    413 
    414         assertTrue(mController.mCalledLoadMoreMessages);
    415         assertEquals(mController.mMailboxId, MAILBOX_ID);
    416         assertFalse(mController.mCalledUpdateMailbox);
    417     }
    418 
    419     // volatile is necessary for testSendPendingMessagesForAllAccounts().
    420     // (Not all of them are actually necessary, but added for consistency.)
    421     private static class MockController extends Controller {
    422         public volatile long mAccountId = -1;
    423         public volatile long mMailboxId = -1;
    424         public volatile boolean mCalledSendPendingMessages;
    425         public volatile boolean mCalledUpdateMailbox;
    426         public volatile boolean mCalledUpdateMailboxList;
    427         public volatile boolean mCalledLoadMoreMessages;
    428         public volatile Result mListener;
    429 
    430         protected MockController(Context context) {
    431             super(context);
    432         }
    433 
    434         public void reset() {
    435             mAccountId = -1;
    436             mMailboxId = -1;
    437             mCalledSendPendingMessages = false;
    438             mCalledUpdateMailbox = false;
    439             mCalledUpdateMailboxList = false;
    440         }
    441 
    442         @Override
    443         public void sendPendingMessages(long accountId) {
    444             mCalledSendPendingMessages = true;
    445             mAccountId = accountId;
    446         }
    447 
    448         @Override
    449         public void updateMailbox(long accountId, long mailboxId, boolean userRequest) {
    450             mCalledUpdateMailbox = true;
    451             mAccountId = accountId;
    452             mMailboxId = mailboxId;
    453         }
    454 
    455         @Override
    456         public void updateMailboxList(long accountId) {
    457             mCalledUpdateMailboxList = true;
    458             mAccountId = accountId;
    459         }
    460 
    461         @Override
    462         public void loadMoreMessages(long mailboxId) {
    463             mCalledLoadMoreMessages = true;
    464             mAccountId = -1;
    465             mMailboxId = mailboxId;
    466         }
    467 
    468         @Override
    469         public void addResultCallback(Result listener) {
    470             Assert.assertTrue(mListener == null);
    471             mListener = listener;
    472 
    473             // Let it call listener.setRegistered(). Otherwise callbacks won't fire.
    474             super.addResultCallback(listener);
    475         }
    476     }
    477 
    478     private static class RefreshListener implements RefreshManager.Listener {
    479         public long mAccountId = -1;
    480         public long mMailboxId = -1;
    481         public String mMessage;
    482         public boolean mCalledOnConnectionError;
    483         public boolean mCalledOnRefreshStatusChanged;
    484 
    485         public void reset() {
    486             mAccountId = -1;
    487             mMailboxId = -1;
    488             mMessage = null;
    489             mCalledOnConnectionError = false;
    490             mCalledOnRefreshStatusChanged = false;
    491         }
    492 
    493         @Override
    494         public void onRefreshStatusChanged(long accountId, long mailboxId) {
    495             mAccountId = accountId;
    496             mMailboxId = mailboxId;
    497             mCalledOnRefreshStatusChanged = true;
    498         }
    499 
    500         @Override
    501         public void onMessagingError(long accountId, long mailboxId, String message) {
    502             mAccountId = accountId;
    503             mMailboxId = mailboxId;
    504             mMessage = message;
    505             mCalledOnConnectionError = true;
    506         }
    507     }
    508 }
    509