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.provider.ProviderTestUtils; 20import com.android.emailcommon.Logging; 21import com.android.emailcommon.mail.MessagingException; 22import com.android.emailcommon.provider.Account; 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(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