| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 package org.chromium.sync.notifier; | |
| 6 | |
| 7 import android.accounts.Account; | |
| 8 import android.content.ComponentName; | |
| 9 import android.content.Intent; | |
| 10 import android.os.Bundle; | |
| 11 import android.test.ServiceTestCase; | |
| 12 import android.test.suitebuilder.annotation.SmallTest; | |
| 13 | |
| 14 import com.google.ipc.invalidation.external.client.InvalidationListener.Registra
tionState; | |
| 15 import com.google.ipc.invalidation.external.client.contrib.AndroidListener; | |
| 16 import com.google.ipc.invalidation.external.client.types.ErrorInfo; | |
| 17 import com.google.ipc.invalidation.external.client.types.Invalidation; | |
| 18 import com.google.ipc.invalidation.external.client.types.ObjectId; | |
| 19 | |
| 20 import org.chromium.base.CollectionUtil; | |
| 21 import org.chromium.base.test.util.AdvancedMockContext; | |
| 22 import org.chromium.base.test.util.Feature; | |
| 23 import org.chromium.sync.internal_api.pub.base.ModelType; | |
| 24 import org.chromium.sync.notifier.InvalidationPreferences.EditContext; | |
| 25 import org.chromium.sync.signin.AccountManagerHelper; | |
| 26 | |
| 27 import java.util.ArrayList; | |
| 28 import java.util.Arrays; | |
| 29 import java.util.EnumSet; | |
| 30 import java.util.HashSet; | |
| 31 import java.util.List; | |
| 32 import java.util.Set; | |
| 33 | |
| 34 /** | |
| 35 * Tests for the {@link InvalidationService}. | |
| 36 * | |
| 37 * @author dsmyers@google.com (Daniel Myers) | |
| 38 */ | |
| 39 public class InvalidationServiceTest extends ServiceTestCase<TestableInvalidatio
nService> { | |
| 40 /** Id used when creating clients. */ | |
| 41 private static final byte[] CLIENT_ID = new byte[]{0, 4, 7}; | |
| 42 | |
| 43 /** Intents provided to {@link #startService}. */ | |
| 44 private List<Intent> mStartServiceIntents; | |
| 45 | |
| 46 public InvalidationServiceTest() { | |
| 47 super(TestableInvalidationService.class); | |
| 48 } | |
| 49 | |
| 50 @Override | |
| 51 public void setUp() throws Exception { | |
| 52 super.setUp(); | |
| 53 mStartServiceIntents = new ArrayList<Intent>(); | |
| 54 setContext(new AdvancedMockContext(getContext()) { | |
| 55 @Override | |
| 56 public ComponentName startService(Intent intent) { | |
| 57 mStartServiceIntents.add(intent); | |
| 58 return new ComponentName(this, InvalidationServiceTest.class); | |
| 59 } | |
| 60 }); | |
| 61 setupService(); | |
| 62 } | |
| 63 | |
| 64 @Override | |
| 65 public void tearDown() throws Exception { | |
| 66 if (InvalidationService.getIsClientStartedForTest()) { | |
| 67 Intent stopIntent = createStopIntent(); | |
| 68 getService().onHandleIntent(stopIntent); | |
| 69 } | |
| 70 assertFalse(InvalidationService.getIsClientStartedForTest()); | |
| 71 super.tearDown(); | |
| 72 } | |
| 73 | |
| 74 @SmallTest | |
| 75 @Feature({"Sync"}) | |
| 76 public void testComputeRegistrationOps() { | |
| 77 /* | |
| 78 * Test plan: compute the set of registration operations resulting from
various combinations | |
| 79 * of existing and desired registrations. Verifying that they are correc
t. | |
| 80 */ | |
| 81 Set<ObjectId> regAccumulator = new HashSet<ObjectId>(); | |
| 82 Set<ObjectId> unregAccumulator = new HashSet<ObjectId>(); | |
| 83 | |
| 84 // Empty existing and desired registrations should yield empty operation
sets. | |
| 85 InvalidationService.computeRegistrationOps( | |
| 86 ModelType.modelTypesToObjectIds( | |
| 87 CollectionUtil.newHashSet(ModelType.BOOKMARK, ModelType.
SESSION)), | |
| 88 ModelType.modelTypesToObjectIds( | |
| 89 CollectionUtil.newHashSet(ModelType.BOOKMARK, ModelType.
SESSION)), | |
| 90 regAccumulator, unregAccumulator); | |
| 91 assertEquals(0, regAccumulator.size()); | |
| 92 assertEquals(0, unregAccumulator.size()); | |
| 93 | |
| 94 // Equal existing and desired registrations should yield empty operation
sets. | |
| 95 InvalidationService.computeRegistrationOps(new HashSet<ObjectId>(), | |
| 96 new HashSet<ObjectId>(), regAccumulator, unregAccumulator); | |
| 97 assertEquals(0, regAccumulator.size()); | |
| 98 assertEquals(0, unregAccumulator.size()); | |
| 99 | |
| 100 // Empty existing and non-empty desired registrations should yield desir
ed registrations | |
| 101 // as the registration operations to do and no unregistrations. | |
| 102 Set<ObjectId> desiredTypes = | |
| 103 CollectionUtil.newHashSet( | |
| 104 ModelType.BOOKMARK.toObjectId(), ModelType.SESSION.toObj
ectId()); | |
| 105 InvalidationService.computeRegistrationOps( | |
| 106 new HashSet<ObjectId>(), | |
| 107 desiredTypes, | |
| 108 regAccumulator, unregAccumulator); | |
| 109 assertEquals( | |
| 110 CollectionUtil.newHashSet( | |
| 111 ModelType.BOOKMARK.toObjectId(), ModelType.SESSION.toObj
ectId()), | |
| 112 new HashSet<ObjectId>(regAccumulator)); | |
| 113 assertEquals(0, unregAccumulator.size()); | |
| 114 regAccumulator.clear(); | |
| 115 | |
| 116 // Unequal existing and desired registrations should yield both registra
tions and | |
| 117 // unregistrations. We should unregister TYPED_URL and register BOOKMARK
, keeping SESSION. | |
| 118 InvalidationService.computeRegistrationOps( | |
| 119 CollectionUtil.newHashSet( | |
| 120 ModelType.SESSION.toObjectId(), ModelType.TYPED_URL.toOb
jectId()), | |
| 121 CollectionUtil.newHashSet( | |
| 122 ModelType.BOOKMARK.toObjectId(), ModelType.SESSION.toObj
ectId()), | |
| 123 regAccumulator, unregAccumulator); | |
| 124 assertEquals(CollectionUtil.newHashSet(ModelType.BOOKMARK.toObjectId()),
regAccumulator); | |
| 125 assertEquals(CollectionUtil.newHashSet(ModelType.TYPED_URL.toObjectId())
, | |
| 126 unregAccumulator); | |
| 127 regAccumulator.clear(); | |
| 128 unregAccumulator.clear(); | |
| 129 } | |
| 130 | |
| 131 @SmallTest | |
| 132 @Feature({"Sync"}) | |
| 133 public void testReady() { | |
| 134 /** | |
| 135 * Test plan: call ready. Verify that the service sets the client id corr
ectly and reissues | |
| 136 * pending registrations. | |
| 137 */ | |
| 138 | |
| 139 // Persist some registrations. | |
| 140 InvalidationPreferences invPrefs = new InvalidationPreferences(getContex
t()); | |
| 141 EditContext editContext = invPrefs.edit(); | |
| 142 invPrefs.setSyncTypes(editContext, CollectionUtil.newArrayList("BOOKMARK
", "SESSION")); | |
| 143 ObjectId objectId = ObjectId.newInstance(1, "obj".getBytes()); | |
| 144 invPrefs.setObjectIds(editContext, CollectionUtil.newArrayList(objectId)
); | |
| 145 assertTrue(invPrefs.commit(editContext)); | |
| 146 | |
| 147 // Issue ready. | |
| 148 getService().ready(CLIENT_ID); | |
| 149 assertTrue(Arrays.equals(CLIENT_ID, InvalidationService.getClientIdForTe
st())); | |
| 150 byte[] otherCid = "otherCid".getBytes(); | |
| 151 getService().ready(otherCid); | |
| 152 assertTrue(Arrays.equals(otherCid, InvalidationService.getClientIdForTes
t())); | |
| 153 | |
| 154 // Verify registrations issued. | |
| 155 assertEquals(CollectionUtil.newHashSet( | |
| 156 ModelType.BOOKMARK.toObjectId(), ModelType.SESSION.toObjectId(),
objectId), | |
| 157 new HashSet<ObjectId>(getService().mRegistrations.get(0))); | |
| 158 } | |
| 159 | |
| 160 @SmallTest | |
| 161 @Feature({"Sync"}) | |
| 162 public void testReissueRegistrations() { | |
| 163 /* | |
| 164 * Test plan: call the reissueRegistrations method of the listener with
both empty and | |
| 165 * non-empty sets of desired registrations stored in preferences. Verify
that no register | |
| 166 * intent is set in the first case and that the appropriate register int
ent is sent in | |
| 167 * the second. | |
| 168 */ | |
| 169 | |
| 170 // No persisted registrations. | |
| 171 getService().reissueRegistrations(CLIENT_ID); | |
| 172 assertTrue(getService().mRegistrations.isEmpty()); | |
| 173 | |
| 174 // Persist some registrations. | |
| 175 InvalidationPreferences invPrefs = new InvalidationPreferences(getContex
t()); | |
| 176 EditContext editContext = invPrefs.edit(); | |
| 177 invPrefs.setSyncTypes(editContext, CollectionUtil.newArrayList("BOOKMARK
", "SESSION")); | |
| 178 ObjectId objectId = ObjectId.newInstance(1, "obj".getBytes()); | |
| 179 invPrefs.setObjectIds(editContext, CollectionUtil.newArrayList(objectId)
); | |
| 180 assertTrue(invPrefs.commit(editContext)); | |
| 181 | |
| 182 // Reissue registrations and verify that the appropriate registrations a
re issued. | |
| 183 getService().reissueRegistrations(CLIENT_ID); | |
| 184 assertEquals(1, getService().mRegistrations.size()); | |
| 185 assertEquals(CollectionUtil.newHashSet( | |
| 186 ModelType.BOOKMARK.toObjectId(), ModelType.SESSION.toObjectId(),
objectId), | |
| 187 new HashSet<ObjectId>(getService().mRegistrations.get(0))); | |
| 188 } | |
| 189 | |
| 190 @SmallTest | |
| 191 @Feature({"Sync"}) | |
| 192 public void testInformRegistrationStatus() { | |
| 193 /* | |
| 194 * Test plan: call inform registration status under a variety of circums
tances and verify | |
| 195 * that the appropriate (un)register calls are issued. | |
| 196 * | |
| 197 * 1. Registration of desired object. No calls issued. | |
| 198 * 2. Unregistration of undesired object. No calls issued. | |
| 199 * 3. Registration of undesired object. Unregistration issued. | |
| 200 * 4. Unregistration of desired object. Registration issued. | |
| 201 */ | |
| 202 // Initial test setup: persist a single registration into preferences. | |
| 203 InvalidationPreferences invPrefs = new InvalidationPreferences(getContex
t()); | |
| 204 EditContext editContext = invPrefs.edit(); | |
| 205 invPrefs.setSyncTypes(editContext, CollectionUtil.newArrayList("SESSION"
)); | |
| 206 ObjectId desiredObjectId = ObjectId.newInstance(1, "obj1".getBytes()); | |
| 207 ObjectId undesiredObjectId = ObjectId.newInstance(1, "obj2".getBytes()); | |
| 208 invPrefs.setObjectIds(editContext, CollectionUtil.newArrayList(desiredOb
jectId)); | |
| 209 assertTrue(invPrefs.commit(editContext)); | |
| 210 | |
| 211 // Cases 1 and 2: calls matching desired state cause no actions. | |
| 212 getService().informRegistrationStatus(CLIENT_ID, ModelType.SESSION.toObj
ectId(), | |
| 213 RegistrationState.REGISTERED); | |
| 214 getService().informRegistrationStatus(CLIENT_ID, desiredObjectId, | |
| 215 RegistrationState.REGISTERED); | |
| 216 getService().informRegistrationStatus(CLIENT_ID, ModelType.BOOKMARK.toOb
jectId(), | |
| 217 RegistrationState.UNREGISTERED); | |
| 218 getService().informRegistrationStatus(CLIENT_ID, undesiredObjectId, | |
| 219 RegistrationState.UNREGISTERED); | |
| 220 assertTrue(getService().mRegistrations.isEmpty()); | |
| 221 assertTrue(getService().mUnregistrations.isEmpty()); | |
| 222 | |
| 223 // Case 3: registration of undesired object triggers an unregistration. | |
| 224 getService().informRegistrationStatus(CLIENT_ID, ModelType.BOOKMARK.toOb
jectId(), | |
| 225 RegistrationState.REGISTERED); | |
| 226 getService().informRegistrationStatus(CLIENT_ID, undesiredObjectId, | |
| 227 RegistrationState.REGISTERED); | |
| 228 assertEquals(2, getService().mUnregistrations.size()); | |
| 229 assertEquals(0, getService().mRegistrations.size()); | |
| 230 assertEquals(CollectionUtil.newArrayList(ModelType.BOOKMARK.toObjectId()
), | |
| 231 getService().mUnregistrations.get(0)); | |
| 232 assertEquals(CollectionUtil.newArrayList(undesiredObjectId), | |
| 233 getService().mUnregistrations.get(1)); | |
| 234 | |
| 235 // Case 4: unregistration of a desired object triggers a registration. | |
| 236 getService().informRegistrationStatus(CLIENT_ID, ModelType.SESSION.toObj
ectId(), | |
| 237 RegistrationState.UNREGISTERED); | |
| 238 getService().informRegistrationStatus(CLIENT_ID, desiredObjectId, | |
| 239 RegistrationState.UNREGISTERED); | |
| 240 assertEquals(2, getService().mUnregistrations.size()); | |
| 241 assertEquals(2, getService().mRegistrations.size()); | |
| 242 assertEquals(CollectionUtil.newArrayList(ModelType.SESSION.toObjectId())
, | |
| 243 getService().mRegistrations.get(0)); | |
| 244 assertEquals(CollectionUtil.newArrayList(desiredObjectId), | |
| 245 getService().mRegistrations.get(1)); | |
| 246 } | |
| 247 | |
| 248 @SmallTest | |
| 249 @Feature({"Sync"}) | |
| 250 public void testInformRegistrationFailure() { | |
| 251 /* | |
| 252 * Test plan: call inform registration failure under a variety of circum
stances and verify | |
| 253 * that the appropriate (un)register calls are issued. | |
| 254 * | |
| 255 * 1. Transient registration failure for an object that should be regist
ered. Register | |
| 256 * should be called. | |
| 257 * 2. Permanent registration failure for an object that should be regist
ered. No calls. | |
| 258 * 3. Transient registration failure for an object that should not be re
gistered. Unregister | |
| 259 * should be called. | |
| 260 * 4. Permanent registration failure for an object should not be registe
red. No calls. | |
| 261 */ | |
| 262 | |
| 263 // Initial test setup: persist a single registration into preferences. | |
| 264 InvalidationPreferences invPrefs = new InvalidationPreferences(getContex
t()); | |
| 265 EditContext editContext = invPrefs.edit(); | |
| 266 invPrefs.setSyncTypes(editContext, CollectionUtil.newArrayList("SESSION"
)); | |
| 267 ObjectId desiredObjectId = ObjectId.newInstance(1, "obj1".getBytes()); | |
| 268 ObjectId undesiredObjectId = ObjectId.newInstance(1, "obj2".getBytes()); | |
| 269 invPrefs.setObjectIds(editContext, CollectionUtil.newArrayList(desiredOb
jectId)); | |
| 270 assertTrue(invPrefs.commit(editContext)); | |
| 271 | |
| 272 // Cases 2 and 4: permanent registration failures never cause calls to b
e made. | |
| 273 getService().informRegistrationFailure(CLIENT_ID, ModelType.SESSION.toOb
jectId(), false, | |
| 274 ""); | |
| 275 getService().informRegistrationFailure(CLIENT_ID, ModelType.BOOKMARK.toO
bjectId(), false, | |
| 276 ""); | |
| 277 getService().informRegistrationFailure(CLIENT_ID, desiredObjectId, false
, ""); | |
| 278 getService().informRegistrationFailure(CLIENT_ID, undesiredObjectId, fal
se, ""); | |
| 279 assertTrue(getService().mRegistrations.isEmpty()); | |
| 280 assertTrue(getService().mUnregistrations.isEmpty()); | |
| 281 | |
| 282 // Case 1: transient failure of a desired registration results in re-reg
istration. | |
| 283 getService().informRegistrationFailure(CLIENT_ID, ModelType.SESSION.toOb
jectId(), true, ""); | |
| 284 getService().informRegistrationFailure(CLIENT_ID, desiredObjectId, true,
""); | |
| 285 assertEquals(2, getService().mRegistrations.size()); | |
| 286 assertTrue(getService().mUnregistrations.isEmpty()); | |
| 287 assertEquals(CollectionUtil.newArrayList(ModelType.SESSION.toObjectId())
, | |
| 288 getService().mRegistrations.get(0)); | |
| 289 assertEquals(CollectionUtil.newArrayList(desiredObjectId), | |
| 290 getService().mRegistrations.get(1)); | |
| 291 | |
| 292 // Case 3: transient failure of an undesired registration results in unr
egistration. | |
| 293 getService().informRegistrationFailure(CLIENT_ID, ModelType.BOOKMARK.toO
bjectId(), true, | |
| 294 ""); | |
| 295 getService().informRegistrationFailure(CLIENT_ID, undesiredObjectId, tru
e, ""); | |
| 296 assertEquals(2, getService().mRegistrations.size()); | |
| 297 assertEquals(2, getService().mUnregistrations.size()); | |
| 298 assertEquals(CollectionUtil.newArrayList(ModelType.BOOKMARK.toObjectId()
), | |
| 299 getService().mUnregistrations.get(0)); | |
| 300 assertEquals(CollectionUtil.newArrayList(undesiredObjectId), | |
| 301 getService().mUnregistrations.get(1)); | |
| 302 } | |
| 303 | |
| 304 @SmallTest | |
| 305 @Feature({"Sync"}) | |
| 306 public void testInformError() { | |
| 307 /* | |
| 308 * Test plan: call informError with both permanent and transient errors.
Verify that | |
| 309 * the transient error causes no action to be taken and that the permane
nt error causes | |
| 310 * the client to be stopped. | |
| 311 */ | |
| 312 | |
| 313 // Client needs to be started for the permament error to trigger and sto
p. | |
| 314 getService().setShouldRunStates(true, true); | |
| 315 getService().onCreate(); | |
| 316 getService().onHandleIntent(createStartIntent()); | |
| 317 getService().mStartedServices.clear(); // Discard start intent. | |
| 318 | |
| 319 // Transient error. | |
| 320 getService().informError(ErrorInfo.newInstance(0, true, "transient", nul
l)); | |
| 321 assertTrue(getService().mStartedServices.isEmpty()); | |
| 322 | |
| 323 // Permanent error. | |
| 324 getService().informError(ErrorInfo.newInstance(0, false, "permanent", nu
ll)); | |
| 325 assertEquals(1, getService().mStartedServices.size()); | |
| 326 Intent sentIntent = getService().mStartedServices.get(0); | |
| 327 Intent stopIntent = AndroidListener.createStopIntent(getContext()); | |
| 328 assertTrue(stopIntent.filterEquals(sentIntent)); | |
| 329 assertEquals(stopIntent.getExtras().keySet(), sentIntent.getExtras().key
Set()); | |
| 330 } | |
| 331 | |
| 332 @SmallTest | |
| 333 @Feature({"Sync"}) | |
| 334 public void testReadWriteState() { | |
| 335 /* | |
| 336 * Test plan: read, write, and read the internal notification client per
sistent state. | |
| 337 * Verify appropriate return values. | |
| 338 */ | |
| 339 assertNull(getService().readState()); | |
| 340 byte[] writtenState = new byte[]{7, 4, 0}; | |
| 341 getService().writeState(writtenState); | |
| 342 assertTrue(Arrays.equals(writtenState, getService().readState())); | |
| 343 } | |
| 344 | |
| 345 @SmallTest | |
| 346 @Feature({"Sync"}) | |
| 347 public void testInvalidateWithPayload() { | |
| 348 doTestInvalidate(true); | |
| 349 } | |
| 350 | |
| 351 @SmallTest | |
| 352 @Feature({"Sync"}) | |
| 353 public void testInvalidateWithoutPayload() { | |
| 354 doTestInvalidate(false); | |
| 355 } | |
| 356 | |
| 357 private void doTestInvalidate(boolean hasPayload) { | |
| 358 /* | |
| 359 * Test plan: call invalidate() with an invalidation that may or may not
have a payload. | |
| 360 * Verify the produced bundle has the correct fields. | |
| 361 */ | |
| 362 // Call invalidate. | |
| 363 int version = 4747; | |
| 364 ObjectId objectId = ObjectId.newInstance(55, "BOOKMARK".getBytes()); | |
| 365 final String payload = "testInvalidate-" + hasPayload; | |
| 366 Invalidation invalidation = hasPayload ? | |
| 367 Invalidation.newInstance(objectId, version, payload.getBytes())
: | |
| 368 Invalidation.newInstance(objectId, version); | |
| 369 byte[] ackHandle = ("testInvalidate-" + hasPayload).getBytes(); | |
| 370 getService().invalidate(invalidation, ackHandle); | |
| 371 | |
| 372 // Validate bundle. | |
| 373 assertEquals(1, getService().mRequestedSyncs.size()); | |
| 374 Bundle syncBundle = getService().mRequestedSyncs.get(0); | |
| 375 assertEquals(55, syncBundle.getInt("objectSource")); | |
| 376 assertEquals("BOOKMARK", syncBundle.getString("objectId")); | |
| 377 assertEquals(version, syncBundle.getLong("version")); | |
| 378 assertEquals(hasPayload ? payload : "", syncBundle.getString("payload"))
; | |
| 379 | |
| 380 // Ensure acknowledged. | |
| 381 assertSingleAcknowledgement(ackHandle); | |
| 382 } | |
| 383 | |
| 384 @SmallTest | |
| 385 @Feature({"Sync"}) | |
| 386 public void testInvalidateUnknownVersion() { | |
| 387 /* | |
| 388 * Test plan: call invalidateUnknownVersion(). Verify the produced bundl
e has the correct | |
| 389 * fields. | |
| 390 */ | |
| 391 ObjectId objectId = ObjectId.newInstance(55, "BOOKMARK".getBytes()); | |
| 392 byte[] ackHandle = "testInvalidateUV".getBytes(); | |
| 393 getService().invalidateUnknownVersion(objectId, ackHandle); | |
| 394 | |
| 395 // Validate bundle. | |
| 396 assertEquals(1, getService().mRequestedSyncs.size()); | |
| 397 Bundle syncBundle = getService().mRequestedSyncs.get(0); | |
| 398 assertEquals(55, syncBundle.getInt("objectSource")); | |
| 399 assertEquals("BOOKMARK", syncBundle.getString("objectId")); | |
| 400 assertEquals(0, syncBundle.getLong("version")); | |
| 401 assertEquals("", syncBundle.getString("payload")); | |
| 402 | |
| 403 // Ensure acknowledged. | |
| 404 assertSingleAcknowledgement(ackHandle); | |
| 405 } | |
| 406 | |
| 407 @SmallTest | |
| 408 @Feature({"Sync"}) | |
| 409 public void testInvalidateAll() { | |
| 410 /* | |
| 411 * Test plan: call invalidateAll(). Verify the produced bundle has the c
orrect fields. | |
| 412 */ | |
| 413 byte[] ackHandle = "testInvalidateAll".getBytes(); | |
| 414 getService().invalidateAll(ackHandle); | |
| 415 | |
| 416 // Validate bundle. | |
| 417 assertEquals(1, getService().mRequestedSyncs.size()); | |
| 418 Bundle syncBundle = getService().mRequestedSyncs.get(0); | |
| 419 assertEquals(0, syncBundle.keySet().size()); | |
| 420 | |
| 421 // Ensure acknowledged. | |
| 422 assertSingleAcknowledgement(ackHandle); | |
| 423 } | |
| 424 | |
| 425 /** Asserts that the service received a single acknowledgement with handle {
@code ackHandle}. */ | |
| 426 private void assertSingleAcknowledgement(byte[] ackHandle) { | |
| 427 assertEquals(1, getService().mAcknowledgements.size()); | |
| 428 assertTrue(Arrays.equals(ackHandle, getService().mAcknowledgements.get(0
))); | |
| 429 } | |
| 430 | |
| 431 @SmallTest | |
| 432 @Feature({"Sync"}) | |
| 433 public void testShouldClientBeRunning() { | |
| 434 /* | |
| 435 * Test plan: call shouldClientBeRunning with various combinations of | |
| 436 * in-foreground/sync-enabled. Verify appropriate return values. | |
| 437 */ | |
| 438 getService().setShouldRunStates(false, false); | |
| 439 assertFalse(getService().shouldClientBeRunning()); | |
| 440 | |
| 441 getService().setShouldRunStates(false, true); | |
| 442 assertFalse(getService().shouldClientBeRunning()); | |
| 443 | |
| 444 getService().setShouldRunStates(true, false); | |
| 445 assertFalse(getService().shouldClientBeRunning()); | |
| 446 | |
| 447 // Should only be running if both in the foreground and sync is enabled. | |
| 448 getService().setShouldRunStates(true, true); | |
| 449 assertTrue(getService().shouldClientBeRunning()); | |
| 450 } | |
| 451 | |
| 452 @SmallTest | |
| 453 @Feature({"Sync"}) | |
| 454 public void testStartAndStopClient() { | |
| 455 /* | |
| 456 * Test plan: with Chrome configured so that the client should run, send
it an empty | |
| 457 * intent. Even though no owning account is known, the client should sti
ll start. Send | |
| 458 * it a stop intent and verify that it stops. | |
| 459 */ | |
| 460 | |
| 461 // Note: we are manipulating the service object directly, rather than th
rough startService, | |
| 462 // because otherwise we would need to handle the asynchronous execution
model of the | |
| 463 // underlying IntentService. | |
| 464 getService().setShouldRunStates(true, true); | |
| 465 getService().onCreate(); | |
| 466 | |
| 467 Intent startIntent = createStartIntent(); | |
| 468 getService().onHandleIntent(startIntent); | |
| 469 assertTrue(InvalidationService.getIsClientStartedForTest()); | |
| 470 | |
| 471 Intent stopIntent = createStopIntent(); | |
| 472 getService().onHandleIntent(stopIntent); | |
| 473 assertFalse(InvalidationService.getIsClientStartedForTest()); | |
| 474 | |
| 475 // The issued intents should have been an AndroidListener start intent f
ollowed by an | |
| 476 // AndroidListener stop intent. | |
| 477 assertEquals(2, mStartServiceIntents.size()); | |
| 478 assertTrue(isAndroidListenerStartIntent(mStartServiceIntents.get(0))); | |
| 479 assertTrue(isAndroidListenerStopIntent(mStartServiceIntents.get(1))); | |
| 480 } | |
| 481 | |
| 482 @SmallTest | |
| 483 @Feature({"Sync"}) | |
| 484 public void testClientStopsWhenShouldNotBeRunning() { | |
| 485 /* | |
| 486 * Test plan: start the client. Then, change the configuration so that C
hrome should not | |
| 487 * be running. Send an intent to the service and verify that it stops. | |
| 488 */ | |
| 489 getService().setShouldRunStates(true, true); | |
| 490 getService().onCreate(); | |
| 491 | |
| 492 // Start the service. | |
| 493 Intent startIntent = createStartIntent(); | |
| 494 getService().onHandleIntent(startIntent); | |
| 495 assertTrue(InvalidationService.getIsClientStartedForTest()); | |
| 496 | |
| 497 // Change configuration. | |
| 498 getService().setShouldRunStates(false, false); | |
| 499 | |
| 500 // Send an Intent and verify that the service stops. | |
| 501 getService().onHandleIntent(startIntent); | |
| 502 assertFalse(InvalidationService.getIsClientStartedForTest()); | |
| 503 | |
| 504 // The issued intents should have been an AndroidListener start intent f
ollowed by an | |
| 505 // AndroidListener stop intent. | |
| 506 assertEquals(2, mStartServiceIntents.size()); | |
| 507 assertTrue(isAndroidListenerStartIntent(mStartServiceIntents.get(0))); | |
| 508 assertTrue(isAndroidListenerStopIntent(mStartServiceIntents.get(1))); | |
| 509 } | |
| 510 | |
| 511 @SmallTest | |
| 512 @Feature({"Sync"}) | |
| 513 public void testRegistrationIntent() { | |
| 514 /* | |
| 515 * Test plan: send a registration-change intent. Verify that it starts t
he client and | |
| 516 * sets both the account and registrations in shared preferences. | |
| 517 */ | |
| 518 getService().setShouldRunStates(true, true); | |
| 519 getService().onCreate(); | |
| 520 | |
| 521 // Send register Intent. | |
| 522 Set<ModelType> desiredRegistrations = CollectionUtil.newHashSet( | |
| 523 ModelType.BOOKMARK, ModelType.SESSION); | |
| 524 Account account = AccountManagerHelper.createAccountFromName("test@examp
le.com"); | |
| 525 Intent registrationIntent = createRegisterIntent(account, false, desired
Registrations); | |
| 526 getService().onHandleIntent(registrationIntent); | |
| 527 | |
| 528 // Verify client started and state written. | |
| 529 assertTrue(InvalidationService.getIsClientStartedForTest()); | |
| 530 InvalidationPreferences invPrefs = new InvalidationPreferences(getContex
t()); | |
| 531 assertEquals(account, invPrefs.getSavedSyncedAccount()); | |
| 532 assertEquals(ModelType.modelTypesToSyncTypesForTest(desiredRegistrations
), | |
| 533 invPrefs.getSavedSyncedTypes()); | |
| 534 assertNull(invPrefs.getSavedObjectIds()); | |
| 535 assertEquals(1, mStartServiceIntents.size()); | |
| 536 assertTrue(isAndroidListenerStartIntent(mStartServiceIntents.get(0))); | |
| 537 | |
| 538 // Send another registration-change intent, this type with all-types set
to true, and | |
| 539 // verify that the on-disk state is updated and that no addition Intents
are issued. | |
| 540 getService().onHandleIntent(createRegisterIntent(account, true, null)); | |
| 541 assertEquals(account, invPrefs.getSavedSyncedAccount()); | |
| 542 assertEquals(CollectionUtil.newHashSet(ModelType.ALL_TYPES_TYPE), | |
| 543 invPrefs.getSavedSyncedTypes()); | |
| 544 assertEquals(1, mStartServiceIntents.size()); | |
| 545 | |
| 546 // Finally, send one more registration-change intent, this time with a d
ifferent account, | |
| 547 // and verify that it both updates the account, stops thye existing clie
nt, and | |
| 548 // starts a new client. | |
| 549 Account account2 = AccountManagerHelper.createAccountFromName("test2@exa
mple.com"); | |
| 550 getService().onHandleIntent(createRegisterIntent(account2, true, null)); | |
| 551 assertEquals(account2, invPrefs.getSavedSyncedAccount()); | |
| 552 assertEquals(3, mStartServiceIntents.size()); | |
| 553 assertTrue(isAndroidListenerStartIntent(mStartServiceIntents.get(0))); | |
| 554 assertTrue(isAndroidListenerStopIntent(mStartServiceIntents.get(1))); | |
| 555 assertTrue(isAndroidListenerStartIntent(mStartServiceIntents.get(2))); | |
| 556 } | |
| 557 | |
| 558 /** | |
| 559 * Determines if the correct object ids have been written to preferences and
registered with the | |
| 560 * invalidation client. | |
| 561 * | |
| 562 * @param expectedTypes The Sync types expected to be registered. | |
| 563 * @param expectedObjectIds The additional object ids expected to be registe
red. | |
| 564 * @param isReady Whether the client is ready to register/unregister. | |
| 565 */ | |
| 566 private boolean expectedObjectIdsRegistered(Set<ModelType> expectedTypes, | |
| 567 Set<ObjectId> expectedObjectIds, boolean isReady) { | |
| 568 // Get synced types saved to preferences. | |
| 569 Set<String> expectedSyncTypes = ModelType.modelTypesToSyncTypesForTest(e
xpectedTypes); | |
| 570 InvalidationPreferences invPrefs = new InvalidationPreferences(getContex
t()); | |
| 571 Set<String> actualSyncTypes = invPrefs.getSavedSyncedTypes(); | |
| 572 if (actualSyncTypes == null) { | |
| 573 actualSyncTypes = new HashSet<String>(); | |
| 574 } | |
| 575 | |
| 576 // Get object ids saved to preferences. | |
| 577 Set<ObjectId> actualObjectIds = invPrefs.getSavedObjectIds(); | |
| 578 if (actualObjectIds == null) { | |
| 579 actualObjectIds = new HashSet<ObjectId>(); | |
| 580 } | |
| 581 | |
| 582 // Get expected registered object ids. | |
| 583 Set<ObjectId> expectedRegisteredIds = new HashSet<ObjectId>(); | |
| 584 if (isReady) { | |
| 585 expectedRegisteredIds.addAll(ModelType.modelTypesToObjectIds(expecte
dTypes)); | |
| 586 expectedRegisteredIds.addAll(expectedObjectIds); | |
| 587 } | |
| 588 | |
| 589 return actualSyncTypes.equals(expectedSyncTypes) && | |
| 590 actualObjectIds.equals(expectedObjectIds) && | |
| 591 getService().mCurrentRegistrations.equals(expectedRegisteredIds)
; | |
| 592 } | |
| 593 | |
| 594 @SmallTest | |
| 595 @Feature({"Sync"}) | |
| 596 public void testRegistrationIntentWithTypesAndObjectIds() { | |
| 597 /* | |
| 598 * Test plan: send a mix of registration-change intents: some for Sync t
ypes and some for | |
| 599 * object ids. Verify that registering for Sync types does not interfere
with object id | |
| 600 * registration and vice-versa. | |
| 601 */ | |
| 602 getService().setShouldRunStates(true, true); | |
| 603 getService().onCreate(); | |
| 604 | |
| 605 Account account = AccountManagerHelper.createAccountFromName("test@examp
le.com"); | |
| 606 Set<ObjectId> objectIds = new HashSet<ObjectId>(); | |
| 607 Set<ModelType> types = new HashSet<ModelType>(); | |
| 608 | |
| 609 // Register for some object ids. | |
| 610 objectIds.add(ObjectId.newInstance(1, "obj1".getBytes())); | |
| 611 objectIds.add(ObjectId.newInstance(2, "obj2".getBytes())); | |
| 612 Intent registrationIntent = | |
| 613 createRegisterIntent(account, new int[] {1, 2}, new String[] {"obj1"
, "obj2"}); | |
| 614 getService().onHandleIntent(registrationIntent); | |
| 615 assertTrue(expectedObjectIdsRegistered(types, objectIds, false /* isRead
y */)); | |
| 616 | |
| 617 // Register for some types. | |
| 618 types.add(ModelType.BOOKMARK); | |
| 619 types.add(ModelType.SESSION); | |
| 620 registrationIntent = createRegisterIntent(account, false, types); | |
| 621 getService().onHandleIntent(registrationIntent); | |
| 622 assertTrue(expectedObjectIdsRegistered(types, objectIds, false /* isRead
y */)); | |
| 623 | |
| 624 // Set client to be ready and verify registrations. | |
| 625 getService().ready(CLIENT_ID); | |
| 626 assertTrue(expectedObjectIdsRegistered(types, objectIds, true /* isReady
*/)); | |
| 627 | |
| 628 // Change object id registration with types registered. | |
| 629 objectIds.add(ObjectId.newInstance(3, "obj3".getBytes())); | |
| 630 registrationIntent = createRegisterIntent( | |
| 631 account, new int[] {1, 2, 3}, new String[] {"obj1", "obj2", "obj3"})
; | |
| 632 getService().onHandleIntent(registrationIntent); | |
| 633 assertTrue(expectedObjectIdsRegistered(types, objectIds, true /* isReady
*/)); | |
| 634 | |
| 635 // Change type registration with object ids registered. | |
| 636 types.remove(ModelType.BOOKMARK); | |
| 637 registrationIntent = createRegisterIntent(account, false, types); | |
| 638 getService().onHandleIntent(registrationIntent); | |
| 639 assertTrue(expectedObjectIdsRegistered(types, objectIds, true /* isReady
*/)); | |
| 640 | |
| 641 // Unregister all types. | |
| 642 types.clear(); | |
| 643 registrationIntent = createRegisterIntent(account, false, types); | |
| 644 getService().onHandleIntent(registrationIntent); | |
| 645 assertTrue(expectedObjectIdsRegistered(types, objectIds, true /* isReady
*/)); | |
| 646 | |
| 647 // Change object id registration with no types registered. | |
| 648 objectIds.remove(ObjectId.newInstance(2, "obj2".getBytes())); | |
| 649 registrationIntent = createRegisterIntent( | |
| 650 account, new int[] {1, 3}, new String[] {"obj1", "obj3"}); | |
| 651 getService().onHandleIntent(registrationIntent); | |
| 652 assertTrue(expectedObjectIdsRegistered(types, objectIds, true /* isReady
*/)); | |
| 653 | |
| 654 // Unregister all object ids. | |
| 655 objectIds.clear(); | |
| 656 registrationIntent = createRegisterIntent(account, new int[0], new Strin
g[0]); | |
| 657 getService().onHandleIntent(registrationIntent); | |
| 658 assertTrue(expectedObjectIdsRegistered(types, objectIds, true /* isReady
*/)); | |
| 659 | |
| 660 // Change type registration with no object ids registered. | |
| 661 types.add(ModelType.BOOKMARK); | |
| 662 types.add(ModelType.PASSWORD); | |
| 663 registrationIntent = createRegisterIntent(account, false, types); | |
| 664 getService().onHandleIntent(registrationIntent); | |
| 665 assertTrue(expectedObjectIdsRegistered(types, objectIds, true /* isReady
*/)); | |
| 666 } | |
| 667 | |
| 668 @SmallTest | |
| 669 @Feature({"Sync"}) | |
| 670 public void testRegistrationIntentNoProxyTabsUsingReady() { | |
| 671 getService().setShouldRunStates(true, true); | |
| 672 getService().onCreate(); | |
| 673 | |
| 674 // Send register Intent. | |
| 675 Account account = AccountManagerHelper.createAccountFromName("test@examp
le.com"); | |
| 676 Intent registrationIntent = createRegisterIntent(account, true, null); | |
| 677 getService().onHandleIntent(registrationIntent); | |
| 678 | |
| 679 // Verify client started and state written. | |
| 680 assertTrue(InvalidationService.getIsClientStartedForTest()); | |
| 681 InvalidationPreferences invPrefs = new InvalidationPreferences(getContex
t()); | |
| 682 assertEquals(account, invPrefs.getSavedSyncedAccount()); | |
| 683 assertEquals(CollectionUtil.newHashSet(ModelType.ALL_TYPES_TYPE), | |
| 684 invPrefs.getSavedSyncedTypes()); | |
| 685 assertEquals(1, mStartServiceIntents.size()); | |
| 686 assertTrue(isAndroidListenerStartIntent(mStartServiceIntents.get(0))); | |
| 687 | |
| 688 // Set client to be ready. This triggers registrations. | |
| 689 getService().ready(CLIENT_ID); | |
| 690 assertTrue(Arrays.equals(CLIENT_ID, InvalidationService.getClientIdForTe
st())); | |
| 691 | |
| 692 // Ensure registrations are correct. | |
| 693 Set<ObjectId> expectedTypes = | |
| 694 ModelType.modelTypesToObjectIds(EnumSet.allOf(ModelType.class)); | |
| 695 assertEquals(expectedTypes, new HashSet<ObjectId>(getService().mRegistra
tions.get(0))); | |
| 696 } | |
| 697 | |
| 698 @SmallTest | |
| 699 @Feature({"Sync"}) | |
| 700 public void testRegistrationIntentNoProxyTabsAlreadyWithClientId() { | |
| 701 getService().setShouldRunStates(true, true); | |
| 702 getService().onCreate(); | |
| 703 | |
| 704 // Send register Intent with no desired types. | |
| 705 Account account = AccountManagerHelper.createAccountFromName("test@examp
le.com"); | |
| 706 Intent registrationIntent = createRegisterIntent(account, false, new Has
hSet<ModelType>()); | |
| 707 getService().onHandleIntent(registrationIntent); | |
| 708 | |
| 709 // Verify client started and state written. | |
| 710 assertTrue(InvalidationService.getIsClientStartedForTest()); | |
| 711 InvalidationPreferences invPrefs = new InvalidationPreferences(getContex
t()); | |
| 712 assertEquals(account, invPrefs.getSavedSyncedAccount()); | |
| 713 assertEquals(new HashSet<String>(), invPrefs.getSavedSyncedTypes()); | |
| 714 assertEquals(1, mStartServiceIntents.size()); | |
| 715 assertTrue(isAndroidListenerStartIntent(mStartServiceIntents.get(0))); | |
| 716 | |
| 717 // Make sure client is ready. | |
| 718 getService().ready(CLIENT_ID); | |
| 719 assertTrue(Arrays.equals(CLIENT_ID, InvalidationService.getClientIdForTe
st())); | |
| 720 | |
| 721 // Choose to register for all types in an already ready client. | |
| 722 registrationIntent = createRegisterIntent(account, true, null); | |
| 723 getService().onHandleIntent(registrationIntent); | |
| 724 | |
| 725 // Ensure registrations are correct. | |
| 726 assertEquals(1, getService().mRegistrations.size()); | |
| 727 Set<ObjectId> expectedTypes = | |
| 728 ModelType.modelTypesToObjectIds(EnumSet.allOf(ModelType.class)); | |
| 729 assertEquals(expectedTypes, new HashSet<ObjectId>(getService().mRegistra
tions.get(0))); | |
| 730 } | |
| 731 | |
| 732 @SmallTest | |
| 733 @Feature({"Sync"}) | |
| 734 public void testRegistrationIntentWhenClientShouldNotBeRunning() { | |
| 735 /* | |
| 736 * Test plan: send a registration change event when the client should no
t be running. | |
| 737 * Verify that the service updates the on-disk state but does not start
the client. | |
| 738 */ | |
| 739 getService().onCreate(); | |
| 740 | |
| 741 // Send register Intent. | |
| 742 Account account = AccountManagerHelper.createAccountFromName("test@examp
le.com"); | |
| 743 Set<ModelType> desiredRegistrations = CollectionUtil.newHashSet( | |
| 744 ModelType.BOOKMARK, ModelType.SESSION); | |
| 745 Intent registrationIntent = createRegisterIntent(account, false, desired
Registrations); | |
| 746 getService().onHandleIntent(registrationIntent); | |
| 747 | |
| 748 // Verify state written but client not started. | |
| 749 assertFalse(InvalidationService.getIsClientStartedForTest()); | |
| 750 InvalidationPreferences invPrefs = new InvalidationPreferences(getContex
t()); | |
| 751 assertEquals(account, invPrefs.getSavedSyncedAccount()); | |
| 752 assertEquals(ModelType.modelTypesToSyncTypesForTest(desiredRegistrations
), | |
| 753 invPrefs.getSavedSyncedTypes()); | |
| 754 assertEquals(0, mStartServiceIntents.size()); | |
| 755 } | |
| 756 | |
| 757 @SmallTest | |
| 758 @Feature({"Sync"}) | |
| 759 public void testDeferredRegistrationsIssued() { | |
| 760 /* | |
| 761 * Test plan: send a registration-change intent. Verify that the client
issues a start | |
| 762 * intent but makes no registration calls. Issue a reissueRegistrations
call and verify | |
| 763 * that the client does issue the appropriate registrations. | |
| 764 */ | |
| 765 getService().setShouldRunStates(true, true); | |
| 766 getService().onCreate(); | |
| 767 | |
| 768 // Send register Intent. Verify client started but no registrations issu
ed. | |
| 769 Account account = AccountManagerHelper.createAccountFromName("test@examp
le.com"); | |
| 770 Set<ModelType> desiredRegistrations = CollectionUtil.newHashSet( | |
| 771 ModelType.BOOKMARK, ModelType.SESSION); | |
| 772 Set<ObjectId> desiredObjectIds = ModelType.modelTypesToObjectIds(desired
Registrations); | |
| 773 | |
| 774 Intent registrationIntent = createRegisterIntent(account, false, desired
Registrations); | |
| 775 getService().onHandleIntent(registrationIntent); | |
| 776 assertTrue(InvalidationService.getIsClientStartedForTest()); | |
| 777 assertEquals(1, mStartServiceIntents.size()); | |
| 778 assertTrue(isAndroidListenerStartIntent(mStartServiceIntents.get(0))); | |
| 779 InvalidationPreferences invPrefs = new InvalidationPreferences(getContex
t()); | |
| 780 assertEquals(ModelType.modelTypesToSyncTypesForTest(desiredRegistrations
), | |
| 781 invPrefs.getSavedSyncedTypes()); | |
| 782 assertEquals(desiredObjectIds, getService().readRegistrationsFromPrefs()
); | |
| 783 | |
| 784 // Issue reissueRegistrations; verify registration intent issues. | |
| 785 getService().reissueRegistrations(CLIENT_ID); | |
| 786 assertEquals(2, mStartServiceIntents.size()); | |
| 787 Intent expectedRegisterIntent = AndroidListener.createRegisterIntent( | |
| 788 getContext(), | |
| 789 CLIENT_ID, | |
| 790 desiredObjectIds); | |
| 791 Intent actualRegisterIntent = mStartServiceIntents.get(1); | |
| 792 assertTrue(expectedRegisterIntent.filterEquals(actualRegisterIntent)); | |
| 793 assertEquals(expectedRegisterIntent.getExtras().keySet(), | |
| 794 actualRegisterIntent.getExtras().keySet()); | |
| 795 assertEquals( | |
| 796 desiredObjectIds, | |
| 797 new HashSet<ObjectId>(getService().mRegistrations.get(0))); | |
| 798 } | |
| 799 | |
| 800 @SmallTest | |
| 801 @Feature({"Sync"}) | |
| 802 public void testRegistrationRetries() { | |
| 803 /* | |
| 804 * Test plan: validate that the alarm receiver used by the AndroidListen
er underlying | |
| 805 * InvalidationService is correctly configured in the manifest and retri
es registrations | |
| 806 * with exponential backoff. May need to be implemented as a downstream
Chrome for Android | |
| 807 * test. | |
| 808 */ | |
| 809 // TODO(dsmyers): implement. | |
| 810 // Bug: https://code.google.com/p/chromium/issues/detail?id=172398 | |
| 811 } | |
| 812 | |
| 813 /** Creates an intent to start the InvalidationService. */ | |
| 814 private Intent createStartIntent() { | |
| 815 Intent intent = new Intent(); | |
| 816 return intent; | |
| 817 } | |
| 818 | |
| 819 /** Creates an intent to stop the InvalidationService. */ | |
| 820 private Intent createStopIntent() { | |
| 821 Intent intent = new Intent(); | |
| 822 intent.putExtra(InvalidationIntentProtocol.EXTRA_STOP, true); | |
| 823 return intent; | |
| 824 } | |
| 825 | |
| 826 /** Creates an intent to register some types with the InvalidationService. *
/ | |
| 827 private Intent createRegisterIntent(Account account, boolean allTypes, Set<M
odelType> types) { | |
| 828 Intent intent = InvalidationIntentProtocol.createRegisterIntent(account,
allTypes, types); | |
| 829 return intent; | |
| 830 } | |
| 831 | |
| 832 /** Creates an intent to register some types with the InvalidationService. *
/ | |
| 833 private Intent createRegisterIntent( | |
| 834 Account account, int[] objectSources, String[] objectNames) { | |
| 835 Intent intent = InvalidationIntentProtocol.createRegisterIntent( | |
| 836 account, objectSources, objectNames); | |
| 837 return intent; | |
| 838 } | |
| 839 | |
| 840 /** Returns whether {@code intent} is an {@link AndroidListener} start inten
t. */ | |
| 841 private boolean isAndroidListenerStartIntent(Intent intent) { | |
| 842 Intent startIntent = AndroidListener.createStartIntent(getContext(), | |
| 843 InvalidationService.CLIENT_TYPE, "unused".getBytes()); | |
| 844 return intent.getExtras().keySet().equals(startIntent.getExtras().keySet
()); | |
| 845 } | |
| 846 | |
| 847 /** Returns whether {@code intent} is an {@link AndroidListener} stop intent
. */ | |
| 848 private boolean isAndroidListenerStopIntent(Intent intent) { | |
| 849 Intent stopIntent = AndroidListener.createStopIntent(getContext()); | |
| 850 return intent.getExtras().keySet().equals(stopIntent.getExtras().keySet(
)); | |
| 851 } | |
| 852 } | |
| OLD | NEW |