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