Index: chrome/android/junit/src/org/chromium/chrome/browser/invalidations/InvalidationControllerTest.java |
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/invalidations/InvalidationControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/invalidations/InvalidationControllerTest.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3990a959887a17cd07cfaab893d0cc3dcc79d395 |
--- /dev/null |
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/invalidations/InvalidationControllerTest.java |
@@ -0,0 +1,453 @@ |
+// Copyright 2015 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.chrome.browser.invalidation; |
+ |
+import android.accounts.Account; |
+import android.app.Activity; |
+import android.content.Context; |
+import android.content.Intent; |
+ |
+import org.chromium.base.ActivityState; |
+import org.chromium.base.ApplicationState; |
+import org.chromium.base.ApplicationStatus; |
+import org.chromium.base.CollectionUtil; |
+import org.chromium.base.test.util.Feature; |
+import org.chromium.chrome.browser.sync.ProfileSyncService; |
+import org.chromium.components.invalidation.InvalidationClientService; |
+import org.chromium.sync.AndroidSyncSettings; |
+import org.chromium.sync.internal_api.pub.base.ModelType; |
+import org.chromium.sync.notifier.InvalidationIntentProtocol; |
+import org.chromium.sync.signin.ChromeSigninController; |
+import org.chromium.sync.test.util.MockSyncContentResolverDelegate; |
+import org.chromium.testing.local.LocalRobolectricTestRunner; |
+import org.junit.Assert; |
+import org.junit.Before; |
+import org.junit.Test; |
+import org.junit.runner.RunWith; |
+import org.robolectric.Robolectric; |
+import org.robolectric.annotation.Config; |
+import org.robolectric.shadows.ShadowActivity; |
+ |
+import java.util.HashSet; |
+import java.util.Set; |
+import java.util.concurrent.atomic.AtomicBoolean; |
+ |
+/** |
+ * Tests for the {@link InvalidationController}. |
+ */ |
+@RunWith(LocalRobolectricTestRunner.class) |
+@Config(manifest = Config.NONE) |
+public class InvalidationControllerTest { |
+ /** |
+ * Stubbed out ProfileSyncService with a setter to control return value of |
+ * {@link ProfileSyncService#getPreferredDataTypes()} |
+ */ |
+ private static class ProfileSyncServiceStub extends ProfileSyncService { |
+ private Set<ModelType> mPreferredDataTypes; |
+ |
+ public ProfileSyncServiceStub(Context context) { |
+ super(context); |
+ } |
+ |
+ public void setPreferredDataTypes(Set<ModelType> types) { |
+ mPreferredDataTypes = types; |
+ } |
+ |
+ @Override |
+ protected void init(Context context) { |
+ // Skip native initialization. |
+ } |
+ |
+ @Override |
+ public Set<ModelType> getPreferredDataTypes() { |
+ return mPreferredDataTypes; |
+ } |
+ } |
+ |
+ private enum IntentType { START, START_AND_REGISTER, STOP }; |
+ |
+ private ShadowActivity mShadowActivity; |
+ private Context mContext; |
+ private InvalidationController mController; |
+ |
+ /** |
+ * The names of the preferred ModelTypes. |
+ */ |
+ private Set<String> mAllTypes; |
+ |
+ /** |
+ * The names of the non-session preferred ModelTypes. |
+ */ |
+ private Set<String> mNonSessionTypes; |
+ |
+ @Before |
+ public void setUp() throws Exception { |
+ Activity activity = Robolectric.buildActivity(Activity.class).setup().get(); |
+ mShadowActivity = Robolectric.shadowOf(activity); |
+ mContext = activity; |
+ |
+ ProfileSyncServiceStub profileSyncServiceStub = new ProfileSyncServiceStub(mContext); |
+ ProfileSyncService.overrideForTests(profileSyncServiceStub); |
+ profileSyncServiceStub.setPreferredDataTypes( |
+ CollectionUtil.newHashSet(ModelType.BOOKMARK, ModelType.SESSION)); |
+ mAllTypes = CollectionUtil.newHashSet(ModelType.BOOKMARK.name(), ModelType.SESSION.name()); |
+ mNonSessionTypes = CollectionUtil.newHashSet(ModelType.BOOKMARK.name()); |
+ |
+ // We don't want to use the system content resolver, so we override it. |
+ MockSyncContentResolverDelegate delegate = new MockSyncContentResolverDelegate(); |
+ // Android master sync can safely always be on. |
+ delegate.setMasterSyncAutomatically(true); |
+ AndroidSyncSettings.overrideForTests(mContext, delegate); |
+ |
+ ChromeSigninController.get(mContext).setSignedInAccountName("test@example.com"); |
+ AndroidSyncSettings.enableChromeSync(mContext); |
+ } |
+ |
+ /** |
+ * Verify the intent sent by InvalidationController#stop(). |
+ */ |
+ @Test |
+ @Feature({"Sync"}) |
+ public void testStop() throws Exception { |
+ InvalidationController controller = new InvalidationController(mContext, true); |
+ controller.stop(); |
+ Intent intent = getOnlyIntent(); |
+ validateIntentComponent(intent); |
+ Assert.assertEquals(1, intent.getExtras().size()); |
+ Assert.assertTrue(intent.hasExtra(InvalidationIntentProtocol.EXTRA_STOP)); |
+ Assert.assertTrue(intent.getBooleanExtra(InvalidationIntentProtocol.EXTRA_STOP, false)); |
+ } |
+ |
+ /** |
+ * Verify the intent sent by InvalidationController#ensureStartedAndUpdateRegisteredTypes(). |
+ */ |
+ @Test |
+ @Feature({"Sync"}) |
+ public void testEnsureStartedAndUpdateRegisteredTypes() { |
+ InvalidationController controller = new InvalidationController(mContext, false); |
+ controller.ensureStartedAndUpdateRegisteredTypes(); |
+ Intent intent = getOnlyIntent(); |
+ |
+ // Validate destination. |
+ validateIntentComponent(intent); |
+ Assert.assertEquals(InvalidationIntentProtocol.ACTION_REGISTER, intent.getAction()); |
+ |
+ // Validate account. |
+ Account intentAccount = |
+ intent.getParcelableExtra(InvalidationIntentProtocol.EXTRA_ACCOUNT); |
+ Assert.assertEquals("test@example.com", intentAccount.name); |
+ |
+ // Validate registered types. |
+ Assert.assertEquals(mAllTypes, getRegisterIntentRegisterTypes(intent)); |
+ Assert.assertNull(InvalidationIntentProtocol.getRegisteredObjectIds(intent)); |
+ } |
+ |
+ /** |
+ * Test that pausing and resuming Chrome's activities does not send any intents if sync is |
+ * disabled. |
+ */ |
+ @Test |
+ @Feature({"Sync"}) |
+ public void testPauseAndResumeMainActivityWithSyncDisabled() throws Exception { |
+ AndroidSyncSettings.disableChromeSync(mContext); |
+ |
+ InvalidationController controller = new InvalidationController(mContext, false); |
+ controller.onApplicationStateChange(ApplicationState.HAS_PAUSED_ACTIVITIES); |
+ controller.onApplicationStateChange(ApplicationState.HAS_RUNNING_ACTIVITIES); |
+ assertNoNewIntents(); |
+ } |
+ |
+ /** |
+ * Test that creating an InvalidationController object registers an ApplicationStateListener. |
+ */ |
+ @Test |
+ @Feature({"Sync"}) |
+ public void testEnsureConstructorRegistersListener() throws Exception { |
+ final AtomicBoolean listenerCallbackCalled = new AtomicBoolean(); |
+ |
+ // Create instance. |
+ new InvalidationController(mContext, true) { |
+ @Override |
+ public void onApplicationStateChange(int newState) { |
+ listenerCallbackCalled.set(true); |
+ } |
+ }; |
+ |
+ // Ensure initial state is correct. |
+ Assert.assertFalse(listenerCallbackCalled.get()); |
+ |
+ // Ensure we get a callback, which means we have registered for them. |
+ ApplicationStatus.onStateChangeForTesting(new Activity(), ActivityState.CREATED); |
+ Assert.assertTrue(listenerCallbackCalled.get()); |
+ } |
+ |
+ /** |
+ * Test that the controller registers for session invalidations and stays registered when |
+ * disabling session invalidations is prohibited. |
+ */ |
+ @Test |
+ @Feature({"Sync"}) |
+ public void testCannotToggleSessionInvalidations() { |
+ InvalidationController controller = new InvalidationController(mContext, false); |
+ controller.ensureStartedAndUpdateRegisteredTypes(); |
+ Assert.assertEquals(mAllTypes, getRegisterIntentRegisterTypes(getOnlyIntent())); |
+ |
+ controller.onRecentTabsPageOpened(); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ assertNoNewIntents(); |
+ |
+ controller.onRecentTabsPageClosed(); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ assertNoNewIntents(); |
+ } |
+ |
+ /********************************************************************************************** |
+ * Tests for when session invalidations can be disabled. |
+ */ |
+ |
+ /** |
+ * Test that an intent is sent to register for session invalidations after the RecentTabsPage is |
+ * opened. |
+ */ |
+ @Test |
+ @Feature({"Sync"}) |
+ public void testRecentTabsPageShown() { |
+ InvalidationController controller = new InvalidationController(mContext, true); |
+ controller.ensureStartedAndUpdateRegisteredTypes(); |
+ Assert.assertEquals(mNonSessionTypes, getRegisterIntentRegisterTypes(getOnlyIntent())); |
+ |
+ controller.onRecentTabsPageOpened(); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ Assert.assertEquals(mAllTypes, getRegisterIntentRegisterTypes(getOnlyIntent())); |
+ |
+ controller.onRecentTabsPageClosed(); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ Assert.assertEquals(mNonSessionTypes, getRegisterIntentRegisterTypes(getOnlyIntent())); |
+ } |
+ |
+ /** |
+ * Test that if the InvalidationController is started while the RecentTabsPage is shown that |
+ * an intent is sent to register for session invalidations only once the InvalidationController |
+ * is started. |
+ */ |
+ @Test |
+ @Feature({"Sync"}) |
+ public void testStartWhileRecentTabsPageShown() { |
+ InvalidationController controller = new InvalidationController(mContext, true); |
+ controller.onRecentTabsPageOpened(); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ assertNoNewIntents(); |
+ |
+ controller.ensureStartedAndUpdateRegisteredTypes(); |
+ Assert.assertEquals(IntentType.START_AND_REGISTER, getIntentType(getOnlyIntent())); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ Assert.assertEquals(mAllTypes, getRegisterIntentRegisterTypes(getOnlyIntent())); |
+ |
+ controller.onRecentTabsPageClosed(); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ Assert.assertEquals(mNonSessionTypes, getRegisterIntentRegisterTypes(getOnlyIntent())); |
+ } |
+ |
+ /** |
+ * Test the handling for multiple open RecentTabsPages. |
+ */ |
+ @Test |
+ @Feature({"Sync"}) |
+ public void testMultipleRecentTabsPages() { |
+ InvalidationController controller = new InvalidationController(mContext, true); |
+ controller.ensureStartedAndUpdateRegisteredTypes(); |
+ Assert.assertEquals(mNonSessionTypes, getRegisterIntentRegisterTypes(getOnlyIntent())); |
+ |
+ controller.onRecentTabsPageOpened(); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ Assert.assertEquals(mAllTypes, getRegisterIntentRegisterTypes(getOnlyIntent())); |
+ |
+ controller.onRecentTabsPageOpened(); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ assertNoNewIntents(); |
+ |
+ controller.onRecentTabsPageClosed(); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ assertNoNewIntents(); |
+ |
+ controller.onRecentTabsPageClosed(); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ Assert.assertEquals(mNonSessionTypes, getRegisterIntentRegisterTypes(getOnlyIntent())); |
+ } |
+ |
+ /** |
+ * Test the handling for when the RecentTabsPage is opened/closed quickly. |
+ */ |
+ @Test |
+ @Feature({"Sync"}) |
+ public void testOpenCloseRecentTabsPageQuickly() { |
+ InvalidationController controller = new InvalidationController(mContext, true); |
+ controller.ensureStartedAndUpdateRegisteredTypes(); |
+ Assert.assertEquals(mNonSessionTypes, getRegisterIntentRegisterTypes(getOnlyIntent())); |
+ |
+ controller.onRecentTabsPageOpened(); |
+ controller.onRecentTabsPageClosed(); |
+ controller.onRecentTabsPageOpened(); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ Assert.assertEquals(mAllTypes, getRegisterIntentRegisterTypes(getOnlyIntent())); |
+ |
+ controller.onRecentTabsPageClosed(); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ Assert.assertEquals(mNonSessionTypes, getRegisterIntentRegisterTypes(getOnlyIntent())); |
+ |
+ controller.onRecentTabsPageOpened(); |
+ controller.onRecentTabsPageClosed(); |
+ controller.onRecentTabsPageOpened(); |
+ controller.onRecentTabsPageClosed(); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ assertNoNewIntents(); |
+ } |
+ |
+ /** |
+ * Test that if the InvalidationController is stopped prior to session sync invalidations being |
+ * disabled as a result of the RecentTabsPage being closed, that session sync invalidations are |
+ * disabled when the InvalidationController is restarted. |
+ */ |
+ @Test |
+ @Feature({"Sync"}) |
+ public void testDisableSessionInvalidationsOnStart() { |
+ InvalidationController controller = new InvalidationController(mContext, true); |
+ controller.ensureStartedAndUpdateRegisteredTypes(); |
+ Assert.assertEquals(mNonSessionTypes, getRegisterIntentRegisterTypes(getOnlyIntent())); |
+ controller.onRecentTabsPageOpened(); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ Assert.assertEquals(mAllTypes, getRegisterIntentRegisterTypes(getOnlyIntent())); |
+ |
+ controller.onRecentTabsPageClosed(); |
+ controller.stop(); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ Assert.assertEquals(IntentType.STOP, getIntentType(getOnlyIntent())); |
+ |
+ controller.ensureStartedAndUpdateRegisteredTypes(); |
+ Assert.assertEquals(mAllTypes, getRegisterIntentRegisterTypes(getOnlyIntent())); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ Assert.assertEquals(mNonSessionTypes, getRegisterIntentRegisterTypes(getOnlyIntent())); |
+ } |
+ |
+ /** |
+ * Test that if the activity is paused prior to session sync invalidations being disabled as a |
+ * result of the RecentTabsPage being closed, that session sync invalidations are disabled when |
+ * the activity is resumed. |
+ */ |
+ @Test |
+ @Feature({"Sync"}) |
+ public void testDisableSessionInvalidationsOnResume() { |
+ InvalidationController controller = new InvalidationController(mContext, true); |
+ controller.ensureStartedAndUpdateRegisteredTypes(); |
+ Assert.assertEquals(mNonSessionTypes, getRegisterIntentRegisterTypes(getOnlyIntent())); |
+ controller.onRecentTabsPageOpened(); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ Assert.assertEquals(mAllTypes, getRegisterIntentRegisterTypes(getOnlyIntent())); |
+ |
+ controller.onRecentTabsPageClosed(); |
+ controller.onApplicationStateChange(ApplicationState.HAS_PAUSED_ACTIVITIES); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ Assert.assertEquals(IntentType.STOP, getIntentType(getOnlyIntent())); |
+ |
+ controller.onApplicationStateChange(ApplicationState.HAS_RUNNING_ACTIVITIES); |
+ Assert.assertEquals(IntentType.START, getIntentType(getOnlyIntent())); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ Assert.assertEquals(mNonSessionTypes, getRegisterIntentRegisterTypes(getOnlyIntent())); |
+ } |
+ |
+ /** |
+ * Test that pausing all of Chrome's activities and resuming one of them keeps session |
+ * invalidations enabled if they were enabled prior to Chrome's activities getting paused. |
+ */ |
+ @Test |
+ @Feature({"Sync"}) |
+ public void testPauseAndResumeMainActivity() throws Exception { |
+ InvalidationController controller = new InvalidationController(mContext, true); |
+ controller.ensureStartedAndUpdateRegisteredTypes(); |
+ Assert.assertEquals(mNonSessionTypes, getRegisterIntentRegisterTypes(getOnlyIntent())); |
+ controller.onRecentTabsPageOpened(); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ Assert.assertEquals(mAllTypes, getRegisterIntentRegisterTypes(getOnlyIntent())); |
+ |
+ controller.onApplicationStateChange(ApplicationState.HAS_PAUSED_ACTIVITIES); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ Assert.assertEquals(IntentType.STOP, getIntentType(getOnlyIntent())); |
+ |
+ // Resuming the activity should not send a START_AND_REGISTER intent. |
+ controller.onApplicationStateChange(ApplicationState.HAS_RUNNING_ACTIVITIES); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ Assert.assertEquals(IntentType.START, getIntentType(getOnlyIntent())); |
+ } |
+ |
+ /** |
+ * Test that opening the RecentTabsPage has no effect after the InvalidationController is |
+ * stopped. |
+ */ |
+ @Test |
+ @Feature({"Sync"}) |
+ public void testPauseAndResumeMainActivityAfterStop() throws Exception { |
+ InvalidationController controller = new InvalidationController(mContext, true); |
+ controller.ensureStartedAndUpdateRegisteredTypes(); |
+ Assert.assertEquals(mNonSessionTypes, getRegisterIntentRegisterTypes(getOnlyIntent())); |
+ |
+ controller.stop(); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ Assert.assertEquals(IntentType.STOP, getIntentType(getOnlyIntent())); |
+ |
+ controller.onRecentTabsPageOpened(); |
+ Robolectric.runUiThreadTasksIncludingDelayedTasks(); |
+ assertNoNewIntents(); |
+ } |
+ |
+ /** |
+ * Asserts that {@code intent} is destined for the correct component. |
+ */ |
+ private static void validateIntentComponent(Intent intent) { |
+ Assert.assertNotNull(intent.getComponent()); |
+ Assert.assertEquals( |
+ InvalidationClientService.class.getName(), intent.getComponent().getClassName()); |
+ } |
+ |
+ /** |
+ * Assert that there are no new intents. |
+ */ |
+ private void assertNoNewIntents() { |
+ Assert.assertNull(mShadowActivity.getNextStartedService()); |
+ } |
+ |
+ /** |
+ * Assert that there is only one new intent. Returns the intent. |
+ */ |
+ private Intent getOnlyIntent() { |
+ Intent intent = mShadowActivity.getNextStartedService(); |
+ Assert.assertNotNull(intent); |
+ Assert.assertNull(mShadowActivity.getNextStartedService()); |
+ return intent; |
+ } |
+ |
+ /** |
+ * Returns the type of the intent. |
+ */ |
+ private static IntentType getIntentType(Intent intent) { |
+ if (intent.hasExtra(InvalidationIntentProtocol.EXTRA_STOP)) { |
+ return IntentType.STOP; |
+ } else if (intent.hasExtra(InvalidationIntentProtocol.EXTRA_REGISTERED_TYPES)) { |
+ return IntentType.START_AND_REGISTER; |
+ } else { |
+ return IntentType.START; |
+ } |
+ } |
+ |
+ /** |
+ * Returns the names of the ModelTypes to be registered by the passed in START_AND_REGISTER |
+ * intent. |
+ */ |
+ private static Set<String> getRegisterIntentRegisterTypes(Intent intent) { |
+ Set<String> registeredTypes = new HashSet<String>(); |
+ registeredTypes.addAll( |
+ intent.getStringArrayListExtra(InvalidationIntentProtocol.EXTRA_REGISTERED_TYPES)); |
+ return registeredTypes; |
+ } |
+} |