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.
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
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:
13 // class MyInvalidationServiceTestDelegate {
15 // MyInvalidationServiceTestDelegate() ...
17 // ~MyInvalidationServiceTestDelegate() {
18 // // DestroyInvalidator() may not be explicitly called by tests.
19 // DestroyInvalidator();
22 // // Create the InvalidationService implementation with the given params.
23 // void CreateInvalidationService() {
27 // // Should return the InvalidationService implementation. Only called
28 // // after CreateInvalidator and before DestroyInvalidator.
29 // MyInvalidationService* GetInvalidationService() {
33 // // Destroy the InvalidationService implementation.
34 // void DestroyInvalidationService() {
38 // // The Trigger* functions below should block until the effects of
39 // // the call are visible on the current thread.
41 // // Should cause OnInvalidatorStateChange() to be called on all
42 // // observers of the InvalidationService implementation with the given
44 // void TriggerOnInvalidatorStateChange(InvalidatorState state) {
48 // // Should cause OnIncomingInvalidation() to be called on all
49 // // observers of the InvalidationService implementation with the given
51 // void TriggerOnIncomingInvalidation(
52 // const ObjectIdInvalidationMap& invalidation_map) {
57 // The InvalidationServiceTest test harness will have a member variable of
58 // this delegate type and will call its functions in the various
61 // Then you simply #include this file as well as gtest.h and add the
62 // following statement to my_sync_notifier_unittest.cc:
64 // INSTANTIATE_TYPED_TEST_CASE_P(
65 // MyInvalidationService,
66 // InvalidationServiceTest,
67 // MyInvalidatorTestDelegate);
71 #ifndef CHROME_BROWSER_INVALIDATION_INVALIDATION_SERVICE_TEST_TEMPLATE_H_
72 #define CHROME_BROWSER_INVALIDATION_INVALIDATION_SERVICE_TEST_TEMPLATE_H_
74 #include "base/basictypes.h"
75 #include "base/compiler_specific.h"
76 #include "components/invalidation/invalidation_service.h"
77 #include "content/public/test/test_browser_thread_bundle.h"
78 #include "google/cacheinvalidation/include/types.h"
79 #include "google/cacheinvalidation/types.pb.h"
80 #include "sync/internal_api/public/base/ack_handle.h"
81 #include "sync/internal_api/public/base/invalidation.h"
82 #include "sync/internal_api/public/base/object_id_invalidation_map_test_util.h"
83 #include "sync/notifier/fake_invalidation_handler.h"
84 #include "sync/notifier/object_id_invalidation_map.h"
85 #include "testing/gtest/include/gtest/gtest.h"
87 template <typename InvalidatorTestDelegate
>
88 class InvalidationServiceTest
: public testing::Test
{
90 InvalidationServiceTest()
91 : id1(ipc::invalidation::ObjectSource::CHROME_SYNC
, "BOOKMARK"),
92 id2(ipc::invalidation::ObjectSource::CHROME_SYNC
, "PREFERENCE"),
93 id3(ipc::invalidation::ObjectSource::CHROME_SYNC
, "AUTOFILL"),
94 id4(ipc::invalidation::ObjectSource::CHROME_PUSH_MESSAGING
,
98 invalidation::InvalidationService
*
99 CreateAndInitializeInvalidationService() {
100 this->delegate_
.CreateInvalidationService();
101 return this->delegate_
.GetInvalidationService();
104 content::TestBrowserThreadBundle thread_bundle_
;
105 InvalidatorTestDelegate delegate_
;
107 const invalidation::ObjectId id1
;
108 const invalidation::ObjectId id2
;
109 const invalidation::ObjectId id3
;
110 const invalidation::ObjectId id4
;
113 TYPED_TEST_CASE_P(InvalidationServiceTest
);
115 // Initialize the invalidator, register a handler, register some IDs for that
116 // handler, and then unregister the handler, dispatching invalidations in
117 // between. The handler should only see invalidations when its registered and
118 // its IDs are registered.
119 TYPED_TEST_P(InvalidationServiceTest
, Basic
) {
120 invalidation::InvalidationService
* const invalidator
=
121 this->CreateAndInitializeInvalidationService();
123 syncer::FakeInvalidationHandler handler
;
125 invalidator
->RegisterInvalidationHandler(&handler
);
127 syncer::ObjectIdInvalidationMap invalidation_map
;
128 invalidation_map
.Insert(syncer::Invalidation::Init(this->id1
, 1, "1"));
129 invalidation_map
.Insert(syncer::Invalidation::Init(this->id2
, 2, "2"));
130 invalidation_map
.Insert(syncer::Invalidation::Init(this->id3
, 3, "3"));
132 // Should be ignored since no IDs are registered to |handler|.
133 this->delegate_
.TriggerOnIncomingInvalidation(invalidation_map
);
134 EXPECT_EQ(0, handler
.GetInvalidationCount());
136 syncer::ObjectIdSet ids
;
137 ids
.insert(this->id1
);
138 ids
.insert(this->id2
);
139 invalidator
->UpdateRegisteredInvalidationIds(&handler
, ids
);
141 this->delegate_
.TriggerOnInvalidatorStateChange(
142 syncer::INVALIDATIONS_ENABLED
);
143 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED
, handler
.GetInvalidatorState());
145 syncer::ObjectIdInvalidationMap expected_invalidations
;
146 expected_invalidations
.Insert(syncer::Invalidation::Init(this->id1
, 1, "1"));
147 expected_invalidations
.Insert(syncer::Invalidation::Init(this->id2
, 2, "2"));
149 this->delegate_
.TriggerOnIncomingInvalidation(invalidation_map
);
150 EXPECT_EQ(1, handler
.GetInvalidationCount());
151 EXPECT_THAT(expected_invalidations
, Eq(handler
.GetLastInvalidationMap()));
153 ids
.erase(this->id1
);
154 ids
.insert(this->id3
);
155 invalidator
->UpdateRegisteredInvalidationIds(&handler
, ids
);
157 expected_invalidations
= syncer::ObjectIdInvalidationMap();
158 expected_invalidations
.Insert(syncer::Invalidation::Init(this->id2
, 2, "2"));
159 expected_invalidations
.Insert(syncer::Invalidation::Init(this->id3
, 3, "3"));
161 // Removed object IDs should not be notified, newly-added ones should.
162 this->delegate_
.TriggerOnIncomingInvalidation(invalidation_map
);
163 EXPECT_EQ(2, handler
.GetInvalidationCount());
164 EXPECT_THAT(expected_invalidations
, Eq(handler
.GetLastInvalidationMap()));
166 this->delegate_
.TriggerOnInvalidatorStateChange(
167 syncer::TRANSIENT_INVALIDATION_ERROR
);
168 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR
,
169 handler
.GetInvalidatorState());
171 this->delegate_
.TriggerOnInvalidatorStateChange(
172 syncer::INVALIDATIONS_ENABLED
);
173 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED
,
174 handler
.GetInvalidatorState());
176 invalidator
->UnregisterInvalidationHandler(&handler
);
178 // Should be ignored since |handler| isn't registered anymore.
179 this->delegate_
.TriggerOnIncomingInvalidation(invalidation_map
);
180 EXPECT_EQ(2, handler
.GetInvalidationCount());
183 // Register handlers and some IDs for those handlers, register a handler with
184 // no IDs, and register a handler with some IDs but unregister it. Then,
185 // dispatch some invalidations and invalidations. Handlers that are registered
186 // should get invalidations, and the ones that have registered IDs should
187 // receive invalidations for those IDs.
188 TYPED_TEST_P(InvalidationServiceTest
, MultipleHandlers
) {
189 invalidation::InvalidationService
* const invalidator
=
190 this->CreateAndInitializeInvalidationService();
192 syncer::FakeInvalidationHandler handler1
;
193 syncer::FakeInvalidationHandler handler2
;
194 syncer::FakeInvalidationHandler handler3
;
195 syncer::FakeInvalidationHandler handler4
;
197 invalidator
->RegisterInvalidationHandler(&handler1
);
198 invalidator
->RegisterInvalidationHandler(&handler2
);
199 invalidator
->RegisterInvalidationHandler(&handler3
);
200 invalidator
->RegisterInvalidationHandler(&handler4
);
203 syncer::ObjectIdSet ids
;
204 ids
.insert(this->id1
);
205 ids
.insert(this->id2
);
206 invalidator
->UpdateRegisteredInvalidationIds(&handler1
, ids
);
210 syncer::ObjectIdSet ids
;
211 ids
.insert(this->id3
);
212 invalidator
->UpdateRegisteredInvalidationIds(&handler2
, ids
);
215 // Don't register any IDs for handler3.
218 syncer::ObjectIdSet ids
;
219 ids
.insert(this->id4
);
220 invalidator
->UpdateRegisteredInvalidationIds(&handler4
, ids
);
223 invalidator
->UnregisterInvalidationHandler(&handler4
);
225 this->delegate_
.TriggerOnInvalidatorStateChange(
226 syncer::INVALIDATIONS_ENABLED
);
227 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED
, handler1
.GetInvalidatorState());
228 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED
, handler2
.GetInvalidatorState());
229 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED
, handler3
.GetInvalidatorState());
230 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR
,
231 handler4
.GetInvalidatorState());
234 syncer::ObjectIdInvalidationMap invalidation_map
;
235 invalidation_map
.Insert(syncer::Invalidation::Init(this->id1
, 1, "1"));
236 invalidation_map
.Insert(syncer::Invalidation::Init(this->id2
, 2, "2"));
237 invalidation_map
.Insert(syncer::Invalidation::Init(this->id3
, 3, "3"));
238 invalidation_map
.Insert(syncer::Invalidation::Init(this->id4
, 4, "4"));
239 this->delegate_
.TriggerOnIncomingInvalidation(invalidation_map
);
241 syncer::ObjectIdInvalidationMap expected_invalidations
;
242 expected_invalidations
.Insert(
243 syncer::Invalidation::Init(this->id1
, 1, "1"));
244 expected_invalidations
.Insert(
245 syncer::Invalidation::Init(this->id2
, 2, "2"));
247 EXPECT_EQ(1, handler1
.GetInvalidationCount());
248 EXPECT_THAT(expected_invalidations
, Eq(handler1
.GetLastInvalidationMap()));
250 expected_invalidations
= syncer::ObjectIdInvalidationMap();
251 expected_invalidations
.Insert(
252 syncer::Invalidation::Init(this->id3
, 3, "3"));
254 EXPECT_EQ(1, handler2
.GetInvalidationCount());
255 EXPECT_THAT(expected_invalidations
, Eq(handler2
.GetLastInvalidationMap()));
257 EXPECT_EQ(0, handler3
.GetInvalidationCount());
258 EXPECT_EQ(0, handler4
.GetInvalidationCount());
261 this->delegate_
.TriggerOnInvalidatorStateChange(
262 syncer::TRANSIENT_INVALIDATION_ERROR
);
263 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR
,
264 handler1
.GetInvalidatorState());
265 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR
,
266 handler2
.GetInvalidatorState());
267 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR
,
268 handler3
.GetInvalidatorState());
269 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR
,
270 handler4
.GetInvalidatorState());
272 invalidator
->UnregisterInvalidationHandler(&handler3
);
273 invalidator
->UnregisterInvalidationHandler(&handler2
);
274 invalidator
->UnregisterInvalidationHandler(&handler1
);
277 // Make sure that passing an empty set to UpdateRegisteredInvalidationIds clears
278 // the corresponding entries for the handler.
279 TYPED_TEST_P(InvalidationServiceTest
, EmptySetUnregisters
) {
280 invalidation::InvalidationService
* const invalidator
=
281 this->CreateAndInitializeInvalidationService();
283 syncer::FakeInvalidationHandler handler1
;
286 syncer::FakeInvalidationHandler handler2
;
288 invalidator
->RegisterInvalidationHandler(&handler1
);
289 invalidator
->RegisterInvalidationHandler(&handler2
);
292 syncer::ObjectIdSet ids
;
293 ids
.insert(this->id1
);
294 ids
.insert(this->id2
);
295 invalidator
->UpdateRegisteredInvalidationIds(&handler1
, ids
);
299 syncer::ObjectIdSet ids
;
300 ids
.insert(this->id3
);
301 invalidator
->UpdateRegisteredInvalidationIds(&handler2
, ids
);
304 // Unregister the IDs for the first observer. It should not receive any
305 // further invalidations.
306 invalidator
->UpdateRegisteredInvalidationIds(&handler1
,
307 syncer::ObjectIdSet());
309 this->delegate_
.TriggerOnInvalidatorStateChange(
310 syncer::INVALIDATIONS_ENABLED
);
311 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED
, handler1
.GetInvalidatorState());
312 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED
, handler2
.GetInvalidatorState());
315 syncer::ObjectIdInvalidationMap invalidation_map
;
316 invalidation_map
.Insert(syncer::Invalidation::Init(this->id1
, 1, "1"));
317 invalidation_map
.Insert(syncer::Invalidation::Init(this->id2
, 2, "2"));
318 invalidation_map
.Insert(syncer::Invalidation::Init(this->id3
, 3, "3"));
319 this->delegate_
.TriggerOnIncomingInvalidation(invalidation_map
);
320 EXPECT_EQ(0, handler1
.GetInvalidationCount());
321 EXPECT_EQ(1, handler2
.GetInvalidationCount());
324 this->delegate_
.TriggerOnInvalidatorStateChange(
325 syncer::TRANSIENT_INVALIDATION_ERROR
);
326 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR
,
327 handler1
.GetInvalidatorState());
328 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR
,
329 handler2
.GetInvalidatorState());
331 invalidator
->UnregisterInvalidationHandler(&handler2
);
332 invalidator
->UnregisterInvalidationHandler(&handler1
);
337 // A FakeInvalidationHandler that is "bound" to a specific
338 // InvalidationService. This is for cross-referencing state information with
339 // the bound InvalidationService.
340 class BoundFakeInvalidationHandler
: public syncer::FakeInvalidationHandler
{
342 explicit BoundFakeInvalidationHandler(
343 const invalidation::InvalidationService
& invalidator
);
344 virtual ~BoundFakeInvalidationHandler();
346 // Returns the last return value of GetInvalidatorState() on the
347 // bound invalidator from the last time the invalidator state
349 syncer::InvalidatorState
GetLastRetrievedState() const;
351 // InvalidationHandler implementation.
352 virtual void OnInvalidatorStateChange(
353 syncer::InvalidatorState state
) OVERRIDE
;
356 const invalidation::InvalidationService
& invalidator_
;
357 syncer::InvalidatorState last_retrieved_state_
;
359 DISALLOW_COPY_AND_ASSIGN(BoundFakeInvalidationHandler
);
362 } // namespace internal
364 TYPED_TEST_P(InvalidationServiceTest
, GetInvalidatorStateAlwaysCurrent
) {
365 invalidation::InvalidationService
* const invalidator
=
366 this->CreateAndInitializeInvalidationService();
368 internal::BoundFakeInvalidationHandler
handler(*invalidator
);
369 invalidator
->RegisterInvalidationHandler(&handler
);
371 this->delegate_
.TriggerOnInvalidatorStateChange(
372 syncer::INVALIDATIONS_ENABLED
);
373 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED
, handler
.GetInvalidatorState());
374 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED
, handler
.GetLastRetrievedState());
376 this->delegate_
.TriggerOnInvalidatorStateChange(
377 syncer::TRANSIENT_INVALIDATION_ERROR
);
378 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR
,
379 handler
.GetInvalidatorState());
380 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR
,
381 handler
.GetLastRetrievedState());
383 invalidator
->UnregisterInvalidationHandler(&handler
);
386 REGISTER_TYPED_TEST_CASE_P(InvalidationServiceTest
,
387 Basic
, MultipleHandlers
, EmptySetUnregisters
,
388 GetInvalidatorStateAlwaysCurrent
);
390 #endif // CHROME_BROWSER_INVALIDATION_INVALIDATION_SERVICE_TEST_TEMPLATE_H_