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