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