|
1 /* Any copyright is dedicated to the Public Domain. |
|
2 http://creativecommons.org/publicdomain/zero/1.0/ */ |
|
3 |
|
4 package org.mozilla.gecko.background.sync; |
|
5 |
|
6 import java.io.UnsupportedEncodingException; |
|
7 import java.security.NoSuchAlgorithmException; |
|
8 import java.util.concurrent.TimeUnit; |
|
9 |
|
10 import org.mozilla.gecko.background.common.GlobalConstants; |
|
11 import org.mozilla.gecko.background.helpers.AndroidSyncTestCase; |
|
12 import org.mozilla.gecko.sync.ExtendedJSONObject; |
|
13 import org.mozilla.gecko.sync.SyncConfiguration; |
|
14 import org.mozilla.gecko.sync.SyncConstants; |
|
15 import org.mozilla.gecko.sync.Utils; |
|
16 import org.mozilla.gecko.sync.setup.Constants; |
|
17 import org.mozilla.gecko.sync.setup.SyncAccounts; |
|
18 import org.mozilla.gecko.sync.setup.SyncAccounts.SyncAccountParameters; |
|
19 |
|
20 import android.accounts.Account; |
|
21 import android.accounts.AccountManager; |
|
22 import android.accounts.AccountManagerCallback; |
|
23 import android.accounts.AccountManagerFuture; |
|
24 import android.content.Context; |
|
25 import android.content.Intent; |
|
26 import android.content.SharedPreferences; |
|
27 import android.test.InstrumentationTestCase; |
|
28 |
|
29 /** |
|
30 * We can use <code>performWait</code> and <code>performNotify</code> here if we |
|
31 * are careful about threading issues with <code>AsyncTask</code>. We need to |
|
32 * take some care to both create and run certain tasks on the main thread -- |
|
33 * moving the object allocation out of the UI thread causes failures! |
|
34 * <p> |
|
35 * @see "<a href='http://stackoverflow.com/questions/2321829/android-asynctask-testing-problem-with-android-test-framework'> |
|
36 * http://stackoverflow.com/questions/2321829/android-asynctask-testing-problem-with-android-test-framework</a>." |
|
37 */ |
|
38 public class TestSyncAccounts extends AndroidSyncTestCase { |
|
39 private static final String TEST_USERNAME = "testAccount@mozilla.com"; |
|
40 private static final String TEST_SYNCKEY = "testSyncKey"; |
|
41 private static final String TEST_PASSWORD = "testPassword"; |
|
42 private static final String TEST_SERVERURL = "test.server.url/"; |
|
43 private static final String TEST_CLUSTERURL = "test.cluster.url/"; |
|
44 |
|
45 public static final String TEST_ACCOUNTTYPE = SyncConstants.ACCOUNTTYPE_SYNC; |
|
46 |
|
47 public static final String TEST_PRODUCT = GlobalConstants.BROWSER_INTENT_PACKAGE; |
|
48 public static final String TEST_PROFILE = Constants.DEFAULT_PROFILE; |
|
49 public static final long TEST_VERSION = SyncConfiguration.CURRENT_PREFS_VERSION; |
|
50 |
|
51 public static final String TEST_PREFERENCE = "testPreference"; |
|
52 public static final String TEST_SYNC_ID = "testSyncID"; |
|
53 |
|
54 private Account account; |
|
55 private Context context; |
|
56 private AccountManager accountManager; |
|
57 private SyncAccountParameters syncAccount; |
|
58 |
|
59 public void setUp() { |
|
60 account = null; |
|
61 context = getApplicationContext(); |
|
62 accountManager = AccountManager.get(context); |
|
63 syncAccount = new SyncAccountParameters(context, null, |
|
64 TEST_USERNAME, TEST_SYNCKEY, TEST_PASSWORD, null); |
|
65 } |
|
66 |
|
67 public static void deleteAccount(final InstrumentationTestCase test, final AccountManager accountManager, final Account account) { |
|
68 performWait(new Runnable() { |
|
69 @Override |
|
70 public void run() { |
|
71 try { |
|
72 test.runTestOnUiThread(new Runnable() { |
|
73 final AccountManagerCallback<Boolean> callback = new AccountManagerCallback<Boolean>() { |
|
74 @Override |
|
75 public void run(AccountManagerFuture<Boolean> future) { |
|
76 try { |
|
77 future.getResult(5L, TimeUnit.SECONDS); |
|
78 } catch (Exception e) { |
|
79 } |
|
80 performNotify(); |
|
81 } |
|
82 }; |
|
83 |
|
84 @Override |
|
85 public void run() { |
|
86 accountManager.removeAccount(account, callback, null); |
|
87 } |
|
88 }); |
|
89 } catch (Throwable e) { |
|
90 performNotify(e); |
|
91 } |
|
92 } |
|
93 }); |
|
94 } |
|
95 |
|
96 public void tearDown() { |
|
97 if (account == null) { |
|
98 return; |
|
99 } |
|
100 deleteAccount(this, accountManager, account); |
|
101 account = null; |
|
102 } |
|
103 |
|
104 public void testSyncAccountParameters() { |
|
105 assertEquals(TEST_USERNAME, syncAccount.username); |
|
106 assertNull(syncAccount.accountManager); |
|
107 assertNull(syncAccount.serverURL); |
|
108 |
|
109 try { |
|
110 syncAccount = new SyncAccountParameters(context, null, |
|
111 null, TEST_SYNCKEY, TEST_PASSWORD, TEST_SERVERURL); |
|
112 } catch (IllegalArgumentException e) { |
|
113 return; |
|
114 } catch (Exception e) { |
|
115 fail("Did not expect exception: " + e); |
|
116 } |
|
117 fail("Expected IllegalArgumentException."); |
|
118 } |
|
119 |
|
120 public void testCreateAccount() { |
|
121 int before = accountManager.getAccountsByType(TEST_ACCOUNTTYPE).length; |
|
122 account = SyncAccounts.createSyncAccount(syncAccount, false); |
|
123 int afterCreate = accountManager.getAccountsByType(TEST_ACCOUNTTYPE).length; |
|
124 assertTrue(afterCreate > before); |
|
125 deleteAccount(this, accountManager, account); |
|
126 account = null; |
|
127 int afterDelete = accountManager.getAccountsByType(TEST_ACCOUNTTYPE).length; |
|
128 assertEquals(before, afterDelete); |
|
129 } |
|
130 |
|
131 public void testCreateSecondAccount() { |
|
132 int before = accountManager.getAccountsByType(TEST_ACCOUNTTYPE).length; |
|
133 account = SyncAccounts.createSyncAccount(syncAccount, false); |
|
134 int afterFirst = accountManager.getAccountsByType(TEST_ACCOUNTTYPE).length; |
|
135 assertTrue(afterFirst > before); |
|
136 |
|
137 SyncAccountParameters secondSyncAccount = new SyncAccountParameters(context, null, |
|
138 "second@username.com", TEST_SYNCKEY, TEST_PASSWORD, null); |
|
139 |
|
140 Account second = SyncAccounts.createSyncAccount(secondSyncAccount, false); |
|
141 assertNotNull(second); |
|
142 int afterSecond = accountManager.getAccountsByType(TEST_ACCOUNTTYPE).length; |
|
143 assertTrue(afterSecond > afterFirst); |
|
144 |
|
145 deleteAccount(this, accountManager, second); |
|
146 deleteAccount(this, accountManager, account); |
|
147 account = null; |
|
148 |
|
149 int afterDelete = accountManager.getAccountsByType(TEST_ACCOUNTTYPE).length; |
|
150 assertEquals(before, afterDelete); |
|
151 } |
|
152 |
|
153 public void testCreateDuplicateAccount() { |
|
154 int before = accountManager.getAccountsByType(TEST_ACCOUNTTYPE).length; |
|
155 account = SyncAccounts.createSyncAccount(syncAccount, false); |
|
156 int afterCreate = accountManager.getAccountsByType(TEST_ACCOUNTTYPE).length; |
|
157 assertTrue(afterCreate > before); |
|
158 |
|
159 Account dupe = SyncAccounts.createSyncAccount(syncAccount, false); |
|
160 assertNull(dupe); |
|
161 } |
|
162 |
|
163 public void testClientRecord() throws NoSuchAlgorithmException, UnsupportedEncodingException { |
|
164 final String TEST_NAME = "testName"; |
|
165 final String TEST_GUID = "testGuid"; |
|
166 syncAccount = new SyncAccountParameters(context, null, |
|
167 TEST_USERNAME, TEST_SYNCKEY, TEST_PASSWORD, null, null, TEST_NAME, TEST_GUID); |
|
168 account = SyncAccounts.createSyncAccount(syncAccount, false); |
|
169 assertNotNull(account); |
|
170 |
|
171 SharedPreferences prefs = Utils.getSharedPreferences(context, TEST_PRODUCT, TEST_USERNAME, |
|
172 SyncConstants.DEFAULT_AUTH_SERVER, TEST_PROFILE, TEST_VERSION); |
|
173 |
|
174 // Verify that client record is set. |
|
175 assertEquals(TEST_GUID, prefs.getString(SyncConfiguration.PREF_ACCOUNT_GUID, null)); |
|
176 assertEquals(TEST_NAME, prefs.getString(SyncConfiguration.PREF_CLIENT_NAME, null)); |
|
177 |
|
178 // Let's verify that clusterURL is correctly not set. |
|
179 String clusterURL = prefs.getString(SyncConfiguration.PREF_CLUSTER_URL, null); |
|
180 assertNull(clusterURL); |
|
181 } |
|
182 |
|
183 public void testClusterURL() throws NoSuchAlgorithmException, UnsupportedEncodingException { |
|
184 syncAccount = new SyncAccountParameters(context, null, |
|
185 TEST_USERNAME, TEST_SYNCKEY, TEST_PASSWORD, TEST_SERVERURL, TEST_CLUSTERURL, null, null); |
|
186 account = SyncAccounts.createSyncAccount(syncAccount, false); |
|
187 assertNotNull(account); |
|
188 |
|
189 SharedPreferences prefs = Utils.getSharedPreferences(context, TEST_PRODUCT, TEST_USERNAME, |
|
190 TEST_SERVERURL, TEST_PROFILE, TEST_VERSION); |
|
191 String clusterURL = prefs.getString(SyncConfiguration.PREF_CLUSTER_URL, null); |
|
192 assertNotNull(clusterURL); |
|
193 assertEquals(TEST_CLUSTERURL, clusterURL); |
|
194 |
|
195 // Let's verify that client name and GUID are not set. |
|
196 assertNull(prefs.getString(SyncConfiguration.PREF_ACCOUNT_GUID, null)); |
|
197 assertNull(prefs.getString(SyncConfiguration.PREF_CLIENT_NAME, null)); |
|
198 } |
|
199 |
|
200 /** |
|
201 * Verify that creating an account wipes stale settings in Shared Preferences. |
|
202 */ |
|
203 public void testCreatingWipesSharedPrefs() throws Exception { |
|
204 final String TEST_PREFERENCE = "testPreference"; |
|
205 final String TEST_SYNC_ID = "testSyncID"; |
|
206 |
|
207 SharedPreferences prefs = Utils.getSharedPreferences(context, TEST_PRODUCT, TEST_USERNAME, |
|
208 TEST_SERVERURL, TEST_PROFILE, TEST_VERSION); |
|
209 prefs.edit().putString(SyncConfiguration.PREF_SYNC_ID, TEST_SYNC_ID).commit(); |
|
210 prefs.edit().putString(TEST_PREFERENCE, TEST_SYNC_ID).commit(); |
|
211 |
|
212 syncAccount = new SyncAccountParameters(context, null, |
|
213 TEST_USERNAME, TEST_SYNCKEY, TEST_PASSWORD, TEST_SERVERURL); |
|
214 account = SyncAccounts.createSyncAccount(syncAccount, false); |
|
215 assertNotNull(account); |
|
216 |
|
217 // All values deleted (known and unknown). |
|
218 assertNull(prefs.getString(SyncConfiguration.PREF_SYNC_ID, null)); |
|
219 assertNull(prefs.getString(TEST_SYNC_ID, null)); |
|
220 } |
|
221 |
|
222 /** |
|
223 * Verify that creating an account preserves settings in Shared Preferences when asked. |
|
224 */ |
|
225 public void testCreateSyncAccountWithExistingPreferences() throws Exception { |
|
226 |
|
227 SharedPreferences prefs = Utils.getSharedPreferences(context, TEST_PRODUCT, TEST_USERNAME, |
|
228 TEST_SERVERURL, TEST_PROFILE, TEST_VERSION); |
|
229 |
|
230 prefs.edit().putString(SyncConfiguration.PREF_SYNC_ID, TEST_SYNC_ID).commit(); |
|
231 prefs.edit().putString(TEST_PREFERENCE, TEST_SYNC_ID).commit(); |
|
232 |
|
233 assertNotNull(prefs.getString(TEST_PREFERENCE, null)); |
|
234 assertNotNull(prefs.getString(SyncConfiguration.PREF_SYNC_ID, null)); |
|
235 |
|
236 syncAccount = new SyncAccountParameters(context, null, |
|
237 TEST_USERNAME, TEST_SYNCKEY, TEST_PASSWORD, TEST_SERVERURL); |
|
238 account = SyncAccounts.createSyncAccountPreservingExistingPreferences(syncAccount, false); |
|
239 assertNotNull(account); |
|
240 |
|
241 // All values remain (known and unknown). |
|
242 assertNotNull(prefs.getString(TEST_PREFERENCE, null)); |
|
243 assertNotNull(prefs.getString(SyncConfiguration.PREF_SYNC_ID, null)); |
|
244 } |
|
245 |
|
246 protected void assertParams(final SyncAccountParameters params) throws Exception { |
|
247 assertNotNull(params); |
|
248 assertEquals(context, params.context); |
|
249 assertEquals(Utils.usernameFromAccount(TEST_USERNAME), params.username); |
|
250 assertEquals(TEST_PASSWORD, params.password); |
|
251 assertEquals(TEST_SERVERURL, params.serverURL); |
|
252 assertEquals(TEST_SYNCKEY, params.syncKey); |
|
253 } |
|
254 |
|
255 public void testBlockingFromAndroidAccountV0() throws Throwable { |
|
256 syncAccount = new SyncAccountParameters(context, null, |
|
257 TEST_USERNAME, TEST_SYNCKEY, TEST_PASSWORD, TEST_SERVERURL, TEST_CLUSTERURL, null, null); |
|
258 try { |
|
259 account = SyncAccounts.createSyncAccount(syncAccount); |
|
260 assertNotNull(account); |
|
261 |
|
262 // Test fetching parameters multiple times. Historically, we needed to |
|
263 // invalidate this token type every fetch; now we don't, but we'd like |
|
264 // to ensure multiple fetches work. |
|
265 SyncAccountParameters params = SyncAccounts.blockingFromAndroidAccountV0(context, accountManager, account); |
|
266 assertParams(params); |
|
267 |
|
268 params = SyncAccounts.blockingFromAndroidAccountV0(context, accountManager, account); |
|
269 assertParams(params); |
|
270 |
|
271 // Test this works on the main thread. |
|
272 this.runTestOnUiThread(new Runnable() { |
|
273 @Override |
|
274 public void run() { |
|
275 SyncAccountParameters params; |
|
276 try { |
|
277 params = SyncAccounts.blockingFromAndroidAccountV0(context, accountManager, account); |
|
278 assertParams(params); |
|
279 } catch (Exception e) { |
|
280 fail("Fetching Sync account parameters failed on UI thread."); |
|
281 } |
|
282 } |
|
283 }); |
|
284 } finally { |
|
285 if (account != null) { |
|
286 deleteAccount(this, accountManager, account); |
|
287 account = null; |
|
288 } |
|
289 } |
|
290 } |
|
291 |
|
292 public void testMakeSyncAccountDeletedIntent() throws Throwable { |
|
293 syncAccount = new SyncAccountParameters(context, null, |
|
294 TEST_USERNAME, TEST_SYNCKEY, TEST_PASSWORD, TEST_SERVERURL, TEST_CLUSTERURL, null, null); |
|
295 try { |
|
296 account = SyncAccounts.createSyncAccount(syncAccount); |
|
297 assertNotNull(account); |
|
298 |
|
299 Intent intent = SyncAccounts.makeSyncAccountDeletedIntent(context, accountManager, account); |
|
300 assertEquals(SyncConstants.SYNC_ACCOUNT_DELETED_ACTION, intent.getAction()); |
|
301 assertEquals(SyncConstants.SYNC_ACCOUNT_DELETED_INTENT_VERSION, intent.getLongExtra(Constants.JSON_KEY_VERSION, 0)); |
|
302 assertEquals(TEST_USERNAME, intent.getStringExtra(Constants.JSON_KEY_ACCOUNT)); |
|
303 assertTrue(Math.abs(intent.getLongExtra(Constants.JSON_KEY_TIMESTAMP, 0) - System.currentTimeMillis()) < 1000); |
|
304 |
|
305 String payload = intent.getStringExtra(Constants.JSON_KEY_PAYLOAD); |
|
306 assertNotNull(payload); |
|
307 |
|
308 SyncAccountParameters params = new SyncAccountParameters(context, accountManager, ExtendedJSONObject.parseJSONObject(payload)); |
|
309 // Can't use assertParams because Sync key is deleted. |
|
310 assertNotNull(params); |
|
311 assertEquals(context, params.context); |
|
312 assertEquals(Utils.usernameFromAccount(TEST_USERNAME), params.username); |
|
313 assertEquals(TEST_PASSWORD, params.password); |
|
314 assertEquals(TEST_SERVERURL, params.serverURL); |
|
315 assertEquals("", params.syncKey); |
|
316 } finally { |
|
317 if (account != null) { |
|
318 deleteAccount(this, accountManager, account); |
|
319 account = null; |
|
320 } |
|
321 } |
|
322 } |
|
323 |
|
324 public void testBlockingPrefsFromAndroidAccountV0() throws Exception { |
|
325 // Create test account with prefs. We use a different username to avoid a |
|
326 // timing issue, where the delayed clean-up of the account created by the |
|
327 // previous test deletes the preferences for this account. |
|
328 SharedPreferences prefs = Utils.getSharedPreferences(context, TEST_PRODUCT, |
|
329 TEST_USERNAME + "2", TEST_SERVERURL, TEST_PROFILE, TEST_VERSION); |
|
330 prefs.edit().putString(TEST_PREFERENCE, TEST_SYNC_ID).commit(); |
|
331 |
|
332 syncAccount = new SyncAccountParameters(context, null, |
|
333 TEST_USERNAME + "2", TEST_SYNCKEY, TEST_PASSWORD, TEST_SERVERURL); |
|
334 account = SyncAccounts.createSyncAccountPreservingExistingPreferences(syncAccount, false); |
|
335 assertNotNull(account); |
|
336 |
|
337 // Fetch account and check prefs. |
|
338 SharedPreferences sharedPreferences = SyncAccounts.blockingPrefsFromAndroidAccountV0(context, accountManager, |
|
339 account, TEST_PRODUCT, TEST_PROFILE, TEST_VERSION); |
|
340 assertNotNull(sharedPreferences); |
|
341 assertEquals(TEST_SYNC_ID, sharedPreferences.getString(TEST_PREFERENCE, null)); |
|
342 } |
|
343 } |