Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / components / invalidation / sync_invalidation_listener_unittest.cc
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.
4
5 #include <cstddef>
6 #include <map>
7 #include <set>
8 #include <string>
9 #include <vector>
10
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"
24
25 namespace syncer {
26
27 namespace {
28
29 using invalidation::AckHandle;
30 using invalidation::ObjectId;
31
32 const char kClientId[] = "client_id";
33 const char kClientInfo[] = "client_info";
34
35 const char kState[] = "state";
36 const char kNewState[] = "new_state";
37
38 const char kPayload1[] = "payload1";
39 const char kPayload2[] = "payload2";
40
41 const int64 kVersion1 = 1LL;
42 const int64 kVersion2 = 2LL;
43
44 const int kChromeSyncSourceId = 1004;
45
46 struct AckHandleLessThan {
47   bool operator()(const AckHandle& lhs, const AckHandle& rhs) const {
48     return lhs.handle_data() < rhs.handle_data();
49   }
50 };
51
52 typedef std::set<AckHandle, AckHandleLessThan> AckHandleSet;
53
54 // Fake invalidation::InvalidationClient implementation that keeps
55 // track of registered IDs and acked handles.
56 class FakeInvalidationClient : public invalidation::InvalidationClient {
57  public:
58   FakeInvalidationClient() : started_(false) {}
59   ~FakeInvalidationClient() override {}
60
61   const ObjectIdSet& GetRegisteredIds() const {
62     return registered_ids_;
63   }
64
65   void ClearAckedHandles() {
66     acked_handles_.clear();
67   }
68
69   bool IsAckedHandle(const AckHandle& ack_handle) const {
70     return (acked_handles_.find(ack_handle) != acked_handles_.end());
71   }
72
73   // invalidation::InvalidationClient implementation.
74
75   void Start() override { started_ = true; }
76
77   void Stop() override { started_ = false; }
78
79   void Register(const ObjectId& object_id) override {
80     if (!started_) {
81       ADD_FAILURE();
82       return;
83     }
84     registered_ids_.insert(object_id);
85   }
86
87   void Register(const invalidation::vector<ObjectId>& object_ids) override {
88     if (!started_) {
89       ADD_FAILURE();
90       return;
91     }
92     registered_ids_.insert(object_ids.begin(), object_ids.end());
93   }
94
95   void Unregister(const ObjectId& object_id) override {
96     if (!started_) {
97       ADD_FAILURE();
98       return;
99     }
100     registered_ids_.erase(object_id);
101   }
102
103   void Unregister(const invalidation::vector<ObjectId>& object_ids) override {
104     if (!started_) {
105       ADD_FAILURE();
106       return;
107     }
108     for (invalidation::vector<ObjectId>::const_iterator
109              it = object_ids.begin(); it != object_ids.end(); ++it) {
110       registered_ids_.erase(*it);
111     }
112   }
113
114   void Acknowledge(const AckHandle& ack_handle) override {
115     if (!started_) {
116       ADD_FAILURE();
117       return;
118     }
119     acked_handles_.insert(ack_handle);
120   }
121
122  private:
123   bool started_;
124   ObjectIdSet registered_ids_;
125   AckHandleSet acked_handles_;
126 };
127
128 // Fake delegate tkat keeps track of invalidation counts, payloads,
129 // and state.
130 class FakeDelegate : public SyncInvalidationListener::Delegate {
131  public:
132   explicit FakeDelegate(SyncInvalidationListener* listener)
133       : state_(TRANSIENT_INVALIDATION_ERROR) {}
134   ~FakeDelegate() override {}
135
136   size_t GetInvalidationCount(const ObjectId& id) const {
137     Map::const_iterator it = invalidations_.find(id);
138     if (it == invalidations_.end()) {
139       return 0;
140     } else {
141       return it->second.size();
142     }
143   }
144
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);
149       return 0;
150     } else {
151       return it->second.back().version();
152     }
153   }
154
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);
159       return 0;
160     } else {
161       return it->second.back().payload();
162     }
163   }
164
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);
169       return false;
170     } else {
171       return it->second.back().is_unknown_version();
172     }
173   }
174
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);
179       return false;
180     } else {
181       return it->second.front().is_unknown_version();
182     }
183   }
184
185   InvalidatorState GetInvalidatorState() const {
186     return state_;
187   }
188
189   void AcknowledgeNthInvalidation(const ObjectId& id, size_t n) {
190     List& list = invalidations_[id];
191     List::iterator it = list.begin() + n;
192     it->Acknowledge();
193   }
194
195   void AcknowledgeAll(const ObjectId& id) {
196     List& list = invalidations_[id];
197     for (List::iterator it = list.begin(); it != list.end(); ++it) {
198       it->Acknowledge();
199     }
200   }
201
202   void DropNthInvalidation(const ObjectId& id, size_t n) {
203     List& list = invalidations_[id];
204     List::iterator it = list.begin() + n;
205     it->Drop();
206     dropped_invalidations_map_.erase(id);
207     dropped_invalidations_map_.insert(std::make_pair(id, *it));
208   }
209
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);
215     }
216   }
217
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());
226     }
227   }
228
229   void OnInvalidatorStateChange(InvalidatorState state) override {
230     state_ = state;
231   }
232
233  private:
234   typedef std::vector<Invalidation> List;
235   typedef std::map<ObjectId, List, ObjectIdLessThan> Map;
236   typedef std::map<ObjectId, Invalidation, ObjectIdLessThan> DropMap;
237
238   Map invalidations_;
239   InvalidatorState state_;
240   DropMap dropped_invalidations_map_;
241 };
242
243 invalidation::InvalidationClient* CreateFakeInvalidationClient(
244     FakeInvalidationClient** fake_invalidation_client,
245     invalidation::SystemResources* resources,
246     int client_type,
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;
252 }
253
254 class SyncInvalidationListenerTest : public testing::Test {
255  protected:
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_) {}
266
267   void SetUp() override {
268     StartClient();
269
270     registered_ids_.insert(kBookmarksId_);
271     registered_ids_.insert(kPreferencesId_);
272     listener_.UpdateRegisteredIds(registered_ids_);
273   }
274
275   void TearDown() override { StopClient(); }
276
277   // Restart client without re-registering IDs.
278   void RestartClient() {
279     StopClient();
280     StartClient();
281   }
282
283   void StartClient() {
284     fake_invalidation_client_ = NULL;
285     listener_.Start(
286         base::Bind(&CreateFakeInvalidationClient, &fake_invalidation_client_),
287         kClientId,
288         kClientInfo,
289         kState,
290         fake_tracker_.GetSavedInvalidations(),
291         fake_tracker_.AsWeakPtr(),
292         base::MessageLoopProxy::current(),
293         &fake_delegate_);
294     DCHECK(fake_invalidation_client_);
295   }
296
297   void StopClient() {
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();
307   }
308
309   size_t GetInvalidationCount(const ObjectId& id) const {
310     return fake_delegate_.GetInvalidationCount(id);
311   }
312
313   int64 GetVersion(const ObjectId& id) const {
314     return fake_delegate_.GetVersion(id);
315   }
316
317   std::string GetPayload(const ObjectId& id) const {
318     return fake_delegate_.GetPayload(id);
319   }
320
321   bool IsUnknownVersion(const ObjectId& id) const {
322     return fake_delegate_.IsUnknownVersion(id);
323   }
324
325   bool StartsWithUnknownVersion(const ObjectId& id) const {
326     return fake_delegate_.StartsWithUnknownVersion(id);
327   }
328
329   void AcknowledgeNthInvalidation(const ObjectId& id, size_t n) {
330     fake_delegate_.AcknowledgeNthInvalidation(id, n);
331   }
332
333   void DropNthInvalidation(const ObjectId& id, size_t n) {
334     return fake_delegate_.DropNthInvalidation(id, n);
335   }
336
337   void RecoverFromDropEvent(const ObjectId& id) {
338     return fake_delegate_.RecoverFromDropEvent(id);
339   }
340
341   void AcknowledgeAll(const ObjectId& id) {
342     fake_delegate_.AcknowledgeAll(id);
343   }
344
345   InvalidatorState GetInvalidatorState() const {
346     return fake_delegate_.GetInvalidatorState();
347   }
348
349   std::string GetInvalidatorClientId() const {
350     return fake_tracker_.GetInvalidatorClientId();
351   }
352
353   std::string GetBootstrapData() const {
354     return fake_tracker_.GetBootstrapData();
355   }
356
357   UnackedInvalidationsMap GetSavedInvalidations() {
358     // Allow any queued writes to go through first.
359     FlushPendingWrites();
360     return fake_tracker_.GetSavedInvalidations();
361   }
362
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();
370     }
371     ObjectIdInvalidationMap map;
372     it->second.ExportInvalidations(
373         base::WeakPtr<AckHandler>(),
374         scoped_refptr<base::SingleThreadTaskRunner>(),
375         &map);
376     if (map.Empty()) {
377       return SingleObjectInvalidationSet();
378     } else  {
379       return map.ForObject(id);
380     }
381   }
382
383   ObjectIdSet GetRegisteredIds() const {
384     return fake_invalidation_client_->GetRegisteredIds();
385   }
386
387   // |payload| can be NULL.
388   void FireInvalidate(const ObjectId& object_id,
389                       int64 version, const char* payload) {
390     invalidation::Invalidation inv;
391     if (payload) {
392       inv = invalidation::Invalidation(object_id, version, payload);
393     } else {
394       inv = invalidation::Invalidation(object_id, version);
395     }
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));
400   }
401
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_,
407                                        object_id,
408                                        ack_handle);
409     EXPECT_TRUE(fake_invalidation_client_->IsAckedHandle(ack_handle));
410   }
411
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));
417   }
418
419   void WriteState(const std::string& new_state) {
420     listener_.WriteState(new_state);
421
422     // Pump message loop to trigger
423     // InvalidationStateTracker::WriteState().
424     FlushPendingWrites();
425   }
426
427   void FlushPendingWrites() {
428     message_loop_.RunUntilIdle();
429   }
430
431   void EnableNotifications() {
432     fake_push_client_->EnableNotifications();
433   }
434
435   void DisableNotifications(notifier::NotificationsDisabledReason reason) {
436     fake_push_client_->DisableNotifications(reason);
437   }
438
439   const ObjectId kBookmarksId_;
440   const ObjectId kPreferencesId_;
441   const ObjectId kExtensionsId_;
442   const ObjectId kAppsId_;
443
444   ObjectIdSet registered_ids_;
445
446  private:
447   base::MessageLoop message_loop_;
448   notifier::FakePushClient* const fake_push_client_;
449
450  protected:
451   // A derrived test needs direct access to this.
452   FakeInvalidationStateTracker fake_tracker_;
453
454   // Tests need to access these directly.
455   FakeInvalidationClient* fake_invalidation_client_;
456   SyncInvalidationListener listener_;
457
458  private:
459   FakeDelegate fake_delegate_;
460 };
461
462 // Write a new state to the client.  It should propagate to the
463 // tracker.
464 TEST_F(SyncInvalidationListenerTest, WriteState) {
465   WriteState(kNewState);
466
467   EXPECT_EQ(kNewState, GetBootstrapData());
468 }
469
470 // Invalidation tests.
471
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_;
476
477   FireInvalidate(id, kVersion1, NULL);
478
479   ASSERT_EQ(1U, GetInvalidationCount(id));
480   ASSERT_FALSE(IsUnknownVersion(id));
481   EXPECT_EQ(kVersion1, GetVersion(id));
482   EXPECT_EQ("", GetPayload(id));
483 }
484
485 // Fire an invalidation with an empty payload.  It should be
486 // processed, the payload should remain empty, and the version should
487 // be updated.
488 TEST_F(SyncInvalidationListenerTest, InvalidateEmptyPayload) {
489   const ObjectId& id = kBookmarksId_;
490
491   FireInvalidate(id, kVersion1, "");
492
493   ASSERT_EQ(1U, GetInvalidationCount(id));
494   ASSERT_FALSE(IsUnknownVersion(id));
495   EXPECT_EQ(kVersion1, GetVersion(id));
496   EXPECT_EQ("", GetPayload(id));
497 }
498
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_;
503
504   FireInvalidate(id, kVersion1, kPayload1);
505
506   ASSERT_EQ(1U, GetInvalidationCount(id));
507   ASSERT_FALSE(IsUnknownVersion(id));
508   EXPECT_EQ(kVersion1, GetVersion(id));
509   EXPECT_EQ(kPayload1, GetPayload(id));
510 }
511
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);
519   }
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));
524 }
525
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;
531   ObjectIdSet ids;
532   ids.insert(id);
533
534   EXPECT_EQ(0U, GetInvalidationCount(id));
535
536   FireInvalidate(id, kVersion1, kPayload1);
537
538   ASSERT_EQ(0U, GetInvalidationCount(id));
539
540   EnableNotifications();
541   listener_.Ready(fake_invalidation_client_);
542   listener_.UpdateRegisteredIds(ids);
543
544   ASSERT_EQ(1U, GetInvalidationCount(id));
545   ASSERT_FALSE(IsUnknownVersion(id));
546   EXPECT_EQ(kVersion1, GetVersion(id));
547   EXPECT_EQ(kPayload1, GetPayload(id));
548 }
549
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;
557   ObjectIdSet ids;
558   ids.insert(id);
559
560   EXPECT_EQ(0U, GetInvalidationCount(id));
561
562   int64 initial_version = kVersion1;
563   for (int64 i = initial_version; i < initial_version + kRepeatCount; ++i) {
564     FireInvalidate(id, i, kPayload1);
565   }
566
567   EnableNotifications();
568   listener_.Ready(fake_invalidation_client_);
569   listener_.UpdateRegisteredIds(ids);
570
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));
577 }
578
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_;
583
584   FireInvalidate(id, kVersion2, kPayload2);
585
586   ASSERT_EQ(1U, GetInvalidationCount(id));
587   ASSERT_FALSE(IsUnknownVersion(id));
588   EXPECT_EQ(kVersion2, GetVersion(id));
589   EXPECT_EQ(kPayload2, GetPayload(id));
590
591   FireInvalidate(id, kVersion1, kPayload1);
592
593   ASSERT_EQ(2U, GetInvalidationCount(id));
594   ASSERT_FALSE(IsUnknownVersion(id));
595
596   EXPECT_EQ(kVersion1, GetVersion(id));
597   EXPECT_EQ(kPayload1, GetPayload(id));
598 }
599
600 // Fire an invalidation with an unknown version.
601 TEST_F(SyncInvalidationListenerTest, InvalidateUnknownVersion) {
602   const ObjectId& id = kBookmarksId_;
603
604   FireInvalidateUnknownVersion(id);
605
606   ASSERT_EQ(1U, GetInvalidationCount(id));
607   EXPECT_TRUE(IsUnknownVersion(id));
608 }
609
610 // Fire an invalidation for all enabled IDs.
611 TEST_F(SyncInvalidationListenerTest, InvalidateAll) {
612   FireInvalidateAll();
613
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));
618   }
619 }
620
621 // Test a simple scenario for multiple IDs.
622 TEST_F(SyncInvalidationListenerTest, InvalidateMultipleIds) {
623   FireInvalidate(kBookmarksId_, 3, NULL);
624
625   ASSERT_EQ(1U, GetInvalidationCount(kBookmarksId_));
626   ASSERT_FALSE(IsUnknownVersion(kBookmarksId_));
627   EXPECT_EQ(3, GetVersion(kBookmarksId_));
628   EXPECT_EQ("", GetPayload(kBookmarksId_));
629
630   // kExtensionId is not registered, so the invalidation should not get through.
631   FireInvalidate(kExtensionsId_, 2, NULL);
632   ASSERT_EQ(0U, GetInvalidationCount(kExtensionsId_));
633 }
634
635 // Registration tests.
636
637 // With IDs already registered, enable notifications then ready the
638 // client.  The IDs should be registered only after the client is
639 // readied.
640 TEST_F(SyncInvalidationListenerTest, RegisterEnableReady) {
641   EXPECT_TRUE(GetRegisteredIds().empty());
642
643   EnableNotifications();
644
645   EXPECT_TRUE(GetRegisteredIds().empty());
646
647   listener_.Ready(fake_invalidation_client_);
648
649   EXPECT_EQ(registered_ids_, GetRegisteredIds());
650 }
651
652 // With IDs already registered, ready the client then enable
653 // notifications.  The IDs should be registered after the client is
654 // readied.
655 TEST_F(SyncInvalidationListenerTest, RegisterReadyEnable) {
656   EXPECT_TRUE(GetRegisteredIds().empty());
657
658   listener_.Ready(fake_invalidation_client_);
659
660   EXPECT_EQ(registered_ids_, GetRegisteredIds());
661
662   EnableNotifications();
663
664   EXPECT_EQ(registered_ids_, GetRegisteredIds());
665 }
666
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());
672
673   EXPECT_TRUE(GetRegisteredIds().empty());
674
675   EnableNotifications();
676
677   EXPECT_TRUE(GetRegisteredIds().empty());
678
679   listener_.UpdateRegisteredIds(registered_ids_);
680
681   EXPECT_TRUE(GetRegisteredIds().empty());
682
683   listener_.Ready(fake_invalidation_client_);
684
685   EXPECT_EQ(registered_ids_, GetRegisteredIds());
686 }
687
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());
693
694   EXPECT_TRUE(GetRegisteredIds().empty());
695
696   EnableNotifications();
697
698   EXPECT_TRUE(GetRegisteredIds().empty());
699
700   listener_.Ready(fake_invalidation_client_);
701
702   EXPECT_TRUE(GetRegisteredIds().empty());
703
704   listener_.UpdateRegisteredIds(registered_ids_);
705
706   EXPECT_EQ(registered_ids_, GetRegisteredIds());
707 }
708
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());
714
715   EXPECT_TRUE(GetRegisteredIds().empty());
716
717   EnableNotifications();
718
719   EXPECT_TRUE(GetRegisteredIds().empty());
720
721   listener_.Ready(fake_invalidation_client_);
722
723   EXPECT_TRUE(GetRegisteredIds().empty());
724
725   listener_.UpdateRegisteredIds(registered_ids_);
726
727   EXPECT_EQ(registered_ids_, GetRegisteredIds());
728 }
729
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.
733 //
734 // This test is important: see http://crbug.com/139424.
735 TEST_F(SyncInvalidationListenerTest, ReadyRegisterEnable) {
736   listener_.UpdateRegisteredIds(ObjectIdSet());
737
738   EXPECT_TRUE(GetRegisteredIds().empty());
739
740   listener_.Ready(fake_invalidation_client_);
741
742   EXPECT_TRUE(GetRegisteredIds().empty());
743
744   listener_.UpdateRegisteredIds(registered_ids_);
745
746   EXPECT_EQ(registered_ids_, GetRegisteredIds());
747
748   EnableNotifications();
749
750   EXPECT_EQ(registered_ids_, GetRegisteredIds());
751 }
752
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());
757
758   listener_.Ready(fake_invalidation_client_);
759
760   EXPECT_EQ(registered_ids_, GetRegisteredIds());
761
762   RestartClient();
763
764   EXPECT_TRUE(GetRegisteredIds().empty());
765
766   listener_.Ready(fake_invalidation_client_);
767
768   EXPECT_EQ(registered_ids_, GetRegisteredIds());
769 }
770
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_);
776
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());
783
784   EXPECT_TRUE(ContainsKey(GetSavedInvalidations(), id));
785   EXPECT_TRUE(ContainsKey(GetSavedInvalidations(), kPreferencesId_));
786
787   ObjectIdSet ids;
788   ids.insert(id);
789   listener_.UpdateRegisteredIds(ids);
790   EXPECT_EQ(1U, GetSavedInvalidations().size());
791   EXPECT_TRUE(ContainsKey(GetSavedInvalidations(), id));
792 }
793
794 TEST_F(SyncInvalidationListenerTest, DuplicateInvaldiations_Simple) {
795   const ObjectId& id = kBookmarksId_;
796   listener_.Ready(fake_invalidation_client_);
797
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");
803
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());
809   it++;
810   EXPECT_EQ(2, it->version());
811   it++;
812   EXPECT_EQ(3, it->version());
813 }
814
815 TEST_F(SyncInvalidationListenerTest, DuplicateInvalidations_NearBufferLimit) {
816   const size_t kPairsToSend = UnackedInvalidationSet::kMaxBufferedInvalidations;
817   const ObjectId& id = kBookmarksId_;
818   listener_.Ready(fake_invalidation_client_);
819
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");
825   }
826
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());
831
832   // Expect that all invalidations (including duplicates) were emitted.
833   EXPECT_EQ(kPairsToSend*2, GetInvalidationCount(id));
834
835   // Acknowledge all invalidations to clear the internal state.
836   AcknowledgeAll(id);
837   EXPECT_TRUE(GetSavedInvalidationsForType(id).IsEmpty());
838 }
839
840 TEST_F(SyncInvalidationListenerTest, DuplicateInvalidations_UnknownVersion) {
841   const ObjectId& id = kBookmarksId_;
842   listener_.Ready(fake_invalidation_client_);
843
844   FireInvalidateUnknownVersion(id);
845   FireInvalidateUnknownVersion(id);
846
847   {
848     SingleObjectInvalidationSet list = GetSavedInvalidationsForType(id);
849     EXPECT_EQ(1U, list.GetSize());
850   }
851
852   // Acknowledge the second.  There should be no effect on the stored list.
853   ASSERT_EQ(2U, GetInvalidationCount(id));
854   AcknowledgeNthInvalidation(id, 1);
855   {
856     SingleObjectInvalidationSet list = GetSavedInvalidationsForType(id);
857     EXPECT_EQ(1U, list.GetSize());
858   }
859
860   // Acknowledge the first.  This should remove the invalidation from the list.
861   ASSERT_EQ(2U, GetInvalidationCount(id));
862   AcknowledgeNthInvalidation(id, 0);
863   {
864     SingleObjectInvalidationSet list = GetSavedInvalidationsForType(id);
865     EXPECT_EQ(0U, list.GetSize());
866   }
867 }
868
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_);
873
874   EXPECT_TRUE(GetSavedInvalidations().empty());
875   FireInvalidate(id, 10, "hello");
876   FireInvalidate(id, 20, "world");
877   FireInvalidateUnknownVersion(id);
878
879   // Expect that all three invalidations have been saved to permanent storage.
880   {
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());
885   }
886
887   // Acknowledge the second sent invaldiation (version 20) and verify it was
888   // removed from storage.
889   AcknowledgeNthInvalidation(id, 1);
890   {
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());
895   }
896
897   // Acknowledge the last sent invalidation (unknown version) and verify it was
898   // removed from storage.
899   AcknowledgeNthInvalidation(id, 2);
900   {
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());
905   }
906 }
907
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_);
912
913   EXPECT_TRUE(GetSavedInvalidations().empty());
914   FireInvalidate(id, 10, "hello");
915   FireInvalidate(id, 20, "world");
916   FireInvalidateUnknownVersion(id);
917
918   // Expect that all three invalidations have been saved to permanent storage.
919   {
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());
924   }
925
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);
929   {
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());
934   }
935
936   // Drop the remaining invalidation.  Verify an unknown version is all that
937   // remains.
938   DropNthInvalidation(id, 0);
939   {
940     SingleObjectInvalidationSet list = GetSavedInvalidationsForType(id);
941     ASSERT_EQ(1U, list.GetSize());
942     EXPECT_TRUE(list.begin()->is_unknown_version());
943   }
944
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());
949
950   RecoverFromDropEvent(id);
951 }
952
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());
958
959   DisableNotifications(
960       notifier::TRANSIENT_NOTIFICATION_ERROR);
961
962   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, GetInvalidatorState());
963
964   DisableNotifications(notifier::NOTIFICATION_CREDENTIALS_REJECTED);
965
966   EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED, GetInvalidatorState());
967
968   EnableNotifications();
969
970   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, GetInvalidatorState());
971 }
972
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());
977
978   EnableNotifications();
979
980   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, GetInvalidatorState());
981
982   listener_.Ready(fake_invalidation_client_);
983
984   EXPECT_EQ(INVALIDATIONS_ENABLED, GetInvalidatorState());
985 }
986
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());
991
992   listener_.Ready(fake_invalidation_client_);
993
994   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, GetInvalidatorState());
995
996   EnableNotifications();
997
998   EXPECT_EQ(INVALIDATIONS_ENABLED, GetInvalidatorState());
999 }
1000
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_);
1007
1008   EXPECT_EQ(INVALIDATIONS_ENABLED, GetInvalidatorState());
1009
1010   DisableNotifications(
1011       notifier::NOTIFICATION_CREDENTIALS_REJECTED);
1012
1013   EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED, GetInvalidatorState());
1014
1015   EnableNotifications();
1016
1017   EXPECT_EQ(INVALIDATIONS_ENABLED, GetInvalidatorState());
1018 }
1019
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_);
1027
1028   EXPECT_EQ(INVALIDATIONS_ENABLED, GetInvalidatorState());
1029
1030   listener_.InformError(
1031       fake_invalidation_client_,
1032       invalidation::ErrorInfo(
1033           invalidation::ErrorReason::AUTH_FAILURE,
1034           false /* is_transient */,
1035           "auth error",
1036           invalidation::ErrorContext()));
1037
1038   EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED, GetInvalidatorState());
1039
1040   DisableNotifications(notifier::TRANSIENT_NOTIFICATION_ERROR);
1041
1042   EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED, GetInvalidatorState());
1043
1044   DisableNotifications(notifier::TRANSIENT_NOTIFICATION_ERROR);
1045
1046   EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED, GetInvalidatorState());
1047
1048   EnableNotifications();
1049
1050   EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED, GetInvalidatorState());
1051
1052   listener_.Ready(fake_invalidation_client_);
1053
1054   EXPECT_EQ(INVALIDATIONS_ENABLED, GetInvalidatorState());
1055 }
1056
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 {
1062  public:
1063   void SetUp() override {
1064     UnackedInvalidationSet bm_state(kBookmarksId_);
1065     UnackedInvalidationSet ext_state(kExtensionsId_);
1066
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);
1071
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);
1076
1077     initial_state.insert(std::make_pair(kBookmarksId_, bm_state));
1078     initial_state.insert(std::make_pair(kExtensionsId_, ext_state));
1079
1080     fake_tracker_.SetSavedInvalidations(initial_state);
1081
1082     SyncInvalidationListenerTest::SetUp();
1083   }
1084
1085   UnackedInvalidationsMap initial_state;
1086 };
1087
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_);
1093
1094   EXPECT_THAT(initial_state, test_util::Eq(GetSavedInvalidations()));
1095
1096   ASSERT_EQ(2U, GetInvalidationCount(kBookmarksId_));
1097   EXPECT_EQ(100, GetVersion(kBookmarksId_));
1098
1099   ASSERT_EQ(0U, GetInvalidationCount(kExtensionsId_));
1100
1101   FireInvalidate(kExtensionsId_, 30, "thirty");
1102
1103   ObjectIdSet ids = GetRegisteredIds();
1104   ids.insert(kExtensionsId_);
1105   listener_.UpdateRegisteredIds(ids);
1106
1107   ASSERT_EQ(3U, GetInvalidationCount(kExtensionsId_));
1108   EXPECT_EQ(30, GetVersion(kExtensionsId_));
1109 }
1110
1111 }  // namespace
1112
1113 }  // namespace syncer