1 /* 2 * Copyright (C) 2009 Marc Blank 3 * Licensed to The Android Open Source Project. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.android.exchange; 19 20 import com.android.email.AccountTestCase; 21 import com.android.email.Email; 22 import com.android.email.provider.EmailContent; 23 import com.android.email.provider.EmailProvider; 24 import com.android.email.provider.ProviderTestUtils; 25 import com.android.email.provider.EmailContent.Account; 26 import com.android.email.provider.EmailContent.Mailbox; 27 import com.android.exchange.SyncManager.SyncError; 28 29 import android.accounts.AccountManager; 30 import android.content.ContentResolver; 31 import android.content.ContentUris; 32 import android.content.Context; 33 34 import java.util.HashMap; 35 36 /** 37 * You can run this entire test case with: 38 * runtest -c com.android.exchange.SyncManagerAccountTests email 39 */ 40 public class SyncManagerAccountTests extends AccountTestCase { 41 42 EmailProvider mProvider; 43 Context mMockContext; 44 45 public SyncManagerAccountTests() { 46 super(); 47 } 48 49 @Override 50 public void setUp() throws Exception { 51 super.setUp(); 52 mMockContext = getMockContext(); 53 // Delete any test accounts we might have created earlier 54 deleteTemporaryAccountManagerAccounts(); 55 } 56 57 @Override 58 public void tearDown() throws Exception { 59 super.tearDown(); 60 // Delete any test accounts we might have created earlier 61 deleteTemporaryAccountManagerAccounts(); 62 } 63 64 /** 65 * Confirm that the test below is functional (and non-destructive) when there are 66 * prexisting (non-test) accounts in the account manager. 67 */ 68 public void testTestReconcileAccounts() { 69 Account firstAccount = null; 70 final String TEST_USER_ACCOUNT = "__user_account_test_1"; 71 Context context = getContext(); 72 try { 73 // Note: Unlike calls to setupProviderAndAccountManagerAccount(), we are creating 74 // *real* accounts here (not in the mock provider) 75 createAccountManagerAccount(TEST_USER_ACCOUNT + TEST_ACCOUNT_SUFFIX); 76 firstAccount = ProviderTestUtils.setupAccount(TEST_USER_ACCOUNT, true, context); 77 // Now run the test with the "user" accounts in place 78 testReconcileAccounts(); 79 } finally { 80 if (firstAccount != null) { 81 boolean firstAccountFound = false; 82 // delete the provider account 83 context.getContentResolver().delete(firstAccount.getUri(), null, null); 84 // delete the account manager account 85 android.accounts.Account[] accountManagerAccounts = AccountManager.get(context) 86 .getAccountsByType(Email.EXCHANGE_ACCOUNT_MANAGER_TYPE); 87 for (android.accounts.Account accountManagerAccount: accountManagerAccounts) { 88 if ((TEST_USER_ACCOUNT + TEST_ACCOUNT_SUFFIX) 89 .equals(accountManagerAccount.name)) { 90 deleteAccountManagerAccount(accountManagerAccount); 91 firstAccountFound = true; 92 } 93 } 94 assertTrue(firstAccountFound); 95 } 96 } 97 } 98 99 /** 100 * Note, there is some inherent risk in this test, as it creates *real* accounts in the 101 * system (it cannot use the mock context with the Account Manager). 102 */ 103 public void testReconcileAccounts() { 104 // Note that we can't use mMockContext for AccountManager interactions, as it isn't a fully 105 // functional Context. 106 Context context = getContext(); 107 108 // Capture the baseline (account manager accounts) so we can measure the changes 109 // we're making, irrespective of the number of actual accounts, and not destroy them 110 android.accounts.Account[] baselineAccounts = 111 AccountManager.get(context).getAccountsByType(Email.EXCHANGE_ACCOUNT_MANAGER_TYPE); 112 113 // Set up three accounts, both in AccountManager and in EmailProvider 114 Account firstAccount = setupProviderAndAccountManagerAccount(getTestAccountName("1")); 115 setupProviderAndAccountManagerAccount(getTestAccountName("2")); 116 setupProviderAndAccountManagerAccount(getTestAccountName("3")); 117 118 // Check that they're set up properly 119 assertEquals(3, EmailContent.count(mMockContext, Account.CONTENT_URI, null, null)); 120 android.accounts.Account[] accountManagerAccounts = 121 getAccountManagerAccounts(baselineAccounts); 122 assertEquals(3, accountManagerAccounts.length); 123 124 // Delete account "2" from AccountManager 125 android.accounts.Account removedAccount = 126 makeAccountManagerAccount(getTestAccountEmailAddress("2")); 127 deleteAccountManagerAccount(removedAccount); 128 129 // Confirm it's deleted 130 accountManagerAccounts = getAccountManagerAccounts(baselineAccounts); 131 assertEquals(2, accountManagerAccounts.length); 132 133 // Run the reconciler 134 ContentResolver resolver = mMockContext.getContentResolver(); 135 SyncManager.reconcileAccountsWithAccountManager(context, 136 makeSyncManagerAccountList(), accountManagerAccounts, true, resolver); 137 138 // There should now be only two EmailProvider accounts 139 assertEquals(2, EmailContent.count(mMockContext, Account.CONTENT_URI, null, null)); 140 141 // Ok, now we've got two of each; let's delete a provider account 142 resolver.delete(ContentUris.withAppendedId(Account.CONTENT_URI, firstAccount.mId), 143 null, null); 144 // ...and then there was one 145 assertEquals(1, EmailContent.count(mMockContext, Account.CONTENT_URI, null, null)); 146 147 // Run the reconciler 148 SyncManager.reconcileAccountsWithAccountManager(context, 149 makeSyncManagerAccountList(), accountManagerAccounts, true, resolver); 150 151 // There should now be only one AccountManager account 152 accountManagerAccounts = getAccountManagerAccounts(baselineAccounts); 153 assertEquals(1, accountManagerAccounts.length); 154 // ... and it should be account "3" 155 assertEquals(getTestAccountEmailAddress("3"), accountManagerAccounts[0].name); 156 } 157 158 public void testReleaseSyncHolds() { 159 Context context = mMockContext; 160 SyncManager syncManager = new SyncManager(); 161 SyncError securityErrorAccount1 = 162 syncManager.new SyncError(AbstractSyncService.EXIT_SECURITY_FAILURE, false); 163 SyncError ioError = 164 syncManager.new SyncError(AbstractSyncService.EXIT_IO_ERROR, false); 165 SyncError securityErrorAccount2 = 166 syncManager.new SyncError(AbstractSyncService.EXIT_SECURITY_FAILURE, false); 167 // Create account and two mailboxes 168 Account acct1 = ProviderTestUtils.setupAccount("acct1", true, context); 169 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", acct1.mId, true, context); 170 Mailbox box2 = ProviderTestUtils.setupMailbox("box2", acct1.mId, true, context); 171 Account acct2 = ProviderTestUtils.setupAccount("acct2", true, context); 172 Mailbox box3 = ProviderTestUtils.setupMailbox("box3", acct2.mId, true, context); 173 Mailbox box4 = ProviderTestUtils.setupMailbox("box4", acct2.mId, true, context); 174 175 HashMap<Long, SyncError> errorMap = syncManager.mSyncErrorMap; 176 // Add errors into the map 177 errorMap.put(box1.mId, securityErrorAccount1); 178 errorMap.put(box2.mId, ioError); 179 errorMap.put(box3.mId, securityErrorAccount2); 180 errorMap.put(box4.mId, securityErrorAccount2); 181 // We should have 4 182 assertEquals(4, errorMap.keySet().size()); 183 // Release the holds on acct2 (there are two of them) 184 syncManager.releaseSyncHolds(context, AbstractSyncService.EXIT_SECURITY_FAILURE, acct2); 185 // There should be two left 186 assertEquals(2, errorMap.keySet().size()); 187 // And these are the two... 188 assertNotNull(errorMap.get(box2.mId)); 189 assertNotNull(errorMap.get(box1.mId)); 190 191 // Put the two back 192 errorMap.put(box3.mId, securityErrorAccount2); 193 errorMap.put(box4.mId, securityErrorAccount2); 194 // We should have 4 again 195 assertEquals(4, errorMap.keySet().size()); 196 // Release all of the security holds 197 syncManager.releaseSyncHolds(context, AbstractSyncService.EXIT_SECURITY_FAILURE, null); 198 // There should be one left 199 assertEquals(1, errorMap.keySet().size()); 200 // And this is the one 201 assertNotNull(errorMap.get(box2.mId)); 202 203 // Release the i/o holds on account 2 (there aren't any) 204 syncManager.releaseSyncHolds(context, AbstractSyncService.EXIT_IO_ERROR, acct2); 205 // There should still be one left 206 assertEquals(1, errorMap.keySet().size()); 207 208 // Release the i/o holds on account 1 (there's one) 209 syncManager.releaseSyncHolds(context, AbstractSyncService.EXIT_IO_ERROR, acct1); 210 // There should still be one left 211 assertEquals(0, errorMap.keySet().size()); 212 } 213 214 } 215