root/sync/android/javatests/src/org/chromium/sync/notifier/signin/SyncStatusHelperTest.java

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. getMasterSyncAutomatically
  2. getSyncAutomatically
  3. getIsSyncable
  4. setIsSyncable
  5. setSyncAutomatically
  6. updateSyncSettingsForAccountInternal
  7. setIsSyncableInternal
  8. setSyncAutomaticallyInternal
  9. resetCount
  10. clearNotification
  11. didReceiveNotification
  12. syncSettingsChanged
  13. setUp
  14. Feature
  15. testToggleMasterSyncAutomaticallyFromSettings
  16. Feature
  17. testToggleAccountSyncFromSettings
  18. Feature
  19. testToggleAccountSyncFromApplication
  20. Feature
  21. testToggleSyncabilityForMultipleAccounts
  22. Feature
  23. testSyncSettingsCaching
  24. Feature
  25. testGetContractAuthority
  26. Feature
  27. testCachedAccountSyncSettingsExitEarly
  28. Feature
  29. testCachedAccountSyncSettingsDidUpdate
  30. Feature
  31. testSyncStatusHelperPostsNotifications

// 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());
    }
}

/* [<][>][^][v][top][bottom][index][help] */