RefreshManagerTest.java revision c184f36c2df16431693d7709e28ded593efc3da7
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;
18
19import com.android.email.mail.MessagingException;
20import com.android.email.provider.EmailContent.Account;
21import com.android.email.provider.EmailProvider;
22import com.android.email.provider.ProviderTestUtils;
23
24import android.content.Context;
25import android.test.InstrumentationTestCase;
26import android.test.suitebuilder.annotation.LargeTest;
27import android.util.Log;
28
29import junit.framework.Assert;
30
31@LargeTest
32public 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(
61                mContext, EmailProvider.class);
62        mTarget = new RefreshManager(mProviderContext, mController, mClock, null);
63        mTarget.registerListener(mListener);
64    }
65
66    @Override
67    protected void tearDown() throws Exception {
68        super.tearDown();
69        mController.cleanupForTest();
70    }
71
72    public void testRegisterUnregisterListener() {
73        // mListener is already registered
74        assertEquals(1, mTarget.getListenersForTest().size());
75
76        mTarget.unregisterListener(mListener);
77        assertEquals(0, mTarget.getListenersForTest().size());
78    }
79
80    public void testRefreshStatus() {
81        RefreshManager.Status s = new RefreshManager.Status();
82        assertFalse(s.isRefreshing());
83        assertTrue(s.canRefresh());
84        assertEquals(0, s.getLastRefreshTime());
85
86        // Request refresh
87        s.onRefreshRequested();
88        assertTrue(s.isRefreshing());
89        assertFalse(s.canRefresh());
90        assertEquals(0, s.getLastRefreshTime());
91
92        // Refresh start
93        s.onCallback(null, 0, mClock);
94        assertTrue(s.isRefreshing());
95        assertFalse(s.canRefresh());
96        assertEquals(0, s.getLastRefreshTime());
97
98        // Refresh 50% done -- nothing changes
99        s.onCallback(null, 50, mClock);
100        assertTrue(s.isRefreshing());
101        assertFalse(s.canRefresh());
102        assertEquals(0, s.getLastRefreshTime());
103
104        // Refresh finish
105        s.onCallback(null, 100, mClock);
106        assertFalse(s.isRefreshing());
107        assertTrue(s.canRefresh());
108        assertEquals(mClock.mTime, s.getLastRefreshTime());
109
110        // Refresh start without request
111        s.onCallback(null, 0, mClock);
112        assertTrue(s.isRefreshing());
113        assertFalse(s.canRefresh());
114        assertEquals(mClock.mTime, s.getLastRefreshTime());
115
116        mClock.advance();
117
118        // Refresh finish with error.
119        s.onCallback(EXCEPTION, 0, mClock);
120        assertFalse(s.isRefreshing());
121        assertTrue(s.canRefresh());
122        assertEquals(mClock.mTime, s.getLastRefreshTime());
123    }
124
125    public void testRefreshMailboxList() {
126        // request refresh for account 1
127        assertTrue(mTarget.refreshMailboxList(ACCOUNT_1));
128
129        assertTrue(mListener.mCalledOnRefreshStatusChanged);
130        assertFalse(mListener.mCalledOnConnectionError);
131        assertEquals(ACCOUNT_1, mListener.mAccountId);
132        assertEquals(-1, mListener.mMailboxId);
133        mListener.reset();
134        assertTrue(mController.mCalledUpdateMailboxList);
135        assertEquals(ACCOUNT_1, mController.mAccountId);
136        assertEquals(-1, mController.mMailboxId);
137        mController.reset();
138        assertTrue(mTarget.isMailboxListRefreshing(ACCOUNT_1));
139        assertTrue(mTarget.isRefreshingAnyMailboxList());
140
141        // Request again -- shouldn't be accepted.
142        assertFalse(mTarget.refreshMailboxList(ACCOUNT_1));
143
144        assertFalse(mListener.mCalledOnRefreshStatusChanged);
145        assertFalse(mListener.mCalledOnConnectionError);
146        mListener.reset();
147        assertFalse(mController.mCalledUpdateMailboxList);
148        mController.reset();
149
150        // request refresh for account 2
151        assertTrue(mTarget.refreshMailboxList(ACCOUNT_2));
152
153        assertTrue(mListener.mCalledOnRefreshStatusChanged);
154        assertFalse(mListener.mCalledOnConnectionError);
155        assertEquals(ACCOUNT_2, mListener.mAccountId);
156        assertEquals(-1, mListener.mMailboxId);
157        mListener.reset();
158        assertTrue(mController.mCalledUpdateMailboxList);
159        assertEquals(ACCOUNT_2, mController.mAccountId);
160        assertEquals(-1, mController.mMailboxId);
161        mController.reset();
162        assertTrue(mTarget.isMailboxListRefreshing(ACCOUNT_2));
163        assertTrue(mTarget.isRefreshingAnyMailboxList());
164
165        // Refreshing for account 1...
166        mController.mListener.updateMailboxListCallback(null, ACCOUNT_1, 0);
167
168        assertTrue(mListener.mCalledOnRefreshStatusChanged);
169        assertFalse(mListener.mCalledOnConnectionError);
170        assertEquals(ACCOUNT_1, mListener.mAccountId);
171        assertEquals(-1, mListener.mMailboxId);
172        mListener.reset();
173        assertTrue(mTarget.isMailboxListRefreshing(ACCOUNT_1));
174        assertEquals(0, mTarget.getMailboxListStatusForTest(ACCOUNT_1).getLastRefreshTime());
175
176        // Done.
177        Log.w(Email.LOG_TAG, "" + mController.mListener.getClass());
178        mController.mListener.updateMailboxListCallback(null, ACCOUNT_1, 100);
179
180        assertTrue(mListener.mCalledOnRefreshStatusChanged);
181        assertFalse(mListener.mCalledOnConnectionError);
182        assertEquals(ACCOUNT_1, mListener.mAccountId);
183        assertEquals(-1, mListener.mMailboxId);
184        mListener.reset();
185        assertFalse(mTarget.isMailboxListRefreshing(ACCOUNT_1));
186        assertEquals(mClock.mTime, mTarget.getMailboxListStatusForTest(ACCOUNT_1)
187                .getLastRefreshTime());
188
189        // Check "any" method.
190        assertTrue(mTarget.isRefreshingAnyMailboxList()); // still refreshing account 2
191
192        // Refreshing for account 2...
193        mClock.advance();
194
195        mController.mListener.updateMailboxListCallback(null, ACCOUNT_2, 0);
196
197        assertTrue(mListener.mCalledOnRefreshStatusChanged);
198        assertFalse(mListener.mCalledOnConnectionError);
199        assertEquals(ACCOUNT_2, mListener.mAccountId);
200        assertEquals(-1, mListener.mMailboxId);
201        mListener.reset();
202        assertTrue(mTarget.isMailboxListRefreshing(ACCOUNT_2));
203        assertEquals(0, mTarget.getMailboxListStatusForTest(ACCOUNT_2).getLastRefreshTime());
204
205        // Done with exception.
206        mController.mListener.updateMailboxListCallback(EXCEPTION, ACCOUNT_2, 0);
207
208        assertTrue(mListener.mCalledOnRefreshStatusChanged);
209        assertTrue(mListener.mCalledOnConnectionError);
210        assertEquals(ACCOUNT_2, mListener.mAccountId);
211        assertEquals(-1, mListener.mMailboxId);
212        assertEquals(EXCEPTION.getUiErrorMessage(mContext), 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.isRefreshingAnyMailboxList());
220    }
221
222    public void testRefreshMessageList() {
223        // request refresh mailbox 1
224        assertTrue(mTarget.refreshMessageList(ACCOUNT_1, MAILBOX_1));
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.isRefreshingAnyMessageList());
237
238        // Request again -- shouldn't be accepted.
239        assertFalse(mTarget.refreshMessageList(ACCOUNT_1, MAILBOX_1));
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));
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.isRefreshingAnyMessageList());
261
262        // Refreshing mailbox 1...
263        mController.mListener.updateMailboxCallback(null, ACCOUNT_1, MAILBOX_1, 0, 0);
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(Email.LOG_TAG, "" + mController.mListener.getClass());
275        mController.mListener.updateMailboxCallback(null, ACCOUNT_1, MAILBOX_1, 100, 0);
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.isRefreshingAnyMessageList()); // still refreshing mailbox 2
288
289        // Refreshing mailbox 2...
290        mClock.advance();
291
292        mController.mListener.updateMailboxCallback(null, ACCOUNT_2, MAILBOX_2, 0, 0);
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);
304
305        assertTrue(mListener.mCalledOnRefreshStatusChanged);
306        assertTrue(mListener.mCalledOnConnectionError);
307        assertEquals(ACCOUNT_2, mListener.mAccountId);
308        assertEquals(MAILBOX_2, mListener.mMailboxId);
309        assertEquals(EXCEPTION.getUiErrorMessage(mContext), 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.isRefreshingAnyMessageList());
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        assertTrue(mTarget.isSendingMessage(ACCOUNT_1));
333        assertTrue(mTarget.isSendingAnyMessage());
334
335        // Request again -- shouldn't be accepted.
336        assertFalse(mTarget.sendPendingMessages(ACCOUNT_1));
337
338        assertFalse(mListener.mCalledOnRefreshStatusChanged);
339        assertFalse(mListener.mCalledOnConnectionError);
340        mListener.reset();
341        assertFalse(mController.mCalledSendPendingMessages);
342        mController.reset();
343
344        // request sending for account 2
345        assertTrue(mTarget.sendPendingMessages(ACCOUNT_2));
346
347        assertTrue(mListener.mCalledOnRefreshStatusChanged);
348        assertFalse(mListener.mCalledOnConnectionError);
349        assertEquals(ACCOUNT_2, mListener.mAccountId);
350        assertEquals(-1, mListener.mMailboxId);
351        mListener.reset();
352        assertTrue(mController.mCalledSendPendingMessages);
353        assertEquals(ACCOUNT_2, mController.mAccountId);
354        assertEquals(-1, mController.mMailboxId);
355        mController.reset();
356        assertTrue(mTarget.isSendingMessage(ACCOUNT_2));
357        assertTrue(mTarget.isSendingAnyMessage());
358
359        // sending for account 1...
360        mController.mListener.sendMailCallback(null, ACCOUNT_1, -1, 0);
361
362        assertTrue(mListener.mCalledOnRefreshStatusChanged);
363        assertFalse(mListener.mCalledOnConnectionError);
364        assertEquals(ACCOUNT_1, mListener.mAccountId);
365        assertEquals(-1, mListener.mMailboxId);
366        mListener.reset();
367        assertTrue(mTarget.isSendingMessage(ACCOUNT_1));
368        assertEquals(0, mTarget.getOutboxStatusForTest(ACCOUNT_1).getLastRefreshTime());
369
370        // Per message callback (1)
371        mController.mListener.sendMailCallback(null, ACCOUNT_1, 100, 0);
372        mController.mListener.sendMailCallback(null, ACCOUNT_1, 101, 0);
373
374        // No callback per message
375        assertFalse(mListener.mCalledOnRefreshStatusChanged);
376        assertFalse(mListener.mCalledOnConnectionError);
377        mListener.reset();
378
379        // Exception -- first error will be reported.
380        mController.mListener.sendMailCallback(EXCEPTION, ACCOUNT_1, 102, 0);
381
382        assertFalse(mListener.mCalledOnRefreshStatusChanged);
383        assertTrue(mListener.mCalledOnConnectionError);
384        assertEquals(EXCEPTION.getUiErrorMessage(mContext), mListener.mMessage);
385        mListener.reset();
386
387        // Exception again -- no more error callbacks
388        mController.mListener.sendMailCallback(null, ACCOUNT_1, 103, 0);
389        mController.mListener.sendMailCallback(EXCEPTION, ACCOUNT_1, 104, 0);
390
391        assertFalse(mListener.mCalledOnRefreshStatusChanged);
392        assertFalse(mListener.mCalledOnConnectionError);
393        mListener.reset();
394
395        // Done.
396        Log.w(Email.LOG_TAG, "" + mController.mListener.getClass());
397        mController.mListener.sendMailCallback(null, ACCOUNT_1, -1, 100);
398
399        assertTrue(mListener.mCalledOnRefreshStatusChanged);
400        assertFalse(mListener.mCalledOnConnectionError);
401        assertEquals(ACCOUNT_1, mListener.mAccountId);
402        assertEquals(-1, mListener.mMailboxId);
403        mListener.reset();
404        assertFalse(mTarget.isSendingMessage(ACCOUNT_1));
405        assertEquals(mClock.mTime, mTarget.getOutboxStatusForTest(ACCOUNT_1)
406                .getLastRefreshTime());
407
408        // Check "any" method.
409        assertTrue(mTarget.isSendingAnyMessage()); // still sending for account 2
410
411        // sending for account 2...
412        mClock.advance();
413
414        mController.mListener.sendMailCallback(null, ACCOUNT_2, -1, 0);
415
416        assertTrue(mListener.mCalledOnRefreshStatusChanged);
417        assertFalse(mListener.mCalledOnConnectionError);
418        assertEquals(ACCOUNT_2, mListener.mAccountId);
419        assertEquals(-1, mListener.mMailboxId);
420        mListener.reset();
421        assertTrue(mTarget.isSendingMessage(ACCOUNT_2));
422        assertEquals(0, mTarget.getOutboxStatusForTest(ACCOUNT_2).getLastRefreshTime());
423
424        // Done with exception.
425        mController.mListener.sendMailCallback(EXCEPTION, ACCOUNT_2, -1, 0);
426
427        assertTrue(mListener.mCalledOnRefreshStatusChanged);
428        assertTrue(mListener.mCalledOnConnectionError);
429        assertEquals(ACCOUNT_2, mListener.mAccountId);
430        assertEquals(-1, mListener.mMailboxId);
431        assertEquals(EXCEPTION.getUiErrorMessage(mContext), mListener.mMessage);
432        mListener.reset();
433        assertFalse(mTarget.isSendingMessage(ACCOUNT_2));
434        assertEquals(mClock.mTime, mTarget.getOutboxStatusForTest(ACCOUNT_2)
435                .getLastRefreshTime());
436
437        // Check "any" method.
438        assertFalse(mTarget.isSendingAnyMessage());
439    }
440
441    public void testSendPendingMessagesForAllAccounts() throws Throwable {
442        Account acct1 = ProviderTestUtils.setupAccount("acct1", true, mProviderContext);
443        Account acct2 = ProviderTestUtils.setupAccount("acct2", true, mProviderContext);
444
445        // AsyncTask needs to be created on the UI thread.
446        runTestOnUiThread(new Runnable() {
447            @Override
448            public void run() {
449                mTarget.sendPendingMessagesForAllAccounts();
450            }
451        });
452
453        // sendPendingMessagesForAllAccounts uses Utility.ForEachAccount, which has it's own test,
454        // so we don't really have to check everything.
455        // Here, we just check if sendPendingMessages() has been called at least for once,
456        // which is a enough check.
457        TestUtils.waitUntil(new TestUtils.Condition() {
458            @Override
459            public boolean isMet() {
460                // The write to this is done on the UI thread, but we're checking it here
461                // on the test thread, so mCalledSendPendingMessages needs to be volatile.
462                return mController.mCalledSendPendingMessages;
463            }
464        }, WAIT_UNTIL_TIMEOUT_SECONDS);
465    }
466
467    // volatile is necessary for testSendPendingMessagesForAllAccounts().
468    // (Not all of them are actually necessary, but added for consistency.)
469    private static class MockController extends Controller {
470        public volatile long mAccountId = -1;
471        public volatile long mMailboxId = -1;
472        public volatile boolean mCalledSendPendingMessages;
473        public volatile boolean mCalledUpdateMailbox;
474        public volatile boolean mCalledUpdateMailboxList;
475        public volatile Result mListener;
476
477        protected MockController(Context context) {
478            super(context);
479        }
480
481        public void reset() {
482            mAccountId = -1;
483            mMailboxId = -1;
484            mCalledSendPendingMessages = false;
485            mCalledUpdateMailbox = false;
486            mCalledUpdateMailboxList = false;
487        }
488
489        @Override
490        public void sendPendingMessages(long accountId) {
491            mCalledSendPendingMessages = true;
492            mAccountId = accountId;
493        }
494
495        @Override
496        public void updateMailbox(long accountId, long mailboxId) {
497            mCalledUpdateMailbox = true;
498            mAccountId = accountId;
499            mMailboxId = mailboxId;
500        }
501
502        @Override
503        public void updateMailboxList(long accountId) {
504            mCalledUpdateMailboxList = true;
505            mAccountId = accountId;
506        }
507
508        @Override
509        public void addResultCallback(Result listener) {
510            Assert.assertTrue(mListener == null);
511            mListener = listener;
512        }
513    }
514
515    private static class RefreshListener implements RefreshManager.Listener {
516        public long mAccountId = -1;
517        public long mMailboxId = -1;
518        public String mMessage;
519        public boolean mCalledOnConnectionError;
520        public boolean mCalledOnRefreshStatusChanged;
521
522        public void reset() {
523            mAccountId = -1;
524            mMailboxId = -1;
525            mMessage = null;
526            mCalledOnConnectionError = false;
527            mCalledOnRefreshStatusChanged = false;
528        }
529
530        @Override
531        public void onRefreshStatusChanged(long accountId, long mailboxId) {
532            mAccountId = accountId;
533            mMailboxId = mailboxId;
534            mCalledOnRefreshStatusChanged = true;
535        }
536
537        @Override
538        public void onMessagingError(long accountId, long mailboxId, String message) {
539            mAccountId = accountId;
540            mMailboxId = mailboxId;
541            mMessage = message;
542            mCalledOnConnectionError = true;
543        }
544    }
545}
546