• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // This class defines tests that implementations of Invalidator should pass in
6 // order to be conformant.  Here's how you use it to test your implementation.
7 //
8 // Say your class is called MyInvalidator.  Then you need to define a class
9 // called MyInvalidatorTestDelegate in my_sync_notifier_unittest.cc like this:
10 //
11 //   class MyInvalidatorTestDelegate {
12 //    public:
13 //     MyInvalidatorTestDelegate() ...
14 //
15 //     ~MyInvalidatorTestDelegate() {
16 //       // DestroyInvalidator() may not be explicitly called by tests.
17 //       DestroyInvalidator();
18 //     }
19 //
20 //     // Create the Invalidator implementation with the given parameters.
21 //     void CreateInvalidator(
22 //         const std::string& initial_state,
23 //         const base::WeakPtr<InvalidationStateTracker>&
24 //             invalidation_state_tracker) {
25 //       ...
26 //     }
27 //
28 //     // Should return the Invalidator implementation.  Only called after
29 //     // CreateInvalidator and before DestroyInvalidator.
30 //     MyInvalidator* GetInvalidator() {
31 //       ...
32 //     }
33 //
34 //     // Destroy the Invalidator implementation.
35 //     void DestroyInvalidator() {
36 //       ...
37 //     }
38 //
39 //     // Called after a call to SetUniqueId(), or UpdateCredentials() on the
40 //     // Invalidator implementation.  Should block until the effects of the
41 //     // call are visible on the current thread.
42 //     void WaitForInvalidator() {
43 //       ...
44 //     }
45 //
46 //     // The Trigger* functions below should block until the effects of
47 //     // the call are visible on the current thread.
48 //
49 //     // Should cause OnInvalidatorStateChange() to be called on all
50 //     // observers of the Invalidator implementation with the given
51 //     // parameters.
52 //     void TriggerOnInvalidatorStateChange(InvalidatorState state) {
53 //       ...
54 //     }
55 //
56 //     // Should cause OnIncomingInvalidation() to be called on all
57 //     // observers of the Invalidator implementation with the given
58 //     // parameters.
59 //     void TriggerOnIncomingInvalidation(
60 //         const ObjectIdInvalidationMap& invalidation_map) {
61 //       ...
62 //     }
63 //   };
64 //
65 // The InvalidatorTest test harness will have a member variable of
66 // this delegate type and will call its functions in the various
67 // tests.
68 //
69 // Then you simply #include this file as well as gtest.h and add the
70 // following statement to my_sync_notifier_unittest.cc:
71 //
72 //   INSTANTIATE_TYPED_TEST_CASE_P(
73 //       MyInvalidator, InvalidatorTest, MyInvalidatorTestDelegate);
74 //
75 // Easy!
76 
77 #ifndef COMPONENTS_INVALIDATION_INVALIDATOR_TEST_TEMPLATE_H_
78 #define COMPONENTS_INVALIDATION_INVALIDATOR_TEST_TEMPLATE_H_
79 
80 #include "base/basictypes.h"
81 #include "base/compiler_specific.h"
82 #include "components/invalidation/fake_invalidation_handler.h"
83 #include "components/invalidation/fake_invalidation_state_tracker.h"
84 #include "components/invalidation/invalidator.h"
85 #include "components/invalidation/object_id_invalidation_map_test_util.h"
86 #include "google/cacheinvalidation/include/types.h"
87 #include "google/cacheinvalidation/types.pb.h"
88 #include "testing/gtest/include/gtest/gtest.h"
89 
90 namespace syncer {
91 
92 template <typename InvalidatorTestDelegate>
93 class InvalidatorTest : public testing::Test {
94  protected:
InvalidatorTest()95   InvalidatorTest()
96       : id1(ipc::invalidation::ObjectSource::TEST, "a"),
97         id2(ipc::invalidation::ObjectSource::TEST, "b"),
98         id3(ipc::invalidation::ObjectSource::TEST, "c"),
99         id4(ipc::invalidation::ObjectSource::TEST, "d") {
100   }
101 
CreateAndInitializeInvalidator()102   Invalidator* CreateAndInitializeInvalidator() {
103     this->delegate_.CreateInvalidator("fake_invalidator_client_id",
104                                       "fake_initial_state",
105                                       this->fake_tracker_.AsWeakPtr());
106     Invalidator* const invalidator = this->delegate_.GetInvalidator();
107 
108     this->delegate_.WaitForInvalidator();
109     invalidator->UpdateCredentials("foo@bar.com", "fake_token");
110     this->delegate_.WaitForInvalidator();
111 
112     return invalidator;
113   }
114 
115   FakeInvalidationStateTracker fake_tracker_;
116   InvalidatorTestDelegate delegate_;
117 
118   const invalidation::ObjectId id1;
119   const invalidation::ObjectId id2;
120   const invalidation::ObjectId id3;
121   const invalidation::ObjectId id4;
122 };
123 
124 TYPED_TEST_CASE_P(InvalidatorTest);
125 
126 // Initialize the invalidator, register a handler, register some IDs for that
127 // handler, and then unregister the handler, dispatching invalidations in
128 // between.  The handler should only see invalidations when its registered and
129 // its IDs are registered.
TYPED_TEST_P(InvalidatorTest,Basic)130 TYPED_TEST_P(InvalidatorTest, Basic) {
131   Invalidator* const invalidator = this->CreateAndInitializeInvalidator();
132 
133   FakeInvalidationHandler handler;
134 
135   invalidator->RegisterHandler(&handler);
136 
137   ObjectIdInvalidationMap invalidation_map;
138   invalidation_map.Insert(Invalidation::Init(this->id1, 1, "1"));
139   invalidation_map.Insert(Invalidation::Init(this->id2, 2, "2"));
140   invalidation_map.Insert(Invalidation::Init(this->id3, 3, "3"));
141 
142   // Should be ignored since no IDs are registered to |handler|.
143   this->delegate_.TriggerOnIncomingInvalidation(invalidation_map);
144   EXPECT_EQ(0, handler.GetInvalidationCount());
145 
146   ObjectIdSet ids;
147   ids.insert(this->id1);
148   ids.insert(this->id2);
149   invalidator->UpdateRegisteredIds(&handler, ids);
150 
151   this->delegate_.TriggerOnInvalidatorStateChange(INVALIDATIONS_ENABLED);
152   EXPECT_EQ(INVALIDATIONS_ENABLED, handler.GetInvalidatorState());
153 
154   ObjectIdInvalidationMap expected_invalidations;
155   expected_invalidations.Insert(Invalidation::Init(this->id1, 1, "1"));
156   expected_invalidations.Insert(Invalidation::Init(this->id2, 2, "2"));
157 
158   this->delegate_.TriggerOnIncomingInvalidation(invalidation_map);
159   EXPECT_EQ(1, handler.GetInvalidationCount());
160   EXPECT_THAT(expected_invalidations, Eq(handler.GetLastInvalidationMap()));
161 
162   ids.erase(this->id1);
163   ids.insert(this->id3);
164   invalidator->UpdateRegisteredIds(&handler, ids);
165 
166   expected_invalidations = ObjectIdInvalidationMap();
167   expected_invalidations.Insert(Invalidation::Init(this->id2, 2, "2"));
168   expected_invalidations.Insert(Invalidation::Init(this->id3, 3, "3"));
169 
170   // Removed object IDs should not be notified, newly-added ones should.
171   this->delegate_.TriggerOnIncomingInvalidation(invalidation_map);
172   EXPECT_EQ(2, handler.GetInvalidationCount());
173   EXPECT_THAT(expected_invalidations, Eq(handler.GetLastInvalidationMap()));
174 
175   this->delegate_.TriggerOnInvalidatorStateChange(TRANSIENT_INVALIDATION_ERROR);
176   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR,
177             handler.GetInvalidatorState());
178 
179   this->delegate_.TriggerOnInvalidatorStateChange(
180       INVALIDATION_CREDENTIALS_REJECTED);
181   EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED,
182             handler.GetInvalidatorState());
183 
184   invalidator->UnregisterHandler(&handler);
185 
186   // Should be ignored since |handler| isn't registered anymore.
187   this->delegate_.TriggerOnIncomingInvalidation(invalidation_map);
188   EXPECT_EQ(2, handler.GetInvalidationCount());
189 }
190 
191 // Register handlers and some IDs for those handlers, register a handler with
192 // no IDs, and register a handler with some IDs but unregister it.  Then,
193 // dispatch some invalidations and invalidations.  Handlers that are registered
194 // should get invalidations, and the ones that have registered IDs should
195 // receive invalidations for those IDs.
TYPED_TEST_P(InvalidatorTest,MultipleHandlers)196 TYPED_TEST_P(InvalidatorTest, MultipleHandlers) {
197   Invalidator* const invalidator = this->CreateAndInitializeInvalidator();
198 
199   FakeInvalidationHandler handler1;
200   FakeInvalidationHandler handler2;
201   FakeInvalidationHandler handler3;
202   FakeInvalidationHandler handler4;
203 
204   invalidator->RegisterHandler(&handler1);
205   invalidator->RegisterHandler(&handler2);
206   invalidator->RegisterHandler(&handler3);
207   invalidator->RegisterHandler(&handler4);
208 
209   {
210     ObjectIdSet ids;
211     ids.insert(this->id1);
212     ids.insert(this->id2);
213     invalidator->UpdateRegisteredIds(&handler1, ids);
214   }
215 
216   {
217     ObjectIdSet ids;
218     ids.insert(this->id3);
219     invalidator->UpdateRegisteredIds(&handler2, ids);
220   }
221 
222   // Don't register any IDs for handler3.
223 
224   {
225     ObjectIdSet ids;
226     ids.insert(this->id4);
227     invalidator->UpdateRegisteredIds(&handler4, ids);
228   }
229 
230   invalidator->UnregisterHandler(&handler4);
231 
232   this->delegate_.TriggerOnInvalidatorStateChange(INVALIDATIONS_ENABLED);
233   EXPECT_EQ(INVALIDATIONS_ENABLED, handler1.GetInvalidatorState());
234   EXPECT_EQ(INVALIDATIONS_ENABLED, handler2.GetInvalidatorState());
235   EXPECT_EQ(INVALIDATIONS_ENABLED, handler3.GetInvalidatorState());
236   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler4.GetInvalidatorState());
237 
238   {
239     ObjectIdInvalidationMap invalidation_map;
240     invalidation_map.Insert(Invalidation::Init(this->id1, 1, "1"));
241     invalidation_map.Insert(Invalidation::Init(this->id2, 2, "2"));
242     invalidation_map.Insert(Invalidation::Init(this->id3, 3, "3"));
243     invalidation_map.Insert(Invalidation::Init(this->id4, 4, "4"));
244 
245     this->delegate_.TriggerOnIncomingInvalidation(invalidation_map);
246 
247     ObjectIdInvalidationMap expected_invalidations;
248     expected_invalidations.Insert(Invalidation::Init(this->id1, 1, "1"));
249     expected_invalidations.Insert(Invalidation::Init(this->id2, 2, "2"));
250 
251     EXPECT_EQ(1, handler1.GetInvalidationCount());
252     EXPECT_THAT(expected_invalidations, Eq(handler1.GetLastInvalidationMap()));
253 
254     expected_invalidations = ObjectIdInvalidationMap();
255     expected_invalidations.Insert(Invalidation::Init(this->id3, 3, "3"));
256 
257     EXPECT_EQ(1, handler2.GetInvalidationCount());
258     EXPECT_THAT(expected_invalidations, Eq(handler2.GetLastInvalidationMap()));
259 
260     EXPECT_EQ(0, handler3.GetInvalidationCount());
261     EXPECT_EQ(0, handler4.GetInvalidationCount());
262   }
263 
264   this->delegate_.TriggerOnInvalidatorStateChange(TRANSIENT_INVALIDATION_ERROR);
265   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler1.GetInvalidatorState());
266   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler2.GetInvalidatorState());
267   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler3.GetInvalidatorState());
268   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler4.GetInvalidatorState());
269 
270   invalidator->UnregisterHandler(&handler3);
271   invalidator->UnregisterHandler(&handler2);
272   invalidator->UnregisterHandler(&handler1);
273 }
274 
275 // Make sure that passing an empty set to UpdateRegisteredIds clears the
276 // corresponding entries for the handler.
TYPED_TEST_P(InvalidatorTest,EmptySetUnregisters)277 TYPED_TEST_P(InvalidatorTest, EmptySetUnregisters) {
278   Invalidator* const invalidator = this->CreateAndInitializeInvalidator();
279 
280   FakeInvalidationHandler handler1;
281 
282   // Control observer.
283   FakeInvalidationHandler handler2;
284 
285   invalidator->RegisterHandler(&handler1);
286   invalidator->RegisterHandler(&handler2);
287 
288   {
289     ObjectIdSet ids;
290     ids.insert(this->id1);
291     ids.insert(this->id2);
292     invalidator->UpdateRegisteredIds(&handler1, ids);
293   }
294 
295   {
296     ObjectIdSet ids;
297     ids.insert(this->id3);
298     invalidator->UpdateRegisteredIds(&handler2, ids);
299   }
300 
301   // Unregister the IDs for the first observer. It should not receive any
302   // further invalidations.
303   invalidator->UpdateRegisteredIds(&handler1, ObjectIdSet());
304 
305   this->delegate_.TriggerOnInvalidatorStateChange(INVALIDATIONS_ENABLED);
306   EXPECT_EQ(INVALIDATIONS_ENABLED, handler1.GetInvalidatorState());
307   EXPECT_EQ(INVALIDATIONS_ENABLED, handler2.GetInvalidatorState());
308 
309   {
310     ObjectIdInvalidationMap invalidation_map;
311     invalidation_map.Insert(Invalidation::Init(this->id1, 1, "1"));
312     invalidation_map.Insert(Invalidation::Init(this->id2, 2, "2"));
313     invalidation_map.Insert(Invalidation::Init(this->id3, 3, "3"));
314     this->delegate_.TriggerOnIncomingInvalidation(invalidation_map);
315     EXPECT_EQ(0, handler1.GetInvalidationCount());
316     EXPECT_EQ(1, handler2.GetInvalidationCount());
317   }
318 
319   this->delegate_.TriggerOnInvalidatorStateChange(TRANSIENT_INVALIDATION_ERROR);
320   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler1.GetInvalidatorState());
321   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler2.GetInvalidatorState());
322 
323   invalidator->UnregisterHandler(&handler2);
324   invalidator->UnregisterHandler(&handler1);
325 }
326 
327 namespace internal {
328 
329 // A FakeInvalidationHandler that is "bound" to a specific
330 // Invalidator.  This is for cross-referencing state information with
331 // the bound Invalidator.
332 class BoundFakeInvalidationHandler : public FakeInvalidationHandler {
333  public:
334   explicit BoundFakeInvalidationHandler(const Invalidator& invalidator);
335   virtual ~BoundFakeInvalidationHandler();
336 
337   // Returns the last return value of GetInvalidatorState() on the
338   // bound invalidator from the last time the invalidator state
339   // changed.
340   InvalidatorState GetLastRetrievedState() const;
341 
342   // InvalidationHandler implementation.
343   virtual void OnInvalidatorStateChange(InvalidatorState state) OVERRIDE;
344 
345  private:
346   const Invalidator& invalidator_;
347   InvalidatorState last_retrieved_state_;
348 
349   DISALLOW_COPY_AND_ASSIGN(BoundFakeInvalidationHandler);
350 };
351 
352 }  // namespace internal
353 
TYPED_TEST_P(InvalidatorTest,GetInvalidatorStateAlwaysCurrent)354 TYPED_TEST_P(InvalidatorTest, GetInvalidatorStateAlwaysCurrent) {
355   Invalidator* const invalidator = this->CreateAndInitializeInvalidator();
356 
357   internal::BoundFakeInvalidationHandler handler(*invalidator);
358   invalidator->RegisterHandler(&handler);
359 
360   this->delegate_.TriggerOnInvalidatorStateChange(INVALIDATIONS_ENABLED);
361   EXPECT_EQ(INVALIDATIONS_ENABLED, handler.GetInvalidatorState());
362   EXPECT_EQ(INVALIDATIONS_ENABLED, handler.GetLastRetrievedState());
363 
364   this->delegate_.TriggerOnInvalidatorStateChange(TRANSIENT_INVALIDATION_ERROR);
365   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler.GetInvalidatorState());
366   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler.GetLastRetrievedState());
367 
368   invalidator->UnregisterHandler(&handler);
369 }
370 
371 REGISTER_TYPED_TEST_CASE_P(InvalidatorTest,
372                            Basic, MultipleHandlers, EmptySetUnregisters,
373                            GetInvalidatorStateAlwaysCurrent);
374 
375 }  // namespace syncer
376 
377 #endif  // COMPONENTS_INVALIDATION_INVALIDATOR_TEST_TEMPLATE_H_
378