1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package org.chromium.chrome.browser.invalidation;
7 import android.accounts.Account;
8 import android.app.Activity;
9 import android.content.Intent;
10 import android.test.InstrumentationTestCase;
11 import android.test.suitebuilder.annotation.SmallTest;
13 import org.chromium.base.ActivityState;
14 import org.chromium.base.ApplicationState;
15 import org.chromium.base.ApplicationStatus;
16 import org.chromium.base.CollectionUtil;
17 import org.chromium.base.test.util.Feature;
18 import org.chromium.components.invalidation.InvalidationClientService;
19 import org.chromium.sync.internal_api.pub.base.ModelType;
20 import org.chromium.sync.notifier.InvalidationIntentProtocol;
21 import org.chromium.sync.notifier.InvalidationPreferences;
22 import org.chromium.sync.notifier.SyncStatusHelper;
23 import org.chromium.sync.signin.AccountManagerHelper;
24 import org.chromium.sync.signin.ChromeSigninController;
25 import org.chromium.sync.test.util.MockSyncContentResolverDelegate;
27 import java.util.ArrayList;
28 import java.util.HashSet;
29 import java.util.List;
31 import java.util.concurrent.atomic.AtomicBoolean;
32 import java.util.concurrent.atomic.AtomicReference;
35 * Tests for the {@link InvalidationController}.
37 public class InvalidationControllerTest extends InstrumentationTestCase {
38 private IntentSavingContext mContext;
39 private InvalidationController mController;
42 protected void setUp() throws Exception {
43 mContext = new IntentSavingContext(getInstrumentation().getTargetContext());
44 mController = InvalidationController.get(mContext);
45 // We don't want to use the system content resolver, so we override it.
46 MockSyncContentResolverDelegate delegate = new MockSyncContentResolverDelegate();
47 // Android master sync can safely always be on.
48 delegate.setMasterSyncAutomatically(true);
49 SyncStatusHelper.overrideSyncStatusHelperForTests(mContext, delegate);
54 public void testStart() throws Exception {
56 assertEquals(1, mContext.getNumStartedIntents());
57 Intent intent = mContext.getStartedIntent(0);
58 validateIntentComponent(intent);
63 public void testStop() throws Exception {
65 assertEquals(1, mContext.getNumStartedIntents());
66 Intent intent = mContext.getStartedIntent(0);
67 validateIntentComponent(intent);
68 assertEquals(1, intent.getExtras().size());
69 assertTrue(intent.hasExtra(InvalidationIntentProtocol.EXTRA_STOP));
70 assertTrue(intent.getBooleanExtra(InvalidationIntentProtocol.EXTRA_STOP, false));
75 public void testResumingMainActivity() throws Exception {
76 // Resuming main activity should trigger a start if sync is enabled.
78 mController.onApplicationStateChange(ApplicationState.HAS_RUNNING_ACTIVITIES);
79 assertEquals(1, mContext.getNumStartedIntents());
80 Intent intent = mContext.getStartedIntent(0);
81 validateIntentComponent(intent);
86 public void testResumingMainActivityWithSyncDisabled() throws Exception {
87 // Resuming main activity should NOT trigger a start if sync is disabled.
89 mController.onApplicationStateChange(ApplicationState.HAS_RUNNING_ACTIVITIES);
90 assertEquals(0, mContext.getNumStartedIntents());
95 public void testPausingMainActivity() throws Exception {
96 // Resuming main activity should trigger a stop if sync is enabled.
98 mController.onApplicationStateChange(ApplicationState.HAS_PAUSED_ACTIVITIES);
99 assertEquals(1, mContext.getNumStartedIntents());
100 Intent intent = mContext.getStartedIntent(0);
101 validateIntentComponent(intent);
102 assertEquals(1, intent.getExtras().size());
103 assertTrue(intent.hasExtra(InvalidationIntentProtocol.EXTRA_STOP));
104 assertTrue(intent.getBooleanExtra(InvalidationIntentProtocol.EXTRA_STOP, false));
109 public void testPausingMainActivityWithSyncDisabled() throws Exception {
110 // Resuming main activity should NOT trigger a stop if sync is disabled.
112 mController.onApplicationStateChange(ApplicationState.HAS_PAUSED_ACTIVITIES);
113 assertEquals(0, mContext.getNumStartedIntents());
116 private void setupSync(boolean syncEnabled) {
117 Account account = AccountManagerHelper.createAccountFromName("test@gmail.com");
118 ChromeSigninController chromeSigninController = ChromeSigninController.get(mContext);
119 chromeSigninController.setSignedInAccountName(account.name);
120 SyncStatusHelper syncStatusHelper = SyncStatusHelper.get(mContext);
122 syncStatusHelper.enableAndroidSync(account);
124 syncStatusHelper.disableAndroidSync(account);
130 public void testEnsureConstructorRegistersListener() throws Exception {
131 final AtomicBoolean listenerCallbackCalled = new AtomicBoolean();
134 new InvalidationController(mContext) {
136 public void onApplicationStateChange(int newState) {
137 listenerCallbackCalled.set(true);
141 // Ensure initial state is correct.
142 assertFalse(listenerCallbackCalled.get());
144 // Ensure we get a callback, which means we have registered for them.
145 ApplicationStatus.onStateChangeForTesting(new Activity(), ActivityState.CREATED);
146 assertTrue(listenerCallbackCalled.get());
151 public void testRegisterForSpecificTypes() {
152 InvalidationController controller = new InvalidationController(mContext);
153 Account account = new Account("test@example.com", "bogus");
154 controller.setRegisteredTypes(account, false,
155 CollectionUtil.newHashSet(ModelType.BOOKMARK, ModelType.SESSION));
156 assertEquals(1, mContext.getNumStartedIntents());
158 // Validate destination.
159 Intent intent = mContext.getStartedIntent(0);
160 validateIntentComponent(intent);
161 assertEquals(InvalidationIntentProtocol.ACTION_REGISTER, intent.getAction());
164 Account intentAccount =
165 intent.getParcelableExtra(InvalidationIntentProtocol.EXTRA_ACCOUNT);
166 assertEquals(account, intentAccount);
168 // Validate registered types.
169 Set<String> expectedTypes = CollectionUtil.newHashSet(ModelType.BOOKMARK.name(),
170 ModelType.SESSION.name());
171 Set<String> actualTypes = new HashSet<String>();
172 actualTypes.addAll(intent.getStringArrayListExtra(
173 InvalidationIntentProtocol.EXTRA_REGISTERED_TYPES));
174 assertEquals(expectedTypes, actualTypes);
175 assertNull(InvalidationIntentProtocol.getRegisteredObjectIds(intent));
180 public void testRegisterForAllTypes() {
181 Account account = new Account("test@example.com", "bogus");
182 mController.setRegisteredTypes(account, true,
183 CollectionUtil.newHashSet(ModelType.BOOKMARK, ModelType.SESSION));
184 assertEquals(1, mContext.getNumStartedIntents());
186 // Validate destination.
187 Intent intent = mContext.getStartedIntent(0);
188 validateIntentComponent(intent);
189 assertEquals(InvalidationIntentProtocol.ACTION_REGISTER, intent.getAction());
192 Account intentAccount =
193 intent.getParcelableExtra(InvalidationIntentProtocol.EXTRA_ACCOUNT);
194 assertEquals(account, intentAccount);
196 // Validate registered types.
197 Set<String> expectedTypes = CollectionUtil.newHashSet(ModelType.ALL_TYPES_TYPE);
198 Set<String> actualTypes = new HashSet<String>();
199 actualTypes.addAll(intent.getStringArrayListExtra(
200 InvalidationIntentProtocol.EXTRA_REGISTERED_TYPES));
201 assertEquals(expectedTypes, actualTypes);
202 assertNull(InvalidationIntentProtocol.getRegisteredObjectIds(intent));
207 public void testRefreshShouldReadValuesFromDiskWithSpecificTypes() {
208 // Store some preferences for ModelTypes and account. We are using the helper class
209 // for this, so we don't have to deal with low-level details such as preference keys.
210 InvalidationPreferences invalidationPreferences = new InvalidationPreferences(mContext);
211 InvalidationPreferences.EditContext edit = invalidationPreferences.edit();
212 Set<String> storedModelTypes = new HashSet<String>();
213 storedModelTypes.add(ModelType.BOOKMARK.name());
214 storedModelTypes.add(ModelType.TYPED_URL.name());
215 Set<ModelType> refreshedTypes = new HashSet<ModelType>();
216 refreshedTypes.add(ModelType.BOOKMARK);
217 refreshedTypes.add(ModelType.TYPED_URL);
218 invalidationPreferences.setSyncTypes(edit, storedModelTypes);
219 Account storedAccount = AccountManagerHelper.createAccountFromName("test@gmail.com");
220 invalidationPreferences.setAccount(edit, storedAccount);
221 invalidationPreferences.commit(edit);
223 // Ensure all calls to {@link InvalidationController#setRegisteredTypes} store values
224 // we can inspect in the test.
225 final AtomicReference<Account> resultAccount = new AtomicReference<Account>();
226 final AtomicBoolean resultAllTypes = new AtomicBoolean();
227 final AtomicReference<Set<ModelType>> resultTypes = new AtomicReference<Set<ModelType>>();
228 InvalidationController controller = new InvalidationController(mContext) {
230 public void setRegisteredTypes(
231 Account account, boolean allTypes, Set<ModelType> types) {
232 resultAccount.set(account);
233 resultAllTypes.set(allTypes);
234 resultTypes.set(types);
239 controller.refreshRegisteredTypes(refreshedTypes);
241 // Validate the values.
242 assertEquals(storedAccount, resultAccount.get());
243 assertEquals(false, resultAllTypes.get());
244 assertEquals(ModelType.syncTypesToModelTypes(storedModelTypes), resultTypes.get());
249 public void testRefreshShouldReadValuesFromDiskWithAllTypes() {
250 // Store preferences for the ModelType.ALL_TYPES_TYPE and account. We
251 // are using the helper class for this, so we don't have to deal with
252 // low-level details such as preference keys.
253 InvalidationPreferences invalidationPreferences = new InvalidationPreferences(mContext);
254 InvalidationPreferences.EditContext edit = invalidationPreferences.edit();
255 List<String> storedModelTypes = new ArrayList<String>();
256 storedModelTypes.add(ModelType.ALL_TYPES_TYPE);
257 invalidationPreferences.setSyncTypes(edit, storedModelTypes);
258 Account storedAccount = AccountManagerHelper.createAccountFromName("test@gmail.com");
259 invalidationPreferences.setAccount(edit, storedAccount);
260 invalidationPreferences.commit(edit);
262 // Ensure all calls to {@link InvalidationController#setRegisteredTypes} store values
263 // we can inspect in the test.
264 final AtomicReference<Account> resultAccount = new AtomicReference<Account>();
265 final AtomicBoolean resultAllTypes = new AtomicBoolean();
266 final AtomicReference<Set<ModelType>> resultTypes = new AtomicReference<Set<ModelType>>();
267 InvalidationController controller = new InvalidationController(mContext) {
269 public void setRegisteredTypes(
270 Account account, boolean allTypes, Set<ModelType> types) {
271 resultAccount.set(account);
272 resultAllTypes.set(allTypes);
273 resultTypes.set(types);
278 controller.refreshRegisteredTypes(new HashSet<ModelType>());
280 // Validate the values.
281 assertEquals(storedAccount, resultAccount.get());
282 assertEquals(true, resultAllTypes.get());
286 * Asserts that {@code intent} is destined for the correct component.
288 private static void validateIntentComponent(Intent intent) {
289 assertNotNull(intent.getComponent());
290 assertEquals(InvalidationClientService.class.getName(),
291 intent.getComponent().getClassName());