• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.service;
18 
19 import android.accounts.AccountManager;
20 import android.content.ComponentName;
21 import android.content.ContentResolver;
22 import android.content.ContentUris;
23 import android.content.ContentValues;
24 import android.content.Context;
25 import android.content.pm.PackageManager;
26 
27 import com.android.email.AccountTestCase;
28 import com.android.email.Controller;
29 import com.android.email.provider.AccountReconciler;
30 import com.android.email.provider.EmailProvider;
31 import com.android.email.provider.ProviderTestUtils;
32 import com.android.email.service.MailService.AccountSyncReport;
33 import com.android.emailcommon.provider.Account;
34 import com.android.emailcommon.provider.EmailContent;
35 import com.android.emailcommon.provider.HostAuth;
36 
37 import java.util.ArrayList;
38 import java.util.HashMap;
39 import java.util.List;
40 
41 /**
42  * Tests of the Email provider.
43  *
44  * You can run this entire test case with:
45  *   runtest -c com.android.email.service.MailServiceTests email
46  */
47 public class MailServiceTests extends AccountTestCase {
48 
49     EmailProvider mProvider;
50     Context mMockContext;
51 
MailServiceTests()52     public MailServiceTests() {
53         super();
54     }
55 
56     @Override
setUp()57     public void setUp() throws Exception {
58         super.setUp();
59         PackageManager pm = getContext().getPackageManager();
60         pm.setComponentEnabledSetting(
61                 new ComponentName(getContext(), EasTestAuthenticatorService.class),
62                 PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
63                 PackageManager.DONT_KILL_APP);
64         mMockContext = getMockContext();
65         // Delete any test accounts we might have created earlier
66         deleteTemporaryAccountManagerAccounts();
67     }
68 
69     @Override
tearDown()70     public void tearDown() throws Exception {
71         super.tearDown();
72         // Delete any test accounts we might have created earlier
73         deleteTemporaryAccountManagerAccounts();
74     }
75 
76     /**
77      * Confirm that the test below is functional (and non-destructive) when there are
78      * prexisting (non-test) accounts in the account manager.
79      */
testTestReconcileAccounts()80     public void testTestReconcileAccounts() {
81         Account firstAccount = null;
82         final String TEST_USER_ACCOUNT = "__user_account_test_1";
83         Context context = getContext();
84         try {
85             // Note:  Unlike calls to setupProviderAndAccountManagerAccount(), we are creating
86             // *real* accounts here (not in the mock provider)
87             createAccountManagerAccount(TEST_USER_ACCOUNT + TEST_ACCOUNT_SUFFIX);
88             firstAccount = ProviderTestUtils.setupAccount(TEST_USER_ACCOUNT, true, context);
89             // Now run the test with the "user" accounts in place
90             testReconcileAccounts();
91         } finally {
92             if (firstAccount != null) {
93                 boolean firstAccountFound = false;
94                 // delete the provider account
95                 context.getContentResolver().delete(firstAccount.getUri(), null, null);
96                 // delete the account manager account
97                 android.accounts.Account[] accountManagerAccounts = AccountManager.get(context)
98                         .getAccountsByType(TEST_ACCOUNT_TYPE);
99                 for (android.accounts.Account accountManagerAccount: accountManagerAccounts) {
100                     if ((TEST_USER_ACCOUNT + TEST_ACCOUNT_SUFFIX)
101                             .equals(accountManagerAccount.name)) {
102                         deleteAccountManagerAccount(accountManagerAccount);
103                         firstAccountFound = true;
104                     }
105                 }
106                 assertTrue(firstAccountFound);
107             }
108         }
109     }
110 
111     /**
112      * Note, there is some inherent risk in this test, as it creates *real* accounts in the
113      * system (it cannot use the mock context with the Account Manager).
114      */
testReconcileAccounts()115     public void testReconcileAccounts() {
116         // Note that we can't use mMockContext for AccountManager interactions, as it isn't a fully
117         // functional Context.
118         Context context = getContext();
119 
120         // Capture the baseline (account manager accounts) so we can measure the changes
121         // we're making, irrespective of the number of actual accounts, and not destroy them
122         android.accounts.Account[] baselineAccounts =
123             AccountManager.get(context).getAccountsByType(TEST_ACCOUNT_TYPE);
124 
125         // Set up three accounts, both in AccountManager and in EmailProvider
126         Account firstAccount = setupProviderAndAccountManagerAccount(getTestAccountName("1"));
127         setupProviderAndAccountManagerAccount(getTestAccountName("2"));
128         setupProviderAndAccountManagerAccount(getTestAccountName("3"));
129 
130         // Check that they're set up properly
131         assertEquals(3, EmailContent.count(mMockContext, Account.CONTENT_URI, null, null));
132         android.accounts.Account[] accountManagerAccounts =
133                 getAccountManagerAccounts(baselineAccounts);
134         assertEquals(3, accountManagerAccounts.length);
135 
136         // Delete account "2" from AccountManager
137         android.accounts.Account removedAccount =
138             makeAccountManagerAccount(getTestAccountEmailAddress("2"));
139         deleteAccountManagerAccount(removedAccount);
140 
141         // Confirm it's deleted
142         accountManagerAccounts = getAccountManagerAccounts(baselineAccounts);
143         assertEquals(2, accountManagerAccounts.length);
144 
145         // Run the reconciler
146         ContentResolver resolver = mMockContext.getContentResolver();
147         MailService.reconcileAccountsWithAccountManager(context,
148                 makeExchangeServiceAccountList(), accountManagerAccounts, mMockContext);
149 
150         // There should now be only two EmailProvider accounts
151         assertEquals(2, EmailContent.count(mMockContext, Account.CONTENT_URI, null, null));
152 
153         // Ok, now we've got two of each; let's delete a provider account
154         resolver.delete(ContentUris.withAppendedId(Account.CONTENT_URI, firstAccount.mId),
155                 null, null);
156         // ...and then there was one
157         assertEquals(1, EmailContent.count(mMockContext, Account.CONTENT_URI, null, null));
158 
159         // Run the reconciler
160         MailService.reconcileAccountsWithAccountManager(context,
161                 makeExchangeServiceAccountList(), accountManagerAccounts, mMockContext);
162 
163         // There should now be only one AccountManager account
164         accountManagerAccounts = getAccountManagerAccounts(baselineAccounts);
165         assertEquals(1, accountManagerAccounts.length);
166         // ... and it should be account "3"
167         assertEquals(getTestAccountEmailAddress("3"), accountManagerAccounts[0].name);
168     }
169 
testReconcileDetection()170     public void testReconcileDetection() {
171         Context context = getContext();
172         List<Account> providerAccounts;
173         android.accounts.Account[] accountManagerAccounts;
174 
175         android.accounts.Account[] baselineAccounts =
176             AccountManager.get(context).getAccountsByType(TEST_ACCOUNT_TYPE);
177 
178         // Empty lists match.
179         providerAccounts = new ArrayList<Account>();
180         accountManagerAccounts = new android.accounts.Account[0];
181         assertFalse(AccountReconciler.accountsNeedReconciling(
182                 context, providerAccounts, accountManagerAccounts));
183 
184         setupProviderAndAccountManagerAccount(getTestAccountName("1"));
185         accountManagerAccounts = getAccountManagerAccounts(baselineAccounts);
186         providerAccounts = makeExchangeServiceAccountList();
187 
188         // A single account, but empty list on the other side is detected as needing reconciliation
189         assertTrue(AccountReconciler.accountsNeedReconciling(
190                 context, new ArrayList<Account>(), accountManagerAccounts));
191         assertTrue(AccountReconciler.accountsNeedReconciling(
192                 context, providerAccounts, new android.accounts.Account[0]));
193 
194         // Note that no reconciliation should have happened though - we just wanted to detect it.
195         assertEquals(1, makeExchangeServiceAccountList().size());
196         assertEquals(1, getAccountManagerAccounts(baselineAccounts).length);
197 
198         // Single account matches - no reconciliation should be detected.
199         assertFalse(AccountReconciler.accountsNeedReconciling(
200                 context, providerAccounts, accountManagerAccounts));
201 
202         // Provider: 1,2,3. AccountManager: 1, 3.
203         String username = getTestAccountName("2");
204         ProviderTestUtils.setupAccount(getTestAccountName("2"), true, getMockContext());
205         setupProviderAndAccountManagerAccount(getTestAccountName("3"));
206 
207         accountManagerAccounts = getAccountManagerAccounts(baselineAccounts);
208         providerAccounts = makeExchangeServiceAccountList();
209         assertTrue(AccountReconciler.accountsNeedReconciling(
210                 context, providerAccounts, accountManagerAccounts));
211     }
212 
213 
214     /**
215      * Lightweight subclass of the Controller class allows injection of mock context
216      */
217     public static class TestController extends Controller {
218 
TestController(Context providerContext, Context systemContext)219         protected TestController(Context providerContext, Context systemContext) {
220             super(systemContext);
221             setProviderContext(providerContext);
222         }
223     }
224 
225     /**
226      * Create a simple HostAuth with protocol
227      */
setupSimpleHostAuth(String protocol)228     private HostAuth setupSimpleHostAuth(String protocol) {
229         HostAuth hostAuth = new HostAuth();
230         hostAuth.mProtocol = protocol;
231         return hostAuth;
232     }
233 
234     /**
235      * Initial testing on setupSyncReportsLocked, making sure that EAS accounts aren't scheduled
236      */
testSetupSyncReportsLocked()237     public void testSetupSyncReportsLocked() {
238         // TODO Test other functionality within setupSyncReportsLocked
239         // Setup accounts of each type, all with manual sync at different intervals
240         Account easAccount = ProviderTestUtils.setupAccount("account1", false, mMockContext);
241         easAccount.mHostAuthRecv = setupSimpleHostAuth("eas");
242         easAccount.mHostAuthSend = easAccount.mHostAuthRecv;
243         easAccount.mSyncInterval = 30;
244         easAccount.save(mMockContext);
245         Account imapAccount = ProviderTestUtils.setupAccount("account2", false, mMockContext);
246         imapAccount.mHostAuthRecv = setupSimpleHostAuth("imap");
247         imapAccount.mHostAuthSend = setupSimpleHostAuth("smtp");
248         imapAccount.mSyncInterval = 60;
249         imapAccount.save(mMockContext);
250         Account pop3Account = ProviderTestUtils.setupAccount("account3", false, mMockContext);
251         pop3Account.mHostAuthRecv = setupSimpleHostAuth("pop3");
252         pop3Account.mHostAuthSend = setupSimpleHostAuth("smtp");
253         pop3Account.mSyncInterval = 90;
254         pop3Account.save(mMockContext);
255 
256         // Setup the SyncReport's for these Accounts
257         MailService mailService = new MailService();
258         mailService.mController = new TestController(mMockContext, getContext());
259         try {
260             mailService.setupSyncReportsLocked(MailService.SYNC_REPORTS_RESET, mMockContext);
261 
262             // Get back the map created by MailService
263             HashMap<Long, AccountSyncReport> syncReportMap = MailService.mSyncReports;
264             synchronized (syncReportMap) {
265                 // Check the SyncReport's for correctness of sync interval
266                 AccountSyncReport syncReport = syncReportMap.get(easAccount.mId);
267                 assertNotNull(syncReport);
268                 // EAS sync interval should have been changed to "never"
269                 assertEquals(Account.CHECK_INTERVAL_NEVER, syncReport.syncInterval);
270                 syncReport = syncReportMap.get(imapAccount.mId);
271                 assertNotNull(syncReport);
272                 assertEquals(60, syncReport.syncInterval);
273                 syncReport = syncReportMap.get(pop3Account.mId);
274                 assertNotNull(syncReport);
275                 assertEquals(90, syncReport.syncInterval);
276                 // Change the EAS account to push
277                 ContentValues cv = new ContentValues();
278                 cv.put(Account.SYNC_INTERVAL, Account.CHECK_INTERVAL_PUSH);
279                 easAccount.update(mMockContext, cv);
280                 syncReportMap.clear();
281                 mailService.setupSyncReportsLocked(easAccount.mId, mMockContext);
282                 syncReport = syncReportMap.get(easAccount.mId);
283                 assertNotNull(syncReport);
284                 // EAS sync interval should be "never" in this case as well
285                 assertEquals(Account.CHECK_INTERVAL_NEVER, syncReport.syncInterval);
286             }
287         } finally {
288             mailService.mController.cleanupForTest();
289         }
290     }
291 
292     /**
293      * Test that setupSyncReports will skip over poorly-formed accounts which can be left
294      * over after unit tests.
295      */
testSetupSyncReportsWithBadAccounts()296     public void testSetupSyncReportsWithBadAccounts() {
297         // Setup accounts that trigger each skip-over case
298         // 1: no email address
299         Account account1 = ProviderTestUtils.setupAccount("account1", false, mMockContext);
300         account1.mHostAuthRecv = setupSimpleHostAuth("imap");
301         account1.mHostAuthSend = setupSimpleHostAuth("smtp");
302         account1.mSyncInterval = 30;
303         account1.mEmailAddress = null;
304         account1.save(mMockContext);
305         // 2: no receiver hostauth
306         Account account2 = ProviderTestUtils.setupAccount("account2", false, mMockContext);
307         account2.mHostAuthRecv = null;
308         account2.mHostAuthSend = setupSimpleHostAuth("smtp");
309         account2.mSyncInterval = 30;
310         account2.save(mMockContext);
311         // 3: no sender hostauth
312         Account account3 = ProviderTestUtils.setupAccount("account3", false, mMockContext);
313         account3.mHostAuthRecv = setupSimpleHostAuth("imap");
314         account3.mHostAuthSend = null;
315         account3.mSyncInterval = 30;
316         account3.save(mMockContext);
317 
318         // Setup the SyncReport's for these Accounts
319         MailService mailService = new MailService();
320         mailService.mController = new TestController(mMockContext, getContext());
321         try {
322             mailService.setupSyncReportsLocked(MailService.SYNC_REPORTS_RESET, mMockContext);
323             // Get back the map created by MailService - it should be empty
324             HashMap<Long, AccountSyncReport> syncReportMap = MailService.mSyncReports;
325             assertEquals(0, syncReportMap.size());
326         } finally {
327             mailService.mController.cleanupForTest();
328         }
329 
330     }
331 }
332