- add sources.
[platform/framework/web/crosswalk.git] / src / sync / notifier / invalidator_test_template.h
1 // Copyright (c) 2012 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 SYNC_NOTIFIER_INVALIDATOR_TEST_TEMPLATE_H_
78 #define SYNC_NOTIFIER_INVALIDATOR_TEST_TEMPLATE_H_
79
80 #include "base/basictypes.h"
81 #include "base/compiler_specific.h"
82 #include "google/cacheinvalidation/include/types.h"
83 #include "google/cacheinvalidation/types.pb.h"
84 #include "sync/internal_api/public/base/invalidation_test_util.h"
85 #include "sync/internal_api/public/base/object_id_invalidation_map_test_util.h"
86 #include "sync/notifier/fake_invalidation_handler.h"
87 #include "sync/notifier/fake_invalidation_state_tracker.h"
88 #include "sync/notifier/invalidator.h"
89 #include "testing/gtest/include/gtest/gtest.h"
90
91 namespace syncer {
92
93 template <typename InvalidatorTestDelegate>
94 class InvalidatorTest : public testing::Test {
95  protected:
96   InvalidatorTest()
97       : id1(ipc::invalidation::ObjectSource::TEST, "a"),
98         id2(ipc::invalidation::ObjectSource::TEST, "b"),
99         id3(ipc::invalidation::ObjectSource::TEST, "c"),
100         id4(ipc::invalidation::ObjectSource::TEST, "d") {
101   }
102
103   Invalidator* CreateAndInitializeInvalidator() {
104     this->delegate_.CreateInvalidator("fake_invalidator_client_id",
105                                       "fake_initial_state",
106                                       this->fake_tracker_.AsWeakPtr());
107     Invalidator* const invalidator = this->delegate_.GetInvalidator();
108
109     this->delegate_.WaitForInvalidator();
110     invalidator->UpdateCredentials("foo@bar.com", "fake_token");
111     this->delegate_.WaitForInvalidator();
112
113     return invalidator;
114   }
115
116   FakeInvalidationStateTracker fake_tracker_;
117   InvalidatorTestDelegate delegate_;
118
119   const invalidation::ObjectId id1;
120   const invalidation::ObjectId id2;
121   const invalidation::ObjectId id3;
122   const invalidation::ObjectId id4;
123 };
124
125 TYPED_TEST_CASE_P(InvalidatorTest);
126
127 // Initialize the invalidator, register a handler, register some IDs for that
128 // handler, and then unregister the handler, dispatching invalidations in
129 // between.  The handler should only see invalidations when its registered and
130 // its IDs are registered.
131 TYPED_TEST_P(InvalidatorTest, Basic) {
132   Invalidator* const invalidator = this->CreateAndInitializeInvalidator();
133
134   FakeInvalidationHandler handler;
135
136   invalidator->RegisterHandler(&handler);
137
138   ObjectIdInvalidationMap invalidation_map;
139   invalidation_map.Insert(Invalidation::Init(this->id1, 1, "1"));
140   invalidation_map.Insert(Invalidation::Init(this->id2, 2, "2"));
141   invalidation_map.Insert(Invalidation::Init(this->id3, 3, "3"));
142
143   // Should be ignored since no IDs are registered to |handler|.
144   this->delegate_.TriggerOnIncomingInvalidation(invalidation_map);
145   EXPECT_EQ(0, handler.GetInvalidationCount());
146
147   ObjectIdSet ids;
148   ids.insert(this->id1);
149   ids.insert(this->id2);
150   invalidator->UpdateRegisteredIds(&handler, ids);
151
152   this->delegate_.TriggerOnInvalidatorStateChange(INVALIDATIONS_ENABLED);
153   EXPECT_EQ(INVALIDATIONS_ENABLED, handler.GetInvalidatorState());
154
155   ObjectIdInvalidationMap expected_invalidations;
156   expected_invalidations.Insert(Invalidation::Init(this->id1, 1, "1"));
157   expected_invalidations.Insert(Invalidation::Init(this->id2, 2, "2"));
158
159   this->delegate_.TriggerOnIncomingInvalidation(invalidation_map);
160   EXPECT_EQ(1, handler.GetInvalidationCount());
161   EXPECT_THAT(expected_invalidations, Eq(handler.GetLastInvalidationMap()));
162
163   ids.erase(this->id1);
164   ids.insert(this->id3);
165   invalidator->UpdateRegisteredIds(&handler, ids);
166
167   expected_invalidations = ObjectIdInvalidationMap();
168   expected_invalidations.Insert(Invalidation::Init(this->id2, 2, "2"));
169   expected_invalidations.Insert(Invalidation::Init(this->id3, 3, "3"));
170
171   // Removed object IDs should not be notified, newly-added ones should.
172   this->delegate_.TriggerOnIncomingInvalidation(invalidation_map);
173   EXPECT_EQ(2, handler.GetInvalidationCount());
174   EXPECT_THAT(expected_invalidations, Eq(handler.GetLastInvalidationMap()));
175
176   this->delegate_.TriggerOnInvalidatorStateChange(TRANSIENT_INVALIDATION_ERROR);
177   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR,
178             handler.GetInvalidatorState());
179
180   this->delegate_.TriggerOnInvalidatorStateChange(
181       INVALIDATION_CREDENTIALS_REJECTED);
182   EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED,
183             handler.GetInvalidatorState());
184
185   invalidator->UnregisterHandler(&handler);
186
187   // Should be ignored since |handler| isn't registered anymore.
188   this->delegate_.TriggerOnIncomingInvalidation(invalidation_map);
189   EXPECT_EQ(2, handler.GetInvalidationCount());
190 }
191
192 // Register handlers and some IDs for those handlers, register a handler with
193 // no IDs, and register a handler with some IDs but unregister it.  Then,
194 // dispatch some invalidations and invalidations.  Handlers that are registered
195 // should get invalidations, and the ones that have registered IDs should
196 // receive invalidations for those IDs.
197 TYPED_TEST_P(InvalidatorTest, MultipleHandlers) {
198   Invalidator* const invalidator = this->CreateAndInitializeInvalidator();
199
200   FakeInvalidationHandler handler1;
201   FakeInvalidationHandler handler2;
202   FakeInvalidationHandler handler3;
203   FakeInvalidationHandler handler4;
204
205   invalidator->RegisterHandler(&handler1);
206   invalidator->RegisterHandler(&handler2);
207   invalidator->RegisterHandler(&handler3);
208   invalidator->RegisterHandler(&handler4);
209
210   {
211     ObjectIdSet ids;
212     ids.insert(this->id1);
213     ids.insert(this->id2);
214     invalidator->UpdateRegisteredIds(&handler1, ids);
215   }
216
217   {
218     ObjectIdSet ids;
219     ids.insert(this->id3);
220     invalidator->UpdateRegisteredIds(&handler2, ids);
221   }
222
223   // Don't register any IDs for handler3.
224
225   {
226     ObjectIdSet ids;
227     ids.insert(this->id4);
228     invalidator->UpdateRegisteredIds(&handler4, ids);
229   }
230
231   invalidator->UnregisterHandler(&handler4);
232
233   this->delegate_.TriggerOnInvalidatorStateChange(INVALIDATIONS_ENABLED);
234   EXPECT_EQ(INVALIDATIONS_ENABLED, handler1.GetInvalidatorState());
235   EXPECT_EQ(INVALIDATIONS_ENABLED, handler2.GetInvalidatorState());
236   EXPECT_EQ(INVALIDATIONS_ENABLED, handler3.GetInvalidatorState());
237   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler4.GetInvalidatorState());
238
239   {
240     ObjectIdInvalidationMap invalidation_map;
241     invalidation_map.Insert(Invalidation::Init(this->id1, 1, "1"));
242     invalidation_map.Insert(Invalidation::Init(this->id2, 2, "2"));
243     invalidation_map.Insert(Invalidation::Init(this->id3, 3, "3"));
244     invalidation_map.Insert(Invalidation::Init(this->id4, 4, "4"));
245
246     this->delegate_.TriggerOnIncomingInvalidation(invalidation_map);
247
248     ObjectIdInvalidationMap expected_invalidations;
249     expected_invalidations.Insert(Invalidation::Init(this->id1, 1, "1"));
250     expected_invalidations.Insert(Invalidation::Init(this->id2, 2, "2"));
251
252     EXPECT_EQ(1, handler1.GetInvalidationCount());
253     EXPECT_THAT(expected_invalidations, Eq(handler1.GetLastInvalidationMap()));
254
255     expected_invalidations = ObjectIdInvalidationMap();
256     expected_invalidations.Insert(Invalidation::Init(this->id3, 3, "3"));
257
258     EXPECT_EQ(1, handler2.GetInvalidationCount());
259     EXPECT_THAT(expected_invalidations, Eq(handler2.GetLastInvalidationMap()));
260
261     EXPECT_EQ(0, handler3.GetInvalidationCount());
262     EXPECT_EQ(0, handler4.GetInvalidationCount());
263   }
264
265   this->delegate_.TriggerOnInvalidatorStateChange(TRANSIENT_INVALIDATION_ERROR);
266   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler1.GetInvalidatorState());
267   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler2.GetInvalidatorState());
268   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler3.GetInvalidatorState());
269   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler4.GetInvalidatorState());
270
271   invalidator->UnregisterHandler(&handler3);
272   invalidator->UnregisterHandler(&handler2);
273   invalidator->UnregisterHandler(&handler1);
274 }
275
276 // Make sure that passing an empty set to UpdateRegisteredIds clears the
277 // corresponding entries for the handler.
278 TYPED_TEST_P(InvalidatorTest, EmptySetUnregisters) {
279   Invalidator* const invalidator = this->CreateAndInitializeInvalidator();
280
281   FakeInvalidationHandler handler1;
282
283   // Control observer.
284   FakeInvalidationHandler handler2;
285
286   invalidator->RegisterHandler(&handler1);
287   invalidator->RegisterHandler(&handler2);
288
289   {
290     ObjectIdSet ids;
291     ids.insert(this->id1);
292     ids.insert(this->id2);
293     invalidator->UpdateRegisteredIds(&handler1, ids);
294   }
295
296   {
297     ObjectIdSet ids;
298     ids.insert(this->id3);
299     invalidator->UpdateRegisteredIds(&handler2, ids);
300   }
301
302   // Unregister the IDs for the first observer. It should not receive any
303   // further invalidations.
304   invalidator->UpdateRegisteredIds(&handler1, ObjectIdSet());
305
306   this->delegate_.TriggerOnInvalidatorStateChange(INVALIDATIONS_ENABLED);
307   EXPECT_EQ(INVALIDATIONS_ENABLED, handler1.GetInvalidatorState());
308   EXPECT_EQ(INVALIDATIONS_ENABLED, handler2.GetInvalidatorState());
309
310   {
311     ObjectIdInvalidationMap invalidation_map;
312     invalidation_map.Insert(Invalidation::Init(this->id1, 1, "1"));
313     invalidation_map.Insert(Invalidation::Init(this->id2, 2, "2"));
314     invalidation_map.Insert(Invalidation::Init(this->id3, 3, "3"));
315     this->delegate_.TriggerOnIncomingInvalidation(invalidation_map);
316     EXPECT_EQ(0, handler1.GetInvalidationCount());
317     EXPECT_EQ(1, handler2.GetInvalidationCount());
318   }
319
320   this->delegate_.TriggerOnInvalidatorStateChange(TRANSIENT_INVALIDATION_ERROR);
321   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler1.GetInvalidatorState());
322   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler2.GetInvalidatorState());
323
324   invalidator->UnregisterHandler(&handler2);
325   invalidator->UnregisterHandler(&handler1);
326 }
327
328 namespace internal {
329
330 // A FakeInvalidationHandler that is "bound" to a specific
331 // Invalidator.  This is for cross-referencing state information with
332 // the bound Invalidator.
333 class BoundFakeInvalidationHandler : public FakeInvalidationHandler {
334  public:
335   explicit BoundFakeInvalidationHandler(const Invalidator& invalidator);
336   virtual ~BoundFakeInvalidationHandler();
337
338   // Returns the last return value of GetInvalidatorState() on the
339   // bound invalidator from the last time the invalidator state
340   // changed.
341   InvalidatorState GetLastRetrievedState() const;
342
343   // InvalidationHandler implementation.
344   virtual void OnInvalidatorStateChange(InvalidatorState state) OVERRIDE;
345
346  private:
347   const Invalidator& invalidator_;
348   InvalidatorState last_retrieved_state_;
349
350   DISALLOW_COPY_AND_ASSIGN(BoundFakeInvalidationHandler);
351 };
352
353 }  // namespace internal
354
355 TYPED_TEST_P(InvalidatorTest, GetInvalidatorStateAlwaysCurrent) {
356   Invalidator* const invalidator = this->CreateAndInitializeInvalidator();
357
358   internal::BoundFakeInvalidationHandler handler(*invalidator);
359   invalidator->RegisterHandler(&handler);
360
361   this->delegate_.TriggerOnInvalidatorStateChange(INVALIDATIONS_ENABLED);
362   EXPECT_EQ(INVALIDATIONS_ENABLED, handler.GetInvalidatorState());
363   EXPECT_EQ(INVALIDATIONS_ENABLED, handler.GetLastRetrievedState());
364
365   this->delegate_.TriggerOnInvalidatorStateChange(TRANSIENT_INVALIDATION_ERROR);
366   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler.GetInvalidatorState());
367   EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler.GetLastRetrievedState());
368
369   invalidator->UnregisterHandler(&handler);
370 }
371
372 REGISTER_TYPED_TEST_CASE_P(InvalidatorTest,
373                            Basic, MultipleHandlers, EmptySetUnregisters,
374                            GetInvalidatorStateAlwaysCurrent);
375
376 }  // namespace syncer
377
378 #endif  // SYNC_NOTIFIER_INVALIDATOR_TEST_TEMPLATE_H_