1 // Copyright 2014 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.
11 #include "base/compiler_specific.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/stl_util.h"
14 #include "components/invalidation/fake_invalidation_state_tracker.h"
15 #include "components/invalidation/invalidation_util.h"
16 #include "components/invalidation/object_id_invalidation_map.h"
17 #include "components/invalidation/push_client_channel.h"
18 #include "components/invalidation/sync_invalidation_listener.h"
19 #include "components/invalidation/unacked_invalidation_set_test_util.h"
20 #include "google/cacheinvalidation/include/invalidation-client.h"
21 #include "google/cacheinvalidation/include/types.h"
22 #include "jingle/notifier/listener/fake_push_client.h"
23 #include "testing/gtest/include/gtest/gtest.h"
29 using invalidation::AckHandle
;
30 using invalidation::ObjectId
;
32 const char kClientId
[] = "client_id";
33 const char kClientInfo
[] = "client_info";
35 const char kState
[] = "state";
36 const char kNewState
[] = "new_state";
38 const char kPayload1
[] = "payload1";
39 const char kPayload2
[] = "payload2";
41 const int64 kVersion1
= 1LL;
42 const int64 kVersion2
= 2LL;
44 const int kChromeSyncSourceId
= 1004;
46 struct AckHandleLessThan
{
47 bool operator()(const AckHandle
& lhs
, const AckHandle
& rhs
) const {
48 return lhs
.handle_data() < rhs
.handle_data();
52 typedef std::set
<AckHandle
, AckHandleLessThan
> AckHandleSet
;
54 // Fake invalidation::InvalidationClient implementation that keeps
55 // track of registered IDs and acked handles.
56 class FakeInvalidationClient
: public invalidation::InvalidationClient
{
58 FakeInvalidationClient() : started_(false) {}
59 ~FakeInvalidationClient() override
{}
61 const ObjectIdSet
& GetRegisteredIds() const {
62 return registered_ids_
;
65 void ClearAckedHandles() {
66 acked_handles_
.clear();
69 bool IsAckedHandle(const AckHandle
& ack_handle
) const {
70 return (acked_handles_
.find(ack_handle
) != acked_handles_
.end());
73 // invalidation::InvalidationClient implementation.
75 void Start() override
{ started_
= true; }
77 void Stop() override
{ started_
= false; }
79 void Register(const ObjectId
& object_id
) override
{
84 registered_ids_
.insert(object_id
);
87 void Register(const invalidation::vector
<ObjectId
>& object_ids
) override
{
92 registered_ids_
.insert(object_ids
.begin(), object_ids
.end());
95 void Unregister(const ObjectId
& object_id
) override
{
100 registered_ids_
.erase(object_id
);
103 void Unregister(const invalidation::vector
<ObjectId
>& object_ids
) override
{
108 for (invalidation::vector
<ObjectId
>::const_iterator
109 it
= object_ids
.begin(); it
!= object_ids
.end(); ++it
) {
110 registered_ids_
.erase(*it
);
114 void Acknowledge(const AckHandle
& ack_handle
) override
{
119 acked_handles_
.insert(ack_handle
);
124 ObjectIdSet registered_ids_
;
125 AckHandleSet acked_handles_
;
128 // Fake delegate tkat keeps track of invalidation counts, payloads,
130 class FakeDelegate
: public SyncInvalidationListener::Delegate
{
132 explicit FakeDelegate(SyncInvalidationListener
* listener
)
133 : state_(TRANSIENT_INVALIDATION_ERROR
) {}
134 ~FakeDelegate() override
{}
136 size_t GetInvalidationCount(const ObjectId
& id
) const {
137 Map::const_iterator it
= invalidations_
.find(id
);
138 if (it
== invalidations_
.end()) {
141 return it
->second
.size();
145 int64
GetVersion(const ObjectId
& id
) const {
146 Map::const_iterator it
= invalidations_
.find(id
);
147 if (it
== invalidations_
.end()) {
148 ADD_FAILURE() << "No invalidations for ID " << ObjectIdToString(id
);
151 return it
->second
.back().version();
155 std::string
GetPayload(const ObjectId
& id
) const {
156 Map::const_iterator it
= invalidations_
.find(id
);
157 if (it
== invalidations_
.end()) {
158 ADD_FAILURE() << "No invalidations for ID " << ObjectIdToString(id
);
161 return it
->second
.back().payload();
165 bool IsUnknownVersion(const ObjectId
& id
) const {
166 Map::const_iterator it
= invalidations_
.find(id
);
167 if (it
== invalidations_
.end()) {
168 ADD_FAILURE() << "No invalidations for ID " << ObjectIdToString(id
);
171 return it
->second
.back().is_unknown_version();
175 bool StartsWithUnknownVersion(const ObjectId
& id
) const {
176 Map::const_iterator it
= invalidations_
.find(id
);
177 if (it
== invalidations_
.end()) {
178 ADD_FAILURE() << "No invalidations for ID " << ObjectIdToString(id
);
181 return it
->second
.front().is_unknown_version();
185 InvalidatorState
GetInvalidatorState() const {
189 void AcknowledgeNthInvalidation(const ObjectId
& id
, size_t n
) {
190 List
& list
= invalidations_
[id
];
191 List::iterator it
= list
.begin() + n
;
195 void AcknowledgeAll(const ObjectId
& id
) {
196 List
& list
= invalidations_
[id
];
197 for (List::iterator it
= list
.begin(); it
!= list
.end(); ++it
) {
202 void DropNthInvalidation(const ObjectId
& id
, size_t n
) {
203 List
& list
= invalidations_
[id
];
204 List::iterator it
= list
.begin() + n
;
206 dropped_invalidations_map_
.erase(id
);
207 dropped_invalidations_map_
.insert(std::make_pair(id
, *it
));
210 void RecoverFromDropEvent(const ObjectId
& id
) {
211 DropMap::iterator it
= dropped_invalidations_map_
.find(id
);
212 if (it
!= dropped_invalidations_map_
.end()) {
213 it
->second
.Acknowledge();
214 dropped_invalidations_map_
.erase(it
);
218 // SyncInvalidationListener::Delegate implementation.
219 void OnInvalidate(const ObjectIdInvalidationMap
& invalidation_map
) override
{
220 ObjectIdSet ids
= invalidation_map
.GetObjectIds();
221 for (ObjectIdSet::iterator it
= ids
.begin(); it
!= ids
.end(); ++it
) {
222 const SingleObjectInvalidationSet
& incoming
=
223 invalidation_map
.ForObject(*it
);
224 List
& list
= invalidations_
[*it
];
225 list
.insert(list
.end(), incoming
.begin(), incoming
.end());
229 void OnInvalidatorStateChange(InvalidatorState state
) override
{
234 typedef std::vector
<Invalidation
> List
;
235 typedef std::map
<ObjectId
, List
, ObjectIdLessThan
> Map
;
236 typedef std::map
<ObjectId
, Invalidation
, ObjectIdLessThan
> DropMap
;
239 InvalidatorState state_
;
240 DropMap dropped_invalidations_map_
;
243 invalidation::InvalidationClient
* CreateFakeInvalidationClient(
244 FakeInvalidationClient
** fake_invalidation_client
,
245 invalidation::SystemResources
* resources
,
247 const invalidation::string
& client_name
,
248 const invalidation::string
& application_name
,
249 invalidation::InvalidationListener
* listener
) {
250 *fake_invalidation_client
= new FakeInvalidationClient();
251 return *fake_invalidation_client
;
254 class SyncInvalidationListenerTest
: public testing::Test
{
256 SyncInvalidationListenerTest()
257 : kBookmarksId_(kChromeSyncSourceId
, "BOOKMARK"),
258 kPreferencesId_(kChromeSyncSourceId
, "PREFERENCE"),
259 kExtensionsId_(kChromeSyncSourceId
, "EXTENSION"),
260 kAppsId_(kChromeSyncSourceId
, "APP"),
261 fake_push_client_(new notifier::FakePushClient()),
262 fake_invalidation_client_(NULL
),
263 listener_(scoped_ptr
<SyncNetworkChannel
>(new PushClientChannel(
264 scoped_ptr
<notifier::PushClient
>(fake_push_client_
)))),
265 fake_delegate_(&listener_
) {}
267 void SetUp() override
{
270 registered_ids_
.insert(kBookmarksId_
);
271 registered_ids_
.insert(kPreferencesId_
);
272 listener_
.UpdateRegisteredIds(registered_ids_
);
275 void TearDown() override
{ StopClient(); }
277 // Restart client without re-registering IDs.
278 void RestartClient() {
284 fake_invalidation_client_
= NULL
;
286 base::Bind(&CreateFakeInvalidationClient
, &fake_invalidation_client_
),
290 fake_tracker_
.GetSavedInvalidations(),
291 fake_tracker_
.AsWeakPtr(),
292 base::MessageLoopProxy::current(),
294 DCHECK(fake_invalidation_client_
);
298 // listener_.StopForTest() stops the invalidation scheduler, which
299 // deletes any pending tasks without running them. Some tasks
300 // "run and delete" another task, so they must be run in order to
301 // avoid leaking the inner task. listener_.StopForTest() does not
302 // schedule any tasks, so it's both necessary and sufficient to
303 // drain the task queue before calling it.
304 FlushPendingWrites();
305 fake_invalidation_client_
= NULL
;
306 listener_
.StopForTest();
309 size_t GetInvalidationCount(const ObjectId
& id
) const {
310 return fake_delegate_
.GetInvalidationCount(id
);
313 int64
GetVersion(const ObjectId
& id
) const {
314 return fake_delegate_
.GetVersion(id
);
317 std::string
GetPayload(const ObjectId
& id
) const {
318 return fake_delegate_
.GetPayload(id
);
321 bool IsUnknownVersion(const ObjectId
& id
) const {
322 return fake_delegate_
.IsUnknownVersion(id
);
325 bool StartsWithUnknownVersion(const ObjectId
& id
) const {
326 return fake_delegate_
.StartsWithUnknownVersion(id
);
329 void AcknowledgeNthInvalidation(const ObjectId
& id
, size_t n
) {
330 fake_delegate_
.AcknowledgeNthInvalidation(id
, n
);
333 void DropNthInvalidation(const ObjectId
& id
, size_t n
) {
334 return fake_delegate_
.DropNthInvalidation(id
, n
);
337 void RecoverFromDropEvent(const ObjectId
& id
) {
338 return fake_delegate_
.RecoverFromDropEvent(id
);
341 void AcknowledgeAll(const ObjectId
& id
) {
342 fake_delegate_
.AcknowledgeAll(id
);
345 InvalidatorState
GetInvalidatorState() const {
346 return fake_delegate_
.GetInvalidatorState();
349 std::string
GetInvalidatorClientId() const {
350 return fake_tracker_
.GetInvalidatorClientId();
353 std::string
GetBootstrapData() const {
354 return fake_tracker_
.GetBootstrapData();
357 UnackedInvalidationsMap
GetSavedInvalidations() {
358 // Allow any queued writes to go through first.
359 FlushPendingWrites();
360 return fake_tracker_
.GetSavedInvalidations();
363 SingleObjectInvalidationSet
GetSavedInvalidationsForType(const ObjectId
& id
) {
364 const UnackedInvalidationsMap
& saved_state
= GetSavedInvalidations();
365 UnackedInvalidationsMap::const_iterator it
=
366 saved_state
.find(kBookmarksId_
);
367 if (it
== saved_state
.end()) {
368 ADD_FAILURE() << "No state saved for ID " << ObjectIdToString(id
);
369 return SingleObjectInvalidationSet();
371 ObjectIdInvalidationMap map
;
372 it
->second
.ExportInvalidations(
373 base::WeakPtr
<AckHandler
>(),
374 scoped_refptr
<base::SingleThreadTaskRunner
>(),
377 return SingleObjectInvalidationSet();
379 return map
.ForObject(id
);
383 ObjectIdSet
GetRegisteredIds() const {
384 return fake_invalidation_client_
->GetRegisteredIds();
387 // |payload| can be NULL.
388 void FireInvalidate(const ObjectId
& object_id
,
389 int64 version
, const char* payload
) {
390 invalidation::Invalidation inv
;
392 inv
= invalidation::Invalidation(object_id
, version
, payload
);
394 inv
= invalidation::Invalidation(object_id
, version
);
396 const AckHandle
ack_handle("fakedata");
397 fake_invalidation_client_
->ClearAckedHandles();
398 listener_
.Invalidate(fake_invalidation_client_
, inv
, ack_handle
);
399 EXPECT_TRUE(fake_invalidation_client_
->IsAckedHandle(ack_handle
));
402 // |payload| can be NULL, but not |type_name|.
403 void FireInvalidateUnknownVersion(const ObjectId
& object_id
) {
404 const AckHandle
ack_handle("fakedata_unknown");
405 fake_invalidation_client_
->ClearAckedHandles();
406 listener_
.InvalidateUnknownVersion(fake_invalidation_client_
,
409 EXPECT_TRUE(fake_invalidation_client_
->IsAckedHandle(ack_handle
));
412 void FireInvalidateAll() {
413 const AckHandle
ack_handle("fakedata_all");
414 fake_invalidation_client_
->ClearAckedHandles();
415 listener_
.InvalidateAll(fake_invalidation_client_
, ack_handle
);
416 EXPECT_TRUE(fake_invalidation_client_
->IsAckedHandle(ack_handle
));
419 void WriteState(const std::string
& new_state
) {
420 listener_
.WriteState(new_state
);
422 // Pump message loop to trigger
423 // InvalidationStateTracker::WriteState().
424 FlushPendingWrites();
427 void FlushPendingWrites() {
428 message_loop_
.RunUntilIdle();
431 void EnableNotifications() {
432 fake_push_client_
->EnableNotifications();
435 void DisableNotifications(notifier::NotificationsDisabledReason reason
) {
436 fake_push_client_
->DisableNotifications(reason
);
439 const ObjectId kBookmarksId_
;
440 const ObjectId kPreferencesId_
;
441 const ObjectId kExtensionsId_
;
442 const ObjectId kAppsId_
;
444 ObjectIdSet registered_ids_
;
447 base::MessageLoop message_loop_
;
448 notifier::FakePushClient
* const fake_push_client_
;
451 // A derrived test needs direct access to this.
452 FakeInvalidationStateTracker fake_tracker_
;
454 // Tests need to access these directly.
455 FakeInvalidationClient
* fake_invalidation_client_
;
456 SyncInvalidationListener listener_
;
459 FakeDelegate fake_delegate_
;
462 // Write a new state to the client. It should propagate to the
464 TEST_F(SyncInvalidationListenerTest
, WriteState
) {
465 WriteState(kNewState
);
467 EXPECT_EQ(kNewState
, GetBootstrapData());
470 // Invalidation tests.
472 // Fire an invalidation without a payload. It should be processed,
473 // the payload should remain empty, and the version should be updated.
474 TEST_F(SyncInvalidationListenerTest
, InvalidateNoPayload
) {
475 const ObjectId
& id
= kBookmarksId_
;
477 FireInvalidate(id
, kVersion1
, NULL
);
479 ASSERT_EQ(1U, GetInvalidationCount(id
));
480 ASSERT_FALSE(IsUnknownVersion(id
));
481 EXPECT_EQ(kVersion1
, GetVersion(id
));
482 EXPECT_EQ("", GetPayload(id
));
485 // Fire an invalidation with an empty payload. It should be
486 // processed, the payload should remain empty, and the version should
488 TEST_F(SyncInvalidationListenerTest
, InvalidateEmptyPayload
) {
489 const ObjectId
& id
= kBookmarksId_
;
491 FireInvalidate(id
, kVersion1
, "");
493 ASSERT_EQ(1U, GetInvalidationCount(id
));
494 ASSERT_FALSE(IsUnknownVersion(id
));
495 EXPECT_EQ(kVersion1
, GetVersion(id
));
496 EXPECT_EQ("", GetPayload(id
));
499 // Fire an invalidation with a payload. It should be processed, and
500 // both the payload and the version should be updated.
501 TEST_F(SyncInvalidationListenerTest
, InvalidateWithPayload
) {
502 const ObjectId
& id
= kPreferencesId_
;
504 FireInvalidate(id
, kVersion1
, kPayload1
);
506 ASSERT_EQ(1U, GetInvalidationCount(id
));
507 ASSERT_FALSE(IsUnknownVersion(id
));
508 EXPECT_EQ(kVersion1
, GetVersion(id
));
509 EXPECT_EQ(kPayload1
, GetPayload(id
));
512 // Fire ten invalidations in a row. All should be received.
513 TEST_F(SyncInvalidationListenerTest
, ManyInvalidations_NoDrop
) {
514 const int kRepeatCount
= 10;
515 const ObjectId
& id
= kPreferencesId_
;
516 int64 initial_version
= kVersion1
;
517 for (int64 i
= initial_version
; i
< initial_version
+ kRepeatCount
; ++i
) {
518 FireInvalidate(id
, i
, kPayload1
);
520 ASSERT_EQ(static_cast<size_t>(kRepeatCount
), GetInvalidationCount(id
));
521 ASSERT_FALSE(IsUnknownVersion(id
));
522 EXPECT_EQ(kPayload1
, GetPayload(id
));
523 EXPECT_EQ(initial_version
+ kRepeatCount
- 1, GetVersion(id
));
526 // Fire an invalidation for an unregistered object ID with a payload. It should
527 // still be processed, and both the payload and the version should be updated.
528 TEST_F(SyncInvalidationListenerTest
, InvalidateBeforeRegistration_Simple
) {
529 const ObjectId
kUnregisteredId(kChromeSyncSourceId
, "unregistered");
530 const ObjectId
& id
= kUnregisteredId
;
534 EXPECT_EQ(0U, GetInvalidationCount(id
));
536 FireInvalidate(id
, kVersion1
, kPayload1
);
538 ASSERT_EQ(0U, GetInvalidationCount(id
));
540 EnableNotifications();
541 listener_
.Ready(fake_invalidation_client_
);
542 listener_
.UpdateRegisteredIds(ids
);
544 ASSERT_EQ(1U, GetInvalidationCount(id
));
545 ASSERT_FALSE(IsUnknownVersion(id
));
546 EXPECT_EQ(kVersion1
, GetVersion(id
));
547 EXPECT_EQ(kPayload1
, GetPayload(id
));
550 // Fire ten invalidations before an object registers. Some invalidations will
551 // be dropped an replaced with an unknown version invalidation.
552 TEST_F(SyncInvalidationListenerTest
, InvalidateBeforeRegistration_Drop
) {
553 const int kRepeatCount
=
554 UnackedInvalidationSet::kMaxBufferedInvalidations
+ 1;
555 const ObjectId
kUnregisteredId(kChromeSyncSourceId
, "unregistered");
556 const ObjectId
& id
= kUnregisteredId
;
560 EXPECT_EQ(0U, GetInvalidationCount(id
));
562 int64 initial_version
= kVersion1
;
563 for (int64 i
= initial_version
; i
< initial_version
+ kRepeatCount
; ++i
) {
564 FireInvalidate(id
, i
, kPayload1
);
567 EnableNotifications();
568 listener_
.Ready(fake_invalidation_client_
);
569 listener_
.UpdateRegisteredIds(ids
);
571 ASSERT_EQ(UnackedInvalidationSet::kMaxBufferedInvalidations
,
572 GetInvalidationCount(id
));
573 ASSERT_FALSE(IsUnknownVersion(id
));
574 EXPECT_EQ(initial_version
+ kRepeatCount
- 1, GetVersion(id
));
575 EXPECT_EQ(kPayload1
, GetPayload(id
));
576 EXPECT_TRUE(StartsWithUnknownVersion(id
));
579 // Fire an invalidation, then fire another one with a lower version. Both
580 // should be received.
581 TEST_F(SyncInvalidationListenerTest
, InvalidateVersion
) {
582 const ObjectId
& id
= kPreferencesId_
;
584 FireInvalidate(id
, kVersion2
, kPayload2
);
586 ASSERT_EQ(1U, GetInvalidationCount(id
));
587 ASSERT_FALSE(IsUnknownVersion(id
));
588 EXPECT_EQ(kVersion2
, GetVersion(id
));
589 EXPECT_EQ(kPayload2
, GetPayload(id
));
591 FireInvalidate(id
, kVersion1
, kPayload1
);
593 ASSERT_EQ(2U, GetInvalidationCount(id
));
594 ASSERT_FALSE(IsUnknownVersion(id
));
596 EXPECT_EQ(kVersion1
, GetVersion(id
));
597 EXPECT_EQ(kPayload1
, GetPayload(id
));
600 // Fire an invalidation with an unknown version.
601 TEST_F(SyncInvalidationListenerTest
, InvalidateUnknownVersion
) {
602 const ObjectId
& id
= kBookmarksId_
;
604 FireInvalidateUnknownVersion(id
);
606 ASSERT_EQ(1U, GetInvalidationCount(id
));
607 EXPECT_TRUE(IsUnknownVersion(id
));
610 // Fire an invalidation for all enabled IDs.
611 TEST_F(SyncInvalidationListenerTest
, InvalidateAll
) {
614 for (ObjectIdSet::const_iterator it
= registered_ids_
.begin();
615 it
!= registered_ids_
.end(); ++it
) {
616 ASSERT_EQ(1U, GetInvalidationCount(*it
));
617 EXPECT_TRUE(IsUnknownVersion(*it
));
621 // Test a simple scenario for multiple IDs.
622 TEST_F(SyncInvalidationListenerTest
, InvalidateMultipleIds
) {
623 FireInvalidate(kBookmarksId_
, 3, NULL
);
625 ASSERT_EQ(1U, GetInvalidationCount(kBookmarksId_
));
626 ASSERT_FALSE(IsUnknownVersion(kBookmarksId_
));
627 EXPECT_EQ(3, GetVersion(kBookmarksId_
));
628 EXPECT_EQ("", GetPayload(kBookmarksId_
));
630 // kExtensionId is not registered, so the invalidation should not get through.
631 FireInvalidate(kExtensionsId_
, 2, NULL
);
632 ASSERT_EQ(0U, GetInvalidationCount(kExtensionsId_
));
635 // Registration tests.
637 // With IDs already registered, enable notifications then ready the
638 // client. The IDs should be registered only after the client is
640 TEST_F(SyncInvalidationListenerTest
, RegisterEnableReady
) {
641 EXPECT_TRUE(GetRegisteredIds().empty());
643 EnableNotifications();
645 EXPECT_TRUE(GetRegisteredIds().empty());
647 listener_
.Ready(fake_invalidation_client_
);
649 EXPECT_EQ(registered_ids_
, GetRegisteredIds());
652 // With IDs already registered, ready the client then enable
653 // notifications. The IDs should be registered after the client is
655 TEST_F(SyncInvalidationListenerTest
, RegisterReadyEnable
) {
656 EXPECT_TRUE(GetRegisteredIds().empty());
658 listener_
.Ready(fake_invalidation_client_
);
660 EXPECT_EQ(registered_ids_
, GetRegisteredIds());
662 EnableNotifications();
664 EXPECT_EQ(registered_ids_
, GetRegisteredIds());
667 // Unregister the IDs, enable notifications, re-register the IDs, then
668 // ready the client. The IDs should be registered only after the
669 // client is readied.
670 TEST_F(SyncInvalidationListenerTest
, EnableRegisterReady
) {
671 listener_
.UpdateRegisteredIds(ObjectIdSet());
673 EXPECT_TRUE(GetRegisteredIds().empty());
675 EnableNotifications();
677 EXPECT_TRUE(GetRegisteredIds().empty());
679 listener_
.UpdateRegisteredIds(registered_ids_
);
681 EXPECT_TRUE(GetRegisteredIds().empty());
683 listener_
.Ready(fake_invalidation_client_
);
685 EXPECT_EQ(registered_ids_
, GetRegisteredIds());
688 // Unregister the IDs, enable notifications, ready the client, then
689 // re-register the IDs. The IDs should be registered only after the
690 // client is readied.
691 TEST_F(SyncInvalidationListenerTest
, EnableReadyRegister
) {
692 listener_
.UpdateRegisteredIds(ObjectIdSet());
694 EXPECT_TRUE(GetRegisteredIds().empty());
696 EnableNotifications();
698 EXPECT_TRUE(GetRegisteredIds().empty());
700 listener_
.Ready(fake_invalidation_client_
);
702 EXPECT_TRUE(GetRegisteredIds().empty());
704 listener_
.UpdateRegisteredIds(registered_ids_
);
706 EXPECT_EQ(registered_ids_
, GetRegisteredIds());
709 // Unregister the IDs, ready the client, enable notifications, then
710 // re-register the IDs. The IDs should be registered only after the
711 // client is readied.
712 TEST_F(SyncInvalidationListenerTest
, ReadyEnableRegister
) {
713 listener_
.UpdateRegisteredIds(ObjectIdSet());
715 EXPECT_TRUE(GetRegisteredIds().empty());
717 EnableNotifications();
719 EXPECT_TRUE(GetRegisteredIds().empty());
721 listener_
.Ready(fake_invalidation_client_
);
723 EXPECT_TRUE(GetRegisteredIds().empty());
725 listener_
.UpdateRegisteredIds(registered_ids_
);
727 EXPECT_EQ(registered_ids_
, GetRegisteredIds());
730 // Unregister the IDs, ready the client, re-register the IDs, then
731 // enable notifications. The IDs should be registered only after the
732 // client is readied.
734 // This test is important: see http://crbug.com/139424.
735 TEST_F(SyncInvalidationListenerTest
, ReadyRegisterEnable
) {
736 listener_
.UpdateRegisteredIds(ObjectIdSet());
738 EXPECT_TRUE(GetRegisteredIds().empty());
740 listener_
.Ready(fake_invalidation_client_
);
742 EXPECT_TRUE(GetRegisteredIds().empty());
744 listener_
.UpdateRegisteredIds(registered_ids_
);
746 EXPECT_EQ(registered_ids_
, GetRegisteredIds());
748 EnableNotifications();
750 EXPECT_EQ(registered_ids_
, GetRegisteredIds());
753 // With IDs already registered, ready the client, restart the client,
754 // then re-ready it. The IDs should still be registered.
755 TEST_F(SyncInvalidationListenerTest
, RegisterTypesPreserved
) {
756 EXPECT_TRUE(GetRegisteredIds().empty());
758 listener_
.Ready(fake_invalidation_client_
);
760 EXPECT_EQ(registered_ids_
, GetRegisteredIds());
764 EXPECT_TRUE(GetRegisteredIds().empty());
766 listener_
.Ready(fake_invalidation_client_
);
768 EXPECT_EQ(registered_ids_
, GetRegisteredIds());
771 // Make sure that state is correctly purged from the local invalidation state
772 // map cache when an ID is unregistered.
773 TEST_F(SyncInvalidationListenerTest
, UnregisterCleansUpStateMapCache
) {
774 const ObjectId
& id
= kBookmarksId_
;
775 listener_
.Ready(fake_invalidation_client_
);
777 EXPECT_TRUE(GetSavedInvalidations().empty());
778 FireInvalidate(id
, 1, "hello");
779 EXPECT_EQ(1U, GetSavedInvalidations().size());
780 EXPECT_TRUE(ContainsKey(GetSavedInvalidations(), id
));
781 FireInvalidate(kPreferencesId_
, 2, "world");
782 EXPECT_EQ(2U, GetSavedInvalidations().size());
784 EXPECT_TRUE(ContainsKey(GetSavedInvalidations(), id
));
785 EXPECT_TRUE(ContainsKey(GetSavedInvalidations(), kPreferencesId_
));
789 listener_
.UpdateRegisteredIds(ids
);
790 EXPECT_EQ(1U, GetSavedInvalidations().size());
791 EXPECT_TRUE(ContainsKey(GetSavedInvalidations(), id
));
794 TEST_F(SyncInvalidationListenerTest
, DuplicateInvaldiations_Simple
) {
795 const ObjectId
& id
= kBookmarksId_
;
796 listener_
.Ready(fake_invalidation_client_
);
798 // Send a stream of invalidations, including two copies of the second.
799 FireInvalidate(id
, 1, "one");
800 FireInvalidate(id
, 2, "two");
801 FireInvalidate(id
, 3, "three");
802 FireInvalidate(id
, 2, "two");
804 // Expect that the duplicate was discarded.
805 SingleObjectInvalidationSet list
= GetSavedInvalidationsForType(id
);
806 EXPECT_EQ(3U, list
.GetSize());
807 SingleObjectInvalidationSet::const_iterator it
= list
.begin();
808 EXPECT_EQ(1, it
->version());
810 EXPECT_EQ(2, it
->version());
812 EXPECT_EQ(3, it
->version());
815 TEST_F(SyncInvalidationListenerTest
, DuplicateInvalidations_NearBufferLimit
) {
816 const size_t kPairsToSend
= UnackedInvalidationSet::kMaxBufferedInvalidations
;
817 const ObjectId
& id
= kBookmarksId_
;
818 listener_
.Ready(fake_invalidation_client_
);
820 // We will have enough buffer space in the state tracker for all these
821 // invalidations only if duplicates are ignored.
822 for (size_t i
= 0; i
< kPairsToSend
; ++i
) {
823 FireInvalidate(id
, i
, "payload");
824 FireInvalidate(id
, i
, "payload");
827 // Expect that the state map ignored duplicates.
828 SingleObjectInvalidationSet list
= GetSavedInvalidationsForType(id
);
829 EXPECT_EQ(kPairsToSend
, list
.GetSize());
830 EXPECT_FALSE(list
.begin()->is_unknown_version());
832 // Expect that all invalidations (including duplicates) were emitted.
833 EXPECT_EQ(kPairsToSend
*2, GetInvalidationCount(id
));
835 // Acknowledge all invalidations to clear the internal state.
837 EXPECT_TRUE(GetSavedInvalidationsForType(id
).IsEmpty());
840 TEST_F(SyncInvalidationListenerTest
, DuplicateInvalidations_UnknownVersion
) {
841 const ObjectId
& id
= kBookmarksId_
;
842 listener_
.Ready(fake_invalidation_client_
);
844 FireInvalidateUnknownVersion(id
);
845 FireInvalidateUnknownVersion(id
);
848 SingleObjectInvalidationSet list
= GetSavedInvalidationsForType(id
);
849 EXPECT_EQ(1U, list
.GetSize());
852 // Acknowledge the second. There should be no effect on the stored list.
853 ASSERT_EQ(2U, GetInvalidationCount(id
));
854 AcknowledgeNthInvalidation(id
, 1);
856 SingleObjectInvalidationSet list
= GetSavedInvalidationsForType(id
);
857 EXPECT_EQ(1U, list
.GetSize());
860 // Acknowledge the first. This should remove the invalidation from the list.
861 ASSERT_EQ(2U, GetInvalidationCount(id
));
862 AcknowledgeNthInvalidation(id
, 0);
864 SingleObjectInvalidationSet list
= GetSavedInvalidationsForType(id
);
865 EXPECT_EQ(0U, list
.GetSize());
869 // Make sure that acknowledgements erase items from the local store.
870 TEST_F(SyncInvalidationListenerTest
, AcknowledgementsCleanUpStateMapCache
) {
871 const ObjectId
& id
= kBookmarksId_
;
872 listener_
.Ready(fake_invalidation_client_
);
874 EXPECT_TRUE(GetSavedInvalidations().empty());
875 FireInvalidate(id
, 10, "hello");
876 FireInvalidate(id
, 20, "world");
877 FireInvalidateUnknownVersion(id
);
879 // Expect that all three invalidations have been saved to permanent storage.
881 SingleObjectInvalidationSet list
= GetSavedInvalidationsForType(id
);
882 ASSERT_EQ(3U, list
.GetSize());
883 EXPECT_TRUE(list
.begin()->is_unknown_version());
884 EXPECT_EQ(20, list
.back().version());
887 // Acknowledge the second sent invaldiation (version 20) and verify it was
888 // removed from storage.
889 AcknowledgeNthInvalidation(id
, 1);
891 SingleObjectInvalidationSet list
= GetSavedInvalidationsForType(id
);
892 ASSERT_EQ(2U, list
.GetSize());
893 EXPECT_TRUE(list
.begin()->is_unknown_version());
894 EXPECT_EQ(10, list
.back().version());
897 // Acknowledge the last sent invalidation (unknown version) and verify it was
898 // removed from storage.
899 AcknowledgeNthInvalidation(id
, 2);
901 SingleObjectInvalidationSet list
= GetSavedInvalidationsForType(id
);
902 ASSERT_EQ(1U, list
.GetSize());
903 EXPECT_FALSE(list
.begin()->is_unknown_version());
904 EXPECT_EQ(10, list
.back().version());
908 // Make sure that drops erase items from the local store.
909 TEST_F(SyncInvalidationListenerTest
, DropsCleanUpStateMapCache
) {
910 const ObjectId
& id
= kBookmarksId_
;
911 listener_
.Ready(fake_invalidation_client_
);
913 EXPECT_TRUE(GetSavedInvalidations().empty());
914 FireInvalidate(id
, 10, "hello");
915 FireInvalidate(id
, 20, "world");
916 FireInvalidateUnknownVersion(id
);
918 // Expect that all three invalidations have been saved to permanent storage.
920 SingleObjectInvalidationSet list
= GetSavedInvalidationsForType(id
);
921 ASSERT_EQ(3U, list
.GetSize());
922 EXPECT_TRUE(list
.begin()->is_unknown_version());
923 EXPECT_EQ(20, list
.back().version());
926 // Drop the second sent invalidation (version 20) and verify it was removed
927 // from storage. Also verify we still have an unknown version invalidation.
928 DropNthInvalidation(id
, 1);
930 SingleObjectInvalidationSet list
= GetSavedInvalidationsForType(id
);
931 ASSERT_EQ(2U, list
.GetSize());
932 EXPECT_TRUE(list
.begin()->is_unknown_version());
933 EXPECT_EQ(10, list
.back().version());
936 // Drop the remaining invalidation. Verify an unknown version is all that
938 DropNthInvalidation(id
, 0);
940 SingleObjectInvalidationSet list
= GetSavedInvalidationsForType(id
);
941 ASSERT_EQ(1U, list
.GetSize());
942 EXPECT_TRUE(list
.begin()->is_unknown_version());
945 // Announce that the delegate has recovered from the drop. Verify no
946 // invalidations remain saved.
947 RecoverFromDropEvent(id
);
948 EXPECT_TRUE(GetSavedInvalidationsForType(id
).IsEmpty());
950 RecoverFromDropEvent(id
);
953 // Without readying the client, disable notifications, then enable
954 // them. The listener should still think notifications are disabled.
955 TEST_F(SyncInvalidationListenerTest
, EnableNotificationsNotReady
) {
956 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR
,
957 GetInvalidatorState());
959 DisableNotifications(
960 notifier::TRANSIENT_NOTIFICATION_ERROR
);
962 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR
, GetInvalidatorState());
964 DisableNotifications(notifier::NOTIFICATION_CREDENTIALS_REJECTED
);
966 EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED
, GetInvalidatorState());
968 EnableNotifications();
970 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR
, GetInvalidatorState());
973 // Enable notifications then Ready the invalidation client. The
974 // delegate should then be ready.
975 TEST_F(SyncInvalidationListenerTest
, EnableNotificationsThenReady
) {
976 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR
, GetInvalidatorState());
978 EnableNotifications();
980 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR
, GetInvalidatorState());
982 listener_
.Ready(fake_invalidation_client_
);
984 EXPECT_EQ(INVALIDATIONS_ENABLED
, GetInvalidatorState());
987 // Ready the invalidation client then enable notifications. The
988 // delegate should then be ready.
989 TEST_F(SyncInvalidationListenerTest
, ReadyThenEnableNotifications
) {
990 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR
, GetInvalidatorState());
992 listener_
.Ready(fake_invalidation_client_
);
994 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR
, GetInvalidatorState());
996 EnableNotifications();
998 EXPECT_EQ(INVALIDATIONS_ENABLED
, GetInvalidatorState());
1001 // Enable notifications and ready the client. Then disable
1002 // notifications with an auth error and re-enable notifications. The
1003 // delegate should go into an auth error mode and then back out.
1004 TEST_F(SyncInvalidationListenerTest
, PushClientAuthError
) {
1005 EnableNotifications();
1006 listener_
.Ready(fake_invalidation_client_
);
1008 EXPECT_EQ(INVALIDATIONS_ENABLED
, GetInvalidatorState());
1010 DisableNotifications(
1011 notifier::NOTIFICATION_CREDENTIALS_REJECTED
);
1013 EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED
, GetInvalidatorState());
1015 EnableNotifications();
1017 EXPECT_EQ(INVALIDATIONS_ENABLED
, GetInvalidatorState());
1020 // Enable notifications and ready the client. Then simulate an auth
1021 // error from the invalidation client. Simulate some notification
1022 // events, then re-ready the client. The delegate should go into an
1023 // auth error mode and come out of it only after the client is ready.
1024 TEST_F(SyncInvalidationListenerTest
, InvalidationClientAuthError
) {
1025 EnableNotifications();
1026 listener_
.Ready(fake_invalidation_client_
);
1028 EXPECT_EQ(INVALIDATIONS_ENABLED
, GetInvalidatorState());
1030 listener_
.InformError(
1031 fake_invalidation_client_
,
1032 invalidation::ErrorInfo(
1033 invalidation::ErrorReason::AUTH_FAILURE
,
1034 false /* is_transient */,
1036 invalidation::ErrorContext()));
1038 EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED
, GetInvalidatorState());
1040 DisableNotifications(notifier::TRANSIENT_NOTIFICATION_ERROR
);
1042 EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED
, GetInvalidatorState());
1044 DisableNotifications(notifier::TRANSIENT_NOTIFICATION_ERROR
);
1046 EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED
, GetInvalidatorState());
1048 EnableNotifications();
1050 EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED
, GetInvalidatorState());
1052 listener_
.Ready(fake_invalidation_client_
);
1054 EXPECT_EQ(INVALIDATIONS_ENABLED
, GetInvalidatorState());
1057 // A variant of SyncInvalidationListenerTest that starts with some initial
1058 // state. We make not attempt to abstract away the contents of this state. The
1059 // tests that make use of this harness depend on its implementation details.
1060 class SyncInvalidationListenerTest_WithInitialState
1061 : public SyncInvalidationListenerTest
{
1063 void SetUp() override
{
1064 UnackedInvalidationSet
bm_state(kBookmarksId_
);
1065 UnackedInvalidationSet
ext_state(kExtensionsId_
);
1067 Invalidation bm_unknown
= Invalidation::InitUnknownVersion(kBookmarksId_
);
1068 Invalidation bm_v100
= Invalidation::Init(kBookmarksId_
, 100, "hundred");
1069 bm_state
.Add(bm_unknown
);
1070 bm_state
.Add(bm_v100
);
1072 Invalidation ext_v10
= Invalidation::Init(kExtensionsId_
, 10, "ten");
1073 Invalidation ext_v20
= Invalidation::Init(kExtensionsId_
, 20, "twenty");
1074 ext_state
.Add(ext_v10
);
1075 ext_state
.Add(ext_v20
);
1077 initial_state
.insert(std::make_pair(kBookmarksId_
, bm_state
));
1078 initial_state
.insert(std::make_pair(kExtensionsId_
, ext_state
));
1080 fake_tracker_
.SetSavedInvalidations(initial_state
);
1082 SyncInvalidationListenerTest::SetUp();
1085 UnackedInvalidationsMap initial_state
;
1088 // Verify that saved invalidations are forwarded when handlers register.
1089 TEST_F(SyncInvalidationListenerTest_WithInitialState
,
1090 ReceiveSavedInvalidations
) {
1091 EnableNotifications();
1092 listener_
.Ready(fake_invalidation_client_
);
1094 EXPECT_THAT(initial_state
, test_util::Eq(GetSavedInvalidations()));
1096 ASSERT_EQ(2U, GetInvalidationCount(kBookmarksId_
));
1097 EXPECT_EQ(100, GetVersion(kBookmarksId_
));
1099 ASSERT_EQ(0U, GetInvalidationCount(kExtensionsId_
));
1101 FireInvalidate(kExtensionsId_
, 30, "thirty");
1103 ObjectIdSet ids
= GetRegisteredIds();
1104 ids
.insert(kExtensionsId_
);
1105 listener_
.UpdateRegisteredIds(ids
);
1107 ASSERT_EQ(3U, GetInvalidationCount(kExtensionsId_
));
1108 EXPECT_EQ(30, GetVersion(kExtensionsId_
));
1113 } // namespace syncer