RefreshManagerTest.java revision cbdd9f78b2605e87e45e4f6761b0a8c444a8cd4c
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.ProviderTestUtils;
22
23import android.content.Context;
24import android.test.InstrumentationTestCase;
25import android.test.suitebuilder.annotation.LargeTest;
26import android.util.Log;
27
28import junit.framework.Assert;
29
30@LargeTest
31public 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        Log.w(Email.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(EXCEPTION.getUiErrorMessage(mContext), mListener.mMessage);
211        mListener.reset();
212        assertFalse(mTarget.isMailboxListRefreshing(ACCOUNT_2));
213        assertEquals(mClock.mTime, mTarget.getMailboxListStatusForTest(ACCOUNT_2)
214                .getLastRefreshTime());
215
216        // Check "any" method.
217        assertFalse(mTarget.isRefreshingAnyMailboxListForTest());
218    }
219
220    public void testRefreshMessageList() {
221        // request refresh mailbox 1
222        assertTrue(mTarget.refreshMessageList(ACCOUNT_1, MAILBOX_1, false));
223
224        assertTrue(mListener.mCalledOnRefreshStatusChanged);
225        assertFalse(mListener.mCalledOnConnectionError);
226        assertEquals(ACCOUNT_1, mListener.mAccountId);
227        assertEquals(MAILBOX_1, mListener.mMailboxId);
228        mListener.reset();
229        assertTrue(mController.mCalledUpdateMailbox);
230        assertEquals(ACCOUNT_1, mController.mAccountId);
231        assertEquals(MAILBOX_1, mController.mMailboxId);
232        mController.reset();
233        assertTrue(mTarget.isMessageListRefreshing(MAILBOX_1));
234        assertTrue(mTarget.isRefreshingAnyMessageListForTest());
235
236        // Request again -- shouldn't be accepted.
237        assertFalse(mTarget.refreshMessageList(ACCOUNT_1, MAILBOX_1, false));
238
239        assertFalse(mListener.mCalledOnRefreshStatusChanged);
240        assertFalse(mListener.mCalledOnConnectionError);
241        mListener.reset();
242        assertFalse(mController.mCalledUpdateMailbox);
243        mController.reset();
244
245        // request refresh mailbox 2
246        assertTrue(mTarget.refreshMessageList(ACCOUNT_2, MAILBOX_2, false));
247
248        assertTrue(mListener.mCalledOnRefreshStatusChanged);
249        assertFalse(mListener.mCalledOnConnectionError);
250        assertEquals(ACCOUNT_2, mListener.mAccountId);
251        assertEquals(MAILBOX_2, mListener.mMailboxId);
252        mListener.reset();
253        assertTrue(mController.mCalledUpdateMailbox);
254        assertEquals(ACCOUNT_2, mController.mAccountId);
255        assertEquals(MAILBOX_2, mController.mMailboxId);
256        mController.reset();
257        assertTrue(mTarget.isMessageListRefreshing(MAILBOX_2));
258        assertTrue(mTarget.isRefreshingAnyMessageListForTest());
259
260        // Refreshing mailbox 1...
261        mController.mListener.updateMailboxCallback(null, ACCOUNT_1, MAILBOX_1, 0, 0);
262
263        assertTrue(mListener.mCalledOnRefreshStatusChanged);
264        assertFalse(mListener.mCalledOnConnectionError);
265        assertEquals(ACCOUNT_1, mListener.mAccountId);
266        assertEquals(MAILBOX_1, mListener.mMailboxId);
267        mListener.reset();
268        assertTrue(mTarget.isMessageListRefreshing(MAILBOX_1));
269        assertEquals(0, mTarget.getMessageListStatusForTest(MAILBOX_1).getLastRefreshTime());
270
271        // Done.
272        Log.w(Email.LOG_TAG, "" + mController.mListener.getClass());
273        mController.mListener.updateMailboxCallback(null, ACCOUNT_1, MAILBOX_1, 100, 0);
274
275        assertTrue(mListener.mCalledOnRefreshStatusChanged);
276        assertFalse(mListener.mCalledOnConnectionError);
277        assertEquals(ACCOUNT_1, mListener.mAccountId);
278        assertEquals(MAILBOX_1, mListener.mMailboxId);
279        mListener.reset();
280        assertFalse(mTarget.isMessageListRefreshing(MAILBOX_1));
281        assertEquals(mClock.mTime, mTarget.getMessageListStatusForTest(MAILBOX_1)
282                .getLastRefreshTime());
283
284        // Check "any" method.
285        assertTrue(mTarget.isRefreshingAnyMessageListForTest()); // still refreshing mailbox 2
286
287        // Refreshing mailbox 2...
288        mClock.advance();
289
290        mController.mListener.updateMailboxCallback(null, ACCOUNT_2, MAILBOX_2, 0, 0);
291
292        assertTrue(mListener.mCalledOnRefreshStatusChanged);
293        assertFalse(mListener.mCalledOnConnectionError);
294        assertEquals(ACCOUNT_2, mListener.mAccountId);
295        assertEquals(MAILBOX_2, mListener.mMailboxId);
296        mListener.reset();
297        assertTrue(mTarget.isMessageListRefreshing(MAILBOX_2));
298        assertEquals(0, mTarget.getMessageListStatusForTest(MAILBOX_2).getLastRefreshTime());
299
300        // Done with exception.
301        mController.mListener.updateMailboxCallback(EXCEPTION, ACCOUNT_2, MAILBOX_2, 0, 0);
302
303        assertTrue(mListener.mCalledOnRefreshStatusChanged);
304        assertTrue(mListener.mCalledOnConnectionError);
305        assertEquals(ACCOUNT_2, mListener.mAccountId);
306        assertEquals(MAILBOX_2, mListener.mMailboxId);
307        assertEquals(EXCEPTION.getUiErrorMessage(mContext), mListener.mMessage);
308        mListener.reset();
309        assertFalse(mTarget.isMessageListRefreshing(MAILBOX_2));
310        assertEquals(mClock.mTime, mTarget.getMessageListStatusForTest(MAILBOX_2)
311                .getLastRefreshTime());
312
313        // Check "any" method.
314        assertFalse(mTarget.isRefreshingAnyMessageListForTest());
315    }
316
317    public void testSendPendingMessages() {
318        // request sending for account 1
319        assertTrue(mTarget.sendPendingMessages(ACCOUNT_1));
320
321        assertTrue(mListener.mCalledOnRefreshStatusChanged);
322        assertFalse(mListener.mCalledOnConnectionError);
323        assertEquals(ACCOUNT_1, mListener.mAccountId);
324        assertEquals(-1, mListener.mMailboxId);
325        mListener.reset();
326        assertTrue(mController.mCalledSendPendingMessages);
327        assertEquals(ACCOUNT_1, mController.mAccountId);
328        assertEquals(-1, mController.mMailboxId);
329        mController.reset();
330
331        // request sending for account 2
332        assertTrue(mTarget.sendPendingMessages(ACCOUNT_2));
333
334        assertFalse(mListener.mCalledOnConnectionError);
335        assertEquals(ACCOUNT_2, mListener.mAccountId);
336        assertEquals(-1, mListener.mMailboxId);
337        mListener.reset();
338        assertTrue(mController.mCalledSendPendingMessages);
339        assertEquals(ACCOUNT_2, mController.mAccountId);
340        assertEquals(-1, mController.mMailboxId);
341        mController.reset();
342
343        // Sending start for account 1...
344        // batch send start.  (message id == -1, progress == 0)
345        mController.mListener.sendMailCallback(null, ACCOUNT_1, -1, 0);
346
347        assertFalse(mListener.mCalledOnConnectionError);
348        mListener.reset();
349
350        // Per message callback
351        mController.mListener.sendMailCallback(null, ACCOUNT_1, 100, 0);
352        mController.mListener.sendMailCallback(null, ACCOUNT_1, 101, 0);
353
354        assertFalse(mListener.mCalledOnConnectionError);
355        mListener.reset();
356
357        // Exception -- first error will be reported.
358        mController.mListener.sendMailCallback(EXCEPTION, ACCOUNT_1, 102, 0);
359
360        assertTrue(mListener.mCalledOnConnectionError);
361        assertEquals(EXCEPTION.getUiErrorMessage(mContext), mListener.mMessage);
362        mListener.reset();
363
364        // Exception again -- no more error callbacks
365        mController.mListener.sendMailCallback(null, ACCOUNT_1, 103, 0);
366        mController.mListener.sendMailCallback(EXCEPTION, ACCOUNT_1, 104, 0);
367
368        assertFalse(mListener.mCalledOnConnectionError);
369        mListener.reset();
370
371        // Done.
372        Log.w(Email.LOG_TAG, "" + mController.mListener.getClass());
373        mController.mListener.sendMailCallback(null, ACCOUNT_1, -1, 100);
374
375        assertFalse(mListener.mCalledOnConnectionError);
376        mListener.reset();
377    }
378
379    public void testSendPendingMessagesForAllAccounts() throws Throwable {
380        Account acct1 = ProviderTestUtils.setupAccount("acct1", true, mProviderContext);
381        Account acct2 = ProviderTestUtils.setupAccount("acct2", true, mProviderContext);
382
383        // AsyncTask needs to be created on the UI thread.
384        runTestOnUiThread(new Runnable() {
385            @Override
386            public void run() {
387                mTarget.sendPendingMessagesForAllAccounts();
388            }
389        });
390
391        // sendPendingMessagesForAllAccounts uses Utility.ForEachAccount, which has it's own test,
392        // so we don't really have to check everything.
393        // Here, we just check if sendPendingMessages() has been called at least for once,
394        // which is a enough check.
395        TestUtils.waitUntil(new TestUtils.Condition() {
396            @Override
397            public boolean isMet() {
398                // The write to this is done on the UI thread, but we're checking it here
399                // on the test thread, so mCalledSendPendingMessages needs to be volatile.
400                return mController.mCalledSendPendingMessages;
401            }
402        }, WAIT_UNTIL_TIMEOUT_SECONDS);
403    }
404
405    // volatile is necessary for testSendPendingMessagesForAllAccounts().
406    // (Not all of them are actually necessary, but added for consistency.)
407    private static class MockController extends Controller {
408        public volatile long mAccountId = -1;
409        public volatile long mMailboxId = -1;
410        public volatile boolean mCalledSendPendingMessages;
411        public volatile boolean mCalledUpdateMailbox;
412        public volatile boolean mCalledUpdateMailboxList;
413        public volatile Result mListener;
414
415        protected MockController(Context context) {
416            super(context);
417        }
418
419        public void reset() {
420            mAccountId = -1;
421            mMailboxId = -1;
422            mCalledSendPendingMessages = false;
423            mCalledUpdateMailbox = false;
424            mCalledUpdateMailboxList = false;
425        }
426
427        @Override
428        public void sendPendingMessages(long accountId) {
429            mCalledSendPendingMessages = true;
430            mAccountId = accountId;
431        }
432
433        @Override
434        public void updateMailbox(long accountId, long mailboxId, boolean userRequest) {
435            mCalledUpdateMailbox = true;
436            mAccountId = accountId;
437            mMailboxId = mailboxId;
438        }
439
440        @Override
441        public void updateMailboxList(long accountId) {
442            mCalledUpdateMailboxList = true;
443            mAccountId = accountId;
444        }
445
446        @Override
447        public void addResultCallback(Result listener) {
448            Assert.assertTrue(mListener == null);
449            mListener = listener;
450
451            // Let it call listener.setRegistered(). Otherwise callbacks won't fire.
452            super.addResultCallback(listener);
453        }
454    }
455
456    private static class RefreshListener implements RefreshManager.Listener {
457        public long mAccountId = -1;
458        public long mMailboxId = -1;
459        public String mMessage;
460        public boolean mCalledOnConnectionError;
461        public boolean mCalledOnRefreshStatusChanged;
462
463        public void reset() {
464            mAccountId = -1;
465            mMailboxId = -1;
466            mMessage = null;
467            mCalledOnConnectionError = false;
468            mCalledOnRefreshStatusChanged = false;
469        }
470
471        @Override
472        public void onRefreshStatusChanged(long accountId, long mailboxId) {
473            mAccountId = accountId;
474            mMailboxId = mailboxId;
475            mCalledOnRefreshStatusChanged = true;
476        }
477
478        @Override
479        public void onMessagingError(long accountId, long mailboxId, String message) {
480            mAccountId = accountId;
481            mMailboxId = mailboxId;
482            mMessage = message;
483            mCalledOnConnectionError = true;
484        }
485    }
486}
487