blob: c9b5d33a5bef9242d2f0a44d84b5d8af63aceb3c [file] [log] [blame]
// 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());
}
}