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 |