| // Copyright 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package org.chromium.sync.notifier.signin; |
| |
| import android.accounts.Account; |
| import android.content.Context; |
| import android.test.InstrumentationTestCase; |
| import android.test.suitebuilder.annotation.SmallTest; |
| |
| import org.chromium.base.ThreadUtils; |
| import org.chromium.base.test.util.Feature; |
| import org.chromium.sync.notifier.SyncStatusHelper; |
| import org.chromium.sync.notifier.SyncStatusHelper.CachedAccountSyncSettings; |
| import org.chromium.sync.notifier.SyncStatusHelper.SyncSettingsChangedObserver; |
| import org.chromium.sync.signin.ChromeSigninController; |
| import org.chromium.sync.test.util.MockSyncContentResolverDelegate; |
| |
| public class SyncStatusHelperTest extends InstrumentationTestCase { |
| |
| private static class CountingMockSyncContentResolverDelegate |
| extends MockSyncContentResolverDelegate { |
| private int mGetMasterSyncAutomaticallyCalls; |
| private int mGetSyncAutomaticallyCalls; |
| private int mGetIsSyncableCalls; |
| private int mSetIsSyncableCalls; |
| private int mSetSyncAutomaticallyCalls; |
| |
| @Override |
| public boolean getMasterSyncAutomatically() { |
| mGetMasterSyncAutomaticallyCalls++; |
| return super.getMasterSyncAutomatically(); |
| } |
| |
| @Override |
| public boolean getSyncAutomatically(Account account, String authority) { |
| mGetSyncAutomaticallyCalls++; |
| return super.getSyncAutomatically(account, authority); |
| } |
| |
| @Override |
| public int getIsSyncable(Account account, String authority) { |
| mGetIsSyncableCalls++; |
| return super.getIsSyncable(account, authority); |
| } |
| |
| @Override |
| public void setIsSyncable(Account account, String authority, int syncable) { |
| mSetIsSyncableCalls++; |
| super.setIsSyncable(account, authority, syncable); |
| } |
| |
| @Override |
| public void setSyncAutomatically(Account account, String authority, boolean sync) { |
| mSetSyncAutomaticallyCalls++; |
| super.setSyncAutomatically(account, authority, sync); |
| } |
| } |
| |
| private static class CountingCachedAccountSyncSettings extends CachedAccountSyncSettings { |
| private int mUpdateSyncSettingsForAccountInternalCalls; |
| private int mSetIsSyncableInternalCalls; |
| private int mSetSyncAutomaticallyInternalCalls; |
| |
| public CountingCachedAccountSyncSettings(String contractAuthority, |
| MockSyncContentResolverDelegate contentResolverWrapper) { |
| super(contractAuthority, contentResolverWrapper); |
| } |
| |
| @Override |
| protected void updateSyncSettingsForAccountInternal(Account account) { |
| mUpdateSyncSettingsForAccountInternalCalls++; |
| super.updateSyncSettingsForAccountInternal(account); |
| } |
| |
| @Override |
| protected void setIsSyncableInternal(Account account) { |
| mSetIsSyncableInternalCalls++; |
| super.setIsSyncableInternal(account); |
| } |
| |
| @Override |
| protected void setSyncAutomaticallyInternal(Account account, boolean value) { |
| mSetSyncAutomaticallyInternalCalls++; |
| super.setSyncAutomaticallyInternal(account, value); |
| } |
| |
| public void resetCount() { |
| mUpdateSyncSettingsForAccountInternalCalls = 0; |
| } |
| } |
| |
| private static class MockSyncSettingsObserver implements SyncSettingsChangedObserver { |
| private boolean mReceivedNotification; |
| |
| public void clearNotification() { |
| mReceivedNotification = false; |
| } |
| |
| public boolean didReceiveNotification() { |
| return mReceivedNotification; |
| } |
| |
| @Override |
| public void syncSettingsChanged() { |
| mReceivedNotification = true; |
| } |
| } |
| |
| private SyncStatusHelper mHelper; |
| private CountingMockSyncContentResolverDelegate mSyncContentResolverDelegate; |
| private String mAuthority; |
| private Account mTestAccount; |
| private Account mAlternateTestAccount; |
| private CountingCachedAccountSyncSettings mCachedAccountSyncSettings; |
| private MockSyncSettingsObserver mSyncSettingsObserver; |
| |
| @Override |
| protected void setUp() throws Exception { |
| mSyncContentResolverDelegate = new CountingMockSyncContentResolverDelegate(); |
| Context context = getInstrumentation().getTargetContext(); |
| mCachedAccountSyncSettings = new CountingCachedAccountSyncSettings( |
| context.getPackageName(), mSyncContentResolverDelegate); |
| SyncStatusHelper.overrideSyncStatusHelperForTests( |
| context, mSyncContentResolverDelegate, mCachedAccountSyncSettings); |
| mHelper = SyncStatusHelper.get(getInstrumentation().getTargetContext()); |
| // Need to set the signed in account name to ensure that sync settings notifications |
| // update the right account. |
| ChromeSigninController.get( |
| getInstrumentation().getTargetContext()).setSignedInAccountName( |
| "account@example.com"); |
| mAuthority = SyncStatusHelper.get(getInstrumentation().getTargetContext()) |
| .getContractAuthority(); |
| mTestAccount = new Account("account@example.com", "com.google"); |
| mAlternateTestAccount = new Account("alternateAccount@example.com", "com.google"); |
| |
| mSyncSettingsObserver = new MockSyncSettingsObserver(); |
| mHelper.registerSyncSettingsChangedObserver(mSyncSettingsObserver); |
| |
| super.setUp(); |
| } |
| |
| @SmallTest |
| @Feature({"Sync"}) |
| public void testToggleMasterSyncAutomaticallyFromSettings() throws InterruptedException { |
| mSyncContentResolverDelegate.setMasterSyncAutomatically(true); |
| mSyncContentResolverDelegate.waitForLastNotificationCompleted(); |
| assertTrue("master sync should be set", mHelper.isMasterSyncAutomaticallyEnabled()); |
| |
| mSyncContentResolverDelegate.setMasterSyncAutomatically(false); |
| mSyncContentResolverDelegate.waitForLastNotificationCompleted(); |
| assertFalse("master sync should be unset", mHelper.isMasterSyncAutomaticallyEnabled()); |
| } |
| |
| @SmallTest |
| @Feature({"Sync"}) |
| public void testToggleAccountSyncFromSettings() throws InterruptedException { |
| // Turn on syncability. |
| mSyncContentResolverDelegate.setMasterSyncAutomatically(true); |
| mSyncContentResolverDelegate.waitForLastNotificationCompleted(); |
| |
| // First sync |
| mSyncContentResolverDelegate.setIsSyncable(mTestAccount, mAuthority, 1); |
| mSyncContentResolverDelegate.waitForLastNotificationCompleted(); |
| mSyncContentResolverDelegate.setSyncAutomatically(mTestAccount, mAuthority, true); |
| mSyncContentResolverDelegate.waitForLastNotificationCompleted(); |
| assertTrue("sync should be set", mHelper.isSyncEnabled(mTestAccount)); |
| assertTrue("sync should be set for chrome app", |
| mHelper.isSyncEnabledForChrome(mTestAccount)); |
| |
| // Disable sync automatically for the app |
| mSyncContentResolverDelegate.setSyncAutomatically(mTestAccount, mAuthority, false); |
| mSyncContentResolverDelegate.waitForLastNotificationCompleted(); |
| assertFalse("sync should be unset", mHelper.isSyncEnabled(mTestAccount)); |
| assertFalse("sync should be unset for chrome app", |
| mHelper.isSyncEnabledForChrome(mTestAccount)); |
| |
| // Re-enable sync |
| mSyncContentResolverDelegate.setSyncAutomatically(mTestAccount, mAuthority, true); |
| mSyncContentResolverDelegate.waitForLastNotificationCompleted(); |
| assertTrue("sync should be re-enabled", mHelper.isSyncEnabled(mTestAccount)); |
| assertTrue("sync should be unset for chrome app", |
| mHelper.isSyncEnabledForChrome(mTestAccount)); |
| |
| // Disabled from master sync |
| mSyncContentResolverDelegate.setMasterSyncAutomatically(false); |
| mSyncContentResolverDelegate.waitForLastNotificationCompleted(); |
| assertFalse("sync should be disabled due to master sync", |
| mHelper.isSyncEnabled(mTestAccount)); |
| assertTrue("sync should be set for chrome app", |
| mHelper.isSyncEnabledForChrome(mTestAccount)); |
| } |
| |
| @SmallTest |
| @Feature({"Sync"}) |
| public void testToggleAccountSyncFromApplication() throws InterruptedException { |
| // Turn on syncability. |
| mSyncContentResolverDelegate.setMasterSyncAutomatically(true); |
| mSyncContentResolverDelegate.waitForLastNotificationCompleted(); |
| |
| ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
| @Override |
| public void run() { |
| mHelper.enableAndroidSync(mTestAccount); |
| } |
| }); |
| mSyncContentResolverDelegate.waitForLastNotificationCompleted(); |
| assertTrue("account should be synced", mHelper.isSyncEnabled(mTestAccount)); |
| |
| ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
| @Override |
| public void run() { |
| mHelper.disableAndroidSync(mTestAccount); |
| } |
| }); |
| mSyncContentResolverDelegate.waitForLastNotificationCompleted(); |
| assertFalse("account should not be synced", mHelper.isSyncEnabled(mTestAccount)); |
| } |
| |
| @SmallTest |
| @Feature({"Sync"}) |
| public void testToggleSyncabilityForMultipleAccounts() throws InterruptedException { |
| // Turn on syncability. |
| mSyncContentResolverDelegate.setMasterSyncAutomatically(true); |
| mSyncContentResolverDelegate.waitForLastNotificationCompleted(); |
| |
| ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
| @Override |
| public void run() { |
| mHelper.enableAndroidSync(mTestAccount); |
| } |
| }); |
| mSyncContentResolverDelegate.waitForLastNotificationCompleted(); |
| assertTrue("account should be synced", mHelper.isSyncEnabled(mTestAccount)); |
| |
| ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
| @Override |
| public void run() { |
| mHelper.enableAndroidSync(mAlternateTestAccount); |
| } |
| }); |
| mSyncContentResolverDelegate.waitForLastNotificationCompleted(); |
| assertTrue("alternate account should be synced", |
| mHelper.isSyncEnabled(mAlternateTestAccount)); |
| |
| ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
| @Override |
| public void run() { |
| mHelper.disableAndroidSync(mAlternateTestAccount); |
| } |
| }); |
| mSyncContentResolverDelegate.waitForLastNotificationCompleted(); |
| assertFalse("alternate account should not be synced", |
| mHelper.isSyncEnabled(mAlternateTestAccount)); |
| assertTrue("account should still be synced", mHelper.isSyncEnabled(mTestAccount)); |
| |
| // Ensure we don't erroneously re-use cached data. |
| assertFalse("null account should not be synced", mHelper.isSyncEnabled(null)); |
| } |
| |
| @SmallTest |
| @Feature({"Sync"}) |
| public void testSyncSettingsCaching() throws InterruptedException { |
| // Turn on syncability. |
| mSyncContentResolverDelegate.setMasterSyncAutomatically(true); |
| mSyncContentResolverDelegate.waitForLastNotificationCompleted(); |
| |
| ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
| @Override |
| public void run() { |
| mHelper.enableAndroidSync(mTestAccount); |
| } |
| }); |
| mSyncContentResolverDelegate.waitForLastNotificationCompleted(); |
| assertTrue("account should be synced", mHelper.isSyncEnabled(mTestAccount)); |
| |
| int masterSyncAutomaticallyCalls = |
| mSyncContentResolverDelegate.mGetMasterSyncAutomaticallyCalls; |
| int isSyncableCalls = mSyncContentResolverDelegate.mGetIsSyncableCalls; |
| int getSyncAutomaticallyAcalls = mSyncContentResolverDelegate.mGetSyncAutomaticallyCalls; |
| |
| // Do a bunch of reads. |
| mHelper.isMasterSyncAutomaticallyEnabled(); |
| mHelper.isSyncEnabled(); |
| mHelper.isSyncEnabled(mTestAccount); |
| mHelper.isSyncEnabledForChrome(mTestAccount); |
| |
| // Ensure values were read from cache. |
| assertEquals(masterSyncAutomaticallyCalls, |
| mSyncContentResolverDelegate.mGetMasterSyncAutomaticallyCalls); |
| assertEquals(isSyncableCalls, mSyncContentResolverDelegate.mGetIsSyncableCalls); |
| assertEquals(getSyncAutomaticallyAcalls, |
| mSyncContentResolverDelegate.mGetSyncAutomaticallyCalls); |
| |
| // Do a bunch of reads for alternate account. |
| mHelper.isMasterSyncAutomaticallyEnabled(); |
| mHelper.isSyncEnabled(mAlternateTestAccount); |
| mHelper.isSyncEnabledForChrome(mAlternateTestAccount); |
| |
| // Ensure master sync was cached but others are fetched once. |
| assertEquals(masterSyncAutomaticallyCalls, |
| mSyncContentResolverDelegate.mGetMasterSyncAutomaticallyCalls); |
| assertEquals(isSyncableCalls + 1, mSyncContentResolverDelegate.mGetIsSyncableCalls); |
| assertEquals(getSyncAutomaticallyAcalls + 1, |
| mSyncContentResolverDelegate.mGetSyncAutomaticallyCalls); |
| } |
| |
| @SmallTest |
| @Feature({"Sync"}) |
| public void testGetContractAuthority() throws Exception { |
| assertEquals("The contract authority should be the package name.", |
| getInstrumentation().getTargetContext().getPackageName(), |
| mHelper.getContractAuthority()); |
| } |
| |
| @SmallTest |
| @Feature({"Sync"}) |
| public void testCachedAccountSyncSettingsExitEarly() throws InterruptedException { |
| mSyncContentResolverDelegate.disableObserverNotifications(); |
| |
| mCachedAccountSyncSettings.updateSyncSettingsForAccount(null); |
| assertTrue("Update sync settings failed to exit early", mCachedAccountSyncSettings |
| .mUpdateSyncSettingsForAccountInternalCalls == 0); |
| |
| mCachedAccountSyncSettings.updateSyncSettingsForAccount(mTestAccount); |
| assertTrue("Update sync settings should not have exited early", mCachedAccountSyncSettings |
| .mUpdateSyncSettingsForAccountInternalCalls == 1); |
| |
| mCachedAccountSyncSettings.setIsSyncable(mTestAccount); |
| assertTrue("setIsSyncable should not have exited early", |
| mCachedAccountSyncSettings.mSetIsSyncableInternalCalls == 1); |
| |
| mCachedAccountSyncSettings.setIsSyncable(mTestAccount); |
| assertTrue("setIsSyncable failed to exit early", mCachedAccountSyncSettings |
| .mSetIsSyncableInternalCalls == 1); |
| |
| mCachedAccountSyncSettings.setSyncAutomatically(mTestAccount, true); |
| assertTrue("setSyncAutomatically should not have to exited early", |
| mCachedAccountSyncSettings.mSetSyncAutomaticallyInternalCalls == 1); |
| |
| mCachedAccountSyncSettings.setSyncAutomatically(mTestAccount, true); |
| assertTrue("setSyncAutomatically failed to exit early", |
| mCachedAccountSyncSettings.mSetSyncAutomaticallyInternalCalls == 1); |
| |
| mCachedAccountSyncSettings.setSyncAutomatically(mTestAccount, false); |
| assertTrue("setSyncAutomatically should not have to exited early", |
| mCachedAccountSyncSettings.mSetSyncAutomaticallyInternalCalls == 2); |
| |
| mCachedAccountSyncSettings.setSyncAutomatically(mTestAccount, false); |
| assertTrue("setSyncAutomatically failed to exit early", |
| mCachedAccountSyncSettings.mSetSyncAutomaticallyInternalCalls == 2); |
| } |
| |
| @SmallTest |
| @Feature({"Sync"}) |
| public void testCachedAccountSyncSettingsDidUpdate() throws InterruptedException { |
| // Since we're just testing the cache we disable observer notifications to prevent |
| // notifications to SyncStatusHelper from mutating it. |
| mSyncContentResolverDelegate.disableObserverNotifications(); |
| |
| mCachedAccountSyncSettings.clearUpdateStatus(); |
| mCachedAccountSyncSettings.getSyncAutomatically(mTestAccount); |
| assertTrue("getSyncAutomatically on un-populated cache failed to update DidUpdate flag", |
| mCachedAccountSyncSettings.getDidUpdateStatus()); |
| |
| mCachedAccountSyncSettings.clearUpdateStatus(); |
| mCachedAccountSyncSettings.getSyncAutomatically(mTestAccount); |
| assertFalse("getSyncAutomatically on populated cache updated DidUpdate flag", |
| mCachedAccountSyncSettings.getDidUpdateStatus()); |
| |
| mCachedAccountSyncSettings.updateSyncSettingsForAccount(mAlternateTestAccount); |
| assertTrue("updateSyncSettingsForAccount failed to update DidUpdate flag", |
| mCachedAccountSyncSettings.getDidUpdateStatus()); |
| |
| mCachedAccountSyncSettings.clearUpdateStatus(); |
| |
| mCachedAccountSyncSettings.updateSyncSettingsForAccount(mTestAccount); |
| assertTrue("updateSyncSettingsForAccount failed to update DidUpdate flag", |
| mCachedAccountSyncSettings.getDidUpdateStatus()); |
| |
| mCachedAccountSyncSettings.clearUpdateStatus(); |
| |
| mCachedAccountSyncSettings.updateSyncSettingsForAccount(mTestAccount); |
| assertFalse("updateSyncSettingsForAccount updated DidUpdate flag", |
| mCachedAccountSyncSettings.getDidUpdateStatus()); |
| |
| mCachedAccountSyncSettings.clearUpdateStatus(); |
| mCachedAccountSyncSettings.setIsSyncable(mTestAccount); |
| assertTrue("setIsSyncable failed to update DidUpdate flag", |
| mCachedAccountSyncSettings.getDidUpdateStatus()); |
| |
| mCachedAccountSyncSettings.clearUpdateStatus(); |
| mCachedAccountSyncSettings.setIsSyncable(mTestAccount); |
| assertFalse("setIsSyncable updated DidUpdate flag", |
| mCachedAccountSyncSettings.getDidUpdateStatus()); |
| |
| mCachedAccountSyncSettings.clearUpdateStatus(); |
| mCachedAccountSyncSettings.setSyncAutomatically(mTestAccount, true); |
| assertTrue("setSyncAutomatically failed to update DidUpdate flag", |
| mCachedAccountSyncSettings.getDidUpdateStatus()); |
| |
| mCachedAccountSyncSettings.clearUpdateStatus(); |
| mCachedAccountSyncSettings.setSyncAutomatically(mTestAccount, true); |
| assertFalse("setSyncAutomatically updated DidUpdate flag", |
| mCachedAccountSyncSettings.getDidUpdateStatus()); |
| |
| mCachedAccountSyncSettings.clearUpdateStatus(); |
| mCachedAccountSyncSettings.setSyncAutomatically(mTestAccount, false); |
| assertTrue("setSyncAutomatically failed to update DidUpdate flag", |
| mCachedAccountSyncSettings.getDidUpdateStatus()); |
| |
| mCachedAccountSyncSettings.clearUpdateStatus(); |
| mCachedAccountSyncSettings.setSyncAutomatically(mTestAccount, false); |
| assertFalse("setSyncAutomatically updated DidUpdate flag", |
| mCachedAccountSyncSettings.getDidUpdateStatus()); |
| } |
| |
| @SmallTest |
| @Feature({"Sync"}) |
| public void testSyncStatusHelperPostsNotifications() throws InterruptedException { |
| // Turn on syncability. |
| mSyncContentResolverDelegate.setMasterSyncAutomatically(true); |
| mSyncContentResolverDelegate.waitForLastNotificationCompleted(); |
| |
| mSyncSettingsObserver.clearNotification(); |
| mHelper.isSyncEnabled(mAlternateTestAccount); |
| assertTrue("isSyncEnabled on wrongly populated cache did not trigger observers", |
| mSyncSettingsObserver.didReceiveNotification()); |
| |
| mSyncSettingsObserver.clearNotification(); |
| mHelper.isSyncEnabled(mTestAccount); |
| assertTrue("isSyncEnabled on wrongly populated cache did not trigger observers", |
| mSyncSettingsObserver.didReceiveNotification()); |
| |
| mSyncSettingsObserver.clearNotification(); |
| mHelper.enableAndroidSync(mTestAccount); |
| assertTrue("enableAndroidSync did not trigger observers", |
| mSyncSettingsObserver.didReceiveNotification()); |
| |
| mSyncSettingsObserver.clearNotification(); |
| mHelper.enableAndroidSync(mTestAccount); |
| assertFalse("enableAndroidSync triggered observers", |
| mSyncSettingsObserver.didReceiveNotification()); |
| |
| mSyncSettingsObserver.clearNotification(); |
| mHelper.disableAndroidSync(mTestAccount); |
| assertTrue("disableAndroidSync did not trigger observers", |
| mSyncSettingsObserver.didReceiveNotification()); |
| |
| mSyncSettingsObserver.clearNotification(); |
| mHelper.disableAndroidSync(mTestAccount); |
| assertFalse("disableAndroidSync triggered observers", |
| mSyncSettingsObserver.didReceiveNotification()); |
| } |
| } |