michael@0: /* Any copyright is dedicated to the Public Domain.
michael@0: http://creativecommons.org/publicdomain/zero/1.0/ */
michael@0:
michael@0: package org.mozilla.gecko.background.sync;
michael@0:
michael@0: import java.io.UnsupportedEncodingException;
michael@0: import java.security.NoSuchAlgorithmException;
michael@0: import java.util.concurrent.TimeUnit;
michael@0:
michael@0: import org.mozilla.gecko.background.common.GlobalConstants;
michael@0: import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
michael@0: import org.mozilla.gecko.sync.ExtendedJSONObject;
michael@0: import org.mozilla.gecko.sync.SyncConfiguration;
michael@0: import org.mozilla.gecko.sync.SyncConstants;
michael@0: import org.mozilla.gecko.sync.Utils;
michael@0: import org.mozilla.gecko.sync.setup.Constants;
michael@0: import org.mozilla.gecko.sync.setup.SyncAccounts;
michael@0: import org.mozilla.gecko.sync.setup.SyncAccounts.SyncAccountParameters;
michael@0:
michael@0: import android.accounts.Account;
michael@0: import android.accounts.AccountManager;
michael@0: import android.accounts.AccountManagerCallback;
michael@0: import android.accounts.AccountManagerFuture;
michael@0: import android.content.Context;
michael@0: import android.content.Intent;
michael@0: import android.content.SharedPreferences;
michael@0: import android.test.InstrumentationTestCase;
michael@0:
michael@0: /**
michael@0: * We can use performWait
and performNotify
here if we
michael@0: * are careful about threading issues with AsyncTask
. We need to
michael@0: * take some care to both create and run certain tasks on the main thread --
michael@0: * moving the object allocation out of the UI thread causes failures!
michael@0: *
michael@0: * @see "
michael@0: * http://stackoverflow.com/questions/2321829/android-asynctask-testing-problem-with-android-test-framework."
michael@0: */
michael@0: public class TestSyncAccounts extends AndroidSyncTestCase {
michael@0: private static final String TEST_USERNAME = "testAccount@mozilla.com";
michael@0: private static final String TEST_SYNCKEY = "testSyncKey";
michael@0: private static final String TEST_PASSWORD = "testPassword";
michael@0: private static final String TEST_SERVERURL = "test.server.url/";
michael@0: private static final String TEST_CLUSTERURL = "test.cluster.url/";
michael@0:
michael@0: public static final String TEST_ACCOUNTTYPE = SyncConstants.ACCOUNTTYPE_SYNC;
michael@0:
michael@0: public static final String TEST_PRODUCT = GlobalConstants.BROWSER_INTENT_PACKAGE;
michael@0: public static final String TEST_PROFILE = Constants.DEFAULT_PROFILE;
michael@0: public static final long TEST_VERSION = SyncConfiguration.CURRENT_PREFS_VERSION;
michael@0:
michael@0: public static final String TEST_PREFERENCE = "testPreference";
michael@0: public static final String TEST_SYNC_ID = "testSyncID";
michael@0:
michael@0: private Account account;
michael@0: private Context context;
michael@0: private AccountManager accountManager;
michael@0: private SyncAccountParameters syncAccount;
michael@0:
michael@0: public void setUp() {
michael@0: account = null;
michael@0: context = getApplicationContext();
michael@0: accountManager = AccountManager.get(context);
michael@0: syncAccount = new SyncAccountParameters(context, null,
michael@0: TEST_USERNAME, TEST_SYNCKEY, TEST_PASSWORD, null);
michael@0: }
michael@0:
michael@0: public static void deleteAccount(final InstrumentationTestCase test, final AccountManager accountManager, final Account account) {
michael@0: performWait(new Runnable() {
michael@0: @Override
michael@0: public void run() {
michael@0: try {
michael@0: test.runTestOnUiThread(new Runnable() {
michael@0: final AccountManagerCallback callback = new AccountManagerCallback() {
michael@0: @Override
michael@0: public void run(AccountManagerFuture future) {
michael@0: try {
michael@0: future.getResult(5L, TimeUnit.SECONDS);
michael@0: } catch (Exception e) {
michael@0: }
michael@0: performNotify();
michael@0: }
michael@0: };
michael@0:
michael@0: @Override
michael@0: public void run() {
michael@0: accountManager.removeAccount(account, callback, null);
michael@0: }
michael@0: });
michael@0: } catch (Throwable e) {
michael@0: performNotify(e);
michael@0: }
michael@0: }
michael@0: });
michael@0: }
michael@0:
michael@0: public void tearDown() {
michael@0: if (account == null) {
michael@0: return;
michael@0: }
michael@0: deleteAccount(this, accountManager, account);
michael@0: account = null;
michael@0: }
michael@0:
michael@0: public void testSyncAccountParameters() {
michael@0: assertEquals(TEST_USERNAME, syncAccount.username);
michael@0: assertNull(syncAccount.accountManager);
michael@0: assertNull(syncAccount.serverURL);
michael@0:
michael@0: try {
michael@0: syncAccount = new SyncAccountParameters(context, null,
michael@0: null, TEST_SYNCKEY, TEST_PASSWORD, TEST_SERVERURL);
michael@0: } catch (IllegalArgumentException e) {
michael@0: return;
michael@0: } catch (Exception e) {
michael@0: fail("Did not expect exception: " + e);
michael@0: }
michael@0: fail("Expected IllegalArgumentException.");
michael@0: }
michael@0:
michael@0: public void testCreateAccount() {
michael@0: int before = accountManager.getAccountsByType(TEST_ACCOUNTTYPE).length;
michael@0: account = SyncAccounts.createSyncAccount(syncAccount, false);
michael@0: int afterCreate = accountManager.getAccountsByType(TEST_ACCOUNTTYPE).length;
michael@0: assertTrue(afterCreate > before);
michael@0: deleteAccount(this, accountManager, account);
michael@0: account = null;
michael@0: int afterDelete = accountManager.getAccountsByType(TEST_ACCOUNTTYPE).length;
michael@0: assertEquals(before, afterDelete);
michael@0: }
michael@0:
michael@0: public void testCreateSecondAccount() {
michael@0: int before = accountManager.getAccountsByType(TEST_ACCOUNTTYPE).length;
michael@0: account = SyncAccounts.createSyncAccount(syncAccount, false);
michael@0: int afterFirst = accountManager.getAccountsByType(TEST_ACCOUNTTYPE).length;
michael@0: assertTrue(afterFirst > before);
michael@0:
michael@0: SyncAccountParameters secondSyncAccount = new SyncAccountParameters(context, null,
michael@0: "second@username.com", TEST_SYNCKEY, TEST_PASSWORD, null);
michael@0:
michael@0: Account second = SyncAccounts.createSyncAccount(secondSyncAccount, false);
michael@0: assertNotNull(second);
michael@0: int afterSecond = accountManager.getAccountsByType(TEST_ACCOUNTTYPE).length;
michael@0: assertTrue(afterSecond > afterFirst);
michael@0:
michael@0: deleteAccount(this, accountManager, second);
michael@0: deleteAccount(this, accountManager, account);
michael@0: account = null;
michael@0:
michael@0: int afterDelete = accountManager.getAccountsByType(TEST_ACCOUNTTYPE).length;
michael@0: assertEquals(before, afterDelete);
michael@0: }
michael@0:
michael@0: public void testCreateDuplicateAccount() {
michael@0: int before = accountManager.getAccountsByType(TEST_ACCOUNTTYPE).length;
michael@0: account = SyncAccounts.createSyncAccount(syncAccount, false);
michael@0: int afterCreate = accountManager.getAccountsByType(TEST_ACCOUNTTYPE).length;
michael@0: assertTrue(afterCreate > before);
michael@0:
michael@0: Account dupe = SyncAccounts.createSyncAccount(syncAccount, false);
michael@0: assertNull(dupe);
michael@0: }
michael@0:
michael@0: public void testClientRecord() throws NoSuchAlgorithmException, UnsupportedEncodingException {
michael@0: final String TEST_NAME = "testName";
michael@0: final String TEST_GUID = "testGuid";
michael@0: syncAccount = new SyncAccountParameters(context, null,
michael@0: TEST_USERNAME, TEST_SYNCKEY, TEST_PASSWORD, null, null, TEST_NAME, TEST_GUID);
michael@0: account = SyncAccounts.createSyncAccount(syncAccount, false);
michael@0: assertNotNull(account);
michael@0:
michael@0: SharedPreferences prefs = Utils.getSharedPreferences(context, TEST_PRODUCT, TEST_USERNAME,
michael@0: SyncConstants.DEFAULT_AUTH_SERVER, TEST_PROFILE, TEST_VERSION);
michael@0:
michael@0: // Verify that client record is set.
michael@0: assertEquals(TEST_GUID, prefs.getString(SyncConfiguration.PREF_ACCOUNT_GUID, null));
michael@0: assertEquals(TEST_NAME, prefs.getString(SyncConfiguration.PREF_CLIENT_NAME, null));
michael@0:
michael@0: // Let's verify that clusterURL is correctly not set.
michael@0: String clusterURL = prefs.getString(SyncConfiguration.PREF_CLUSTER_URL, null);
michael@0: assertNull(clusterURL);
michael@0: }
michael@0:
michael@0: public void testClusterURL() throws NoSuchAlgorithmException, UnsupportedEncodingException {
michael@0: syncAccount = new SyncAccountParameters(context, null,
michael@0: TEST_USERNAME, TEST_SYNCKEY, TEST_PASSWORD, TEST_SERVERURL, TEST_CLUSTERURL, null, null);
michael@0: account = SyncAccounts.createSyncAccount(syncAccount, false);
michael@0: assertNotNull(account);
michael@0:
michael@0: SharedPreferences prefs = Utils.getSharedPreferences(context, TEST_PRODUCT, TEST_USERNAME,
michael@0: TEST_SERVERURL, TEST_PROFILE, TEST_VERSION);
michael@0: String clusterURL = prefs.getString(SyncConfiguration.PREF_CLUSTER_URL, null);
michael@0: assertNotNull(clusterURL);
michael@0: assertEquals(TEST_CLUSTERURL, clusterURL);
michael@0:
michael@0: // Let's verify that client name and GUID are not set.
michael@0: assertNull(prefs.getString(SyncConfiguration.PREF_ACCOUNT_GUID, null));
michael@0: assertNull(prefs.getString(SyncConfiguration.PREF_CLIENT_NAME, null));
michael@0: }
michael@0:
michael@0: /**
michael@0: * Verify that creating an account wipes stale settings in Shared Preferences.
michael@0: */
michael@0: public void testCreatingWipesSharedPrefs() throws Exception {
michael@0: final String TEST_PREFERENCE = "testPreference";
michael@0: final String TEST_SYNC_ID = "testSyncID";
michael@0:
michael@0: SharedPreferences prefs = Utils.getSharedPreferences(context, TEST_PRODUCT, TEST_USERNAME,
michael@0: TEST_SERVERURL, TEST_PROFILE, TEST_VERSION);
michael@0: prefs.edit().putString(SyncConfiguration.PREF_SYNC_ID, TEST_SYNC_ID).commit();
michael@0: prefs.edit().putString(TEST_PREFERENCE, TEST_SYNC_ID).commit();
michael@0:
michael@0: syncAccount = new SyncAccountParameters(context, null,
michael@0: TEST_USERNAME, TEST_SYNCKEY, TEST_PASSWORD, TEST_SERVERURL);
michael@0: account = SyncAccounts.createSyncAccount(syncAccount, false);
michael@0: assertNotNull(account);
michael@0:
michael@0: // All values deleted (known and unknown).
michael@0: assertNull(prefs.getString(SyncConfiguration.PREF_SYNC_ID, null));
michael@0: assertNull(prefs.getString(TEST_SYNC_ID, null));
michael@0: }
michael@0:
michael@0: /**
michael@0: * Verify that creating an account preserves settings in Shared Preferences when asked.
michael@0: */
michael@0: public void testCreateSyncAccountWithExistingPreferences() throws Exception {
michael@0:
michael@0: SharedPreferences prefs = Utils.getSharedPreferences(context, TEST_PRODUCT, TEST_USERNAME,
michael@0: TEST_SERVERURL, TEST_PROFILE, TEST_VERSION);
michael@0:
michael@0: prefs.edit().putString(SyncConfiguration.PREF_SYNC_ID, TEST_SYNC_ID).commit();
michael@0: prefs.edit().putString(TEST_PREFERENCE, TEST_SYNC_ID).commit();
michael@0:
michael@0: assertNotNull(prefs.getString(TEST_PREFERENCE, null));
michael@0: assertNotNull(prefs.getString(SyncConfiguration.PREF_SYNC_ID, null));
michael@0:
michael@0: syncAccount = new SyncAccountParameters(context, null,
michael@0: TEST_USERNAME, TEST_SYNCKEY, TEST_PASSWORD, TEST_SERVERURL);
michael@0: account = SyncAccounts.createSyncAccountPreservingExistingPreferences(syncAccount, false);
michael@0: assertNotNull(account);
michael@0:
michael@0: // All values remain (known and unknown).
michael@0: assertNotNull(prefs.getString(TEST_PREFERENCE, null));
michael@0: assertNotNull(prefs.getString(SyncConfiguration.PREF_SYNC_ID, null));
michael@0: }
michael@0:
michael@0: protected void assertParams(final SyncAccountParameters params) throws Exception {
michael@0: assertNotNull(params);
michael@0: assertEquals(context, params.context);
michael@0: assertEquals(Utils.usernameFromAccount(TEST_USERNAME), params.username);
michael@0: assertEquals(TEST_PASSWORD, params.password);
michael@0: assertEquals(TEST_SERVERURL, params.serverURL);
michael@0: assertEquals(TEST_SYNCKEY, params.syncKey);
michael@0: }
michael@0:
michael@0: public void testBlockingFromAndroidAccountV0() throws Throwable {
michael@0: syncAccount = new SyncAccountParameters(context, null,
michael@0: TEST_USERNAME, TEST_SYNCKEY, TEST_PASSWORD, TEST_SERVERURL, TEST_CLUSTERURL, null, null);
michael@0: try {
michael@0: account = SyncAccounts.createSyncAccount(syncAccount);
michael@0: assertNotNull(account);
michael@0:
michael@0: // Test fetching parameters multiple times. Historically, we needed to
michael@0: // invalidate this token type every fetch; now we don't, but we'd like
michael@0: // to ensure multiple fetches work.
michael@0: SyncAccountParameters params = SyncAccounts.blockingFromAndroidAccountV0(context, accountManager, account);
michael@0: assertParams(params);
michael@0:
michael@0: params = SyncAccounts.blockingFromAndroidAccountV0(context, accountManager, account);
michael@0: assertParams(params);
michael@0:
michael@0: // Test this works on the main thread.
michael@0: this.runTestOnUiThread(new Runnable() {
michael@0: @Override
michael@0: public void run() {
michael@0: SyncAccountParameters params;
michael@0: try {
michael@0: params = SyncAccounts.blockingFromAndroidAccountV0(context, accountManager, account);
michael@0: assertParams(params);
michael@0: } catch (Exception e) {
michael@0: fail("Fetching Sync account parameters failed on UI thread.");
michael@0: }
michael@0: }
michael@0: });
michael@0: } finally {
michael@0: if (account != null) {
michael@0: deleteAccount(this, accountManager, account);
michael@0: account = null;
michael@0: }
michael@0: }
michael@0: }
michael@0:
michael@0: public void testMakeSyncAccountDeletedIntent() throws Throwable {
michael@0: syncAccount = new SyncAccountParameters(context, null,
michael@0: TEST_USERNAME, TEST_SYNCKEY, TEST_PASSWORD, TEST_SERVERURL, TEST_CLUSTERURL, null, null);
michael@0: try {
michael@0: account = SyncAccounts.createSyncAccount(syncAccount);
michael@0: assertNotNull(account);
michael@0:
michael@0: Intent intent = SyncAccounts.makeSyncAccountDeletedIntent(context, accountManager, account);
michael@0: assertEquals(SyncConstants.SYNC_ACCOUNT_DELETED_ACTION, intent.getAction());
michael@0: assertEquals(SyncConstants.SYNC_ACCOUNT_DELETED_INTENT_VERSION, intent.getLongExtra(Constants.JSON_KEY_VERSION, 0));
michael@0: assertEquals(TEST_USERNAME, intent.getStringExtra(Constants.JSON_KEY_ACCOUNT));
michael@0: assertTrue(Math.abs(intent.getLongExtra(Constants.JSON_KEY_TIMESTAMP, 0) - System.currentTimeMillis()) < 1000);
michael@0:
michael@0: String payload = intent.getStringExtra(Constants.JSON_KEY_PAYLOAD);
michael@0: assertNotNull(payload);
michael@0:
michael@0: SyncAccountParameters params = new SyncAccountParameters(context, accountManager, ExtendedJSONObject.parseJSONObject(payload));
michael@0: // Can't use assertParams because Sync key is deleted.
michael@0: assertNotNull(params);
michael@0: assertEquals(context, params.context);
michael@0: assertEquals(Utils.usernameFromAccount(TEST_USERNAME), params.username);
michael@0: assertEquals(TEST_PASSWORD, params.password);
michael@0: assertEquals(TEST_SERVERURL, params.serverURL);
michael@0: assertEquals("", params.syncKey);
michael@0: } finally {
michael@0: if (account != null) {
michael@0: deleteAccount(this, accountManager, account);
michael@0: account = null;
michael@0: }
michael@0: }
michael@0: }
michael@0:
michael@0: public void testBlockingPrefsFromAndroidAccountV0() throws Exception {
michael@0: // Create test account with prefs. We use a different username to avoid a
michael@0: // timing issue, where the delayed clean-up of the account created by the
michael@0: // previous test deletes the preferences for this account.
michael@0: SharedPreferences prefs = Utils.getSharedPreferences(context, TEST_PRODUCT,
michael@0: TEST_USERNAME + "2", TEST_SERVERURL, TEST_PROFILE, TEST_VERSION);
michael@0: prefs.edit().putString(TEST_PREFERENCE, TEST_SYNC_ID).commit();
michael@0:
michael@0: syncAccount = new SyncAccountParameters(context, null,
michael@0: TEST_USERNAME + "2", TEST_SYNCKEY, TEST_PASSWORD, TEST_SERVERURL);
michael@0: account = SyncAccounts.createSyncAccountPreservingExistingPreferences(syncAccount, false);
michael@0: assertNotNull(account);
michael@0:
michael@0: // Fetch account and check prefs.
michael@0: SharedPreferences sharedPreferences = SyncAccounts.blockingPrefsFromAndroidAccountV0(context, accountManager,
michael@0: account, TEST_PRODUCT, TEST_PROFILE, TEST_VERSION);
michael@0: assertNotNull(sharedPreferences);
michael@0: assertEquals(TEST_SYNC_ID, sharedPreferences.getString(TEST_PREFERENCE, null));
michael@0: }
michael@0: }