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.
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.
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:
11 // class MyInvalidatorTestDelegate {
13 // MyInvalidatorTestDelegate() ...
15 // ~MyInvalidatorTestDelegate() {
16 // // DestroyInvalidator() may not be explicitly called by tests.
17 // DestroyInvalidator();
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) {
28 // // Should return the Invalidator implementation. Only called after
29 // // CreateInvalidator and before DestroyInvalidator.
30 // MyInvalidator* GetInvalidator() {
34 // // Destroy the Invalidator implementation.
35 // void DestroyInvalidator() {
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() {
46 // // The Trigger* functions below should block until the effects of
47 // // the call are visible on the current thread.
49 // // Should cause OnInvalidatorStateChange() to be called on all
50 // // observers of the Invalidator implementation with the given
52 // void TriggerOnInvalidatorStateChange(InvalidatorState state) {
56 // // Should cause OnIncomingInvalidation() to be called on all
57 // // observers of the Invalidator implementation with the given
59 // void TriggerOnIncomingInvalidation(
60 // const ObjectIdInvalidationMap& invalidation_map) {
65 // The InvalidatorTest test harness will have a member variable of
66 // this delegate type and will call its functions in the various
69 // Then you simply #include this file as well as gtest.h and add the
70 // following statement to my_sync_notifier_unittest.cc:
72 // INSTANTIATE_TYPED_TEST_CASE_P(
73 // MyInvalidator, InvalidatorTest, MyInvalidatorTestDelegate);
77 #ifndef SYNC_NOTIFIER_INVALIDATOR_TEST_TEMPLATE_H_
78 #define SYNC_NOTIFIER_INVALIDATOR_TEST_TEMPLATE_H_
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"
93 template <typename InvalidatorTestDelegate
>
94 class InvalidatorTest
: public testing::Test
{
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") {
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();
109 this->delegate_
.WaitForInvalidator();
110 invalidator
->UpdateCredentials("foo@bar.com", "fake_token");
111 this->delegate_
.WaitForInvalidator();
116 FakeInvalidationStateTracker fake_tracker_
;
117 InvalidatorTestDelegate delegate_
;
119 const invalidation::ObjectId id1
;
120 const invalidation::ObjectId id2
;
121 const invalidation::ObjectId id3
;
122 const invalidation::ObjectId id4
;
125 TYPED_TEST_CASE_P(InvalidatorTest
);
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();
134 FakeInvalidationHandler handler
;
136 invalidator
->RegisterHandler(&handler
);
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"));
143 // Should be ignored since no IDs are registered to |handler|.
144 this->delegate_
.TriggerOnIncomingInvalidation(invalidation_map
);
145 EXPECT_EQ(0, handler
.GetInvalidationCount());
148 ids
.insert(this->id1
);
149 ids
.insert(this->id2
);
150 invalidator
->UpdateRegisteredIds(&handler
, ids
);
152 this->delegate_
.TriggerOnInvalidatorStateChange(INVALIDATIONS_ENABLED
);
153 EXPECT_EQ(INVALIDATIONS_ENABLED
, handler
.GetInvalidatorState());
155 ObjectIdInvalidationMap expected_invalidations
;
156 expected_invalidations
.Insert(Invalidation::Init(this->id1
, 1, "1"));
157 expected_invalidations
.Insert(Invalidation::Init(this->id2
, 2, "2"));
159 this->delegate_
.TriggerOnIncomingInvalidation(invalidation_map
);
160 EXPECT_EQ(1, handler
.GetInvalidationCount());
161 EXPECT_THAT(expected_invalidations
, Eq(handler
.GetLastInvalidationMap()));
163 ids
.erase(this->id1
);
164 ids
.insert(this->id3
);
165 invalidator
->UpdateRegisteredIds(&handler
, ids
);
167 expected_invalidations
= ObjectIdInvalidationMap();
168 expected_invalidations
.Insert(Invalidation::Init(this->id2
, 2, "2"));
169 expected_invalidations
.Insert(Invalidation::Init(this->id3
, 3, "3"));
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()));
176 this->delegate_
.TriggerOnInvalidatorStateChange(TRANSIENT_INVALIDATION_ERROR
);
177 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR
,
178 handler
.GetInvalidatorState());
180 this->delegate_
.TriggerOnInvalidatorStateChange(
181 INVALIDATION_CREDENTIALS_REJECTED
);
182 EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED
,
183 handler
.GetInvalidatorState());
185 invalidator
->UnregisterHandler(&handler
);
187 // Should be ignored since |handler| isn't registered anymore.
188 this->delegate_
.TriggerOnIncomingInvalidation(invalidation_map
);
189 EXPECT_EQ(2, handler
.GetInvalidationCount());
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();
200 FakeInvalidationHandler handler1
;
201 FakeInvalidationHandler handler2
;
202 FakeInvalidationHandler handler3
;
203 FakeInvalidationHandler handler4
;
205 invalidator
->RegisterHandler(&handler1
);
206 invalidator
->RegisterHandler(&handler2
);
207 invalidator
->RegisterHandler(&handler3
);
208 invalidator
->RegisterHandler(&handler4
);
212 ids
.insert(this->id1
);
213 ids
.insert(this->id2
);
214 invalidator
->UpdateRegisteredIds(&handler1
, ids
);
219 ids
.insert(this->id3
);
220 invalidator
->UpdateRegisteredIds(&handler2
, ids
);
223 // Don't register any IDs for handler3.
227 ids
.insert(this->id4
);
228 invalidator
->UpdateRegisteredIds(&handler4
, ids
);
231 invalidator
->UnregisterHandler(&handler4
);
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());
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"));
246 this->delegate_
.TriggerOnIncomingInvalidation(invalidation_map
);
248 ObjectIdInvalidationMap expected_invalidations
;
249 expected_invalidations
.Insert(Invalidation::Init(this->id1
, 1, "1"));
250 expected_invalidations
.Insert(Invalidation::Init(this->id2
, 2, "2"));
252 EXPECT_EQ(1, handler1
.GetInvalidationCount());
253 EXPECT_THAT(expected_invalidations
, Eq(handler1
.GetLastInvalidationMap()));
255 expected_invalidations
= ObjectIdInvalidationMap();
256 expected_invalidations
.Insert(Invalidation::Init(this->id3
, 3, "3"));
258 EXPECT_EQ(1, handler2
.GetInvalidationCount());
259 EXPECT_THAT(expected_invalidations
, Eq(handler2
.GetLastInvalidationMap()));
261 EXPECT_EQ(0, handler3
.GetInvalidationCount());
262 EXPECT_EQ(0, handler4
.GetInvalidationCount());
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());
271 invalidator
->UnregisterHandler(&handler3
);
272 invalidator
->UnregisterHandler(&handler2
);
273 invalidator
->UnregisterHandler(&handler1
);
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();
281 FakeInvalidationHandler handler1
;
284 FakeInvalidationHandler handler2
;
286 invalidator
->RegisterHandler(&handler1
);
287 invalidator
->RegisterHandler(&handler2
);
291 ids
.insert(this->id1
);
292 ids
.insert(this->id2
);
293 invalidator
->UpdateRegisteredIds(&handler1
, ids
);
298 ids
.insert(this->id3
);
299 invalidator
->UpdateRegisteredIds(&handler2
, ids
);
302 // Unregister the IDs for the first observer. It should not receive any
303 // further invalidations.
304 invalidator
->UpdateRegisteredIds(&handler1
, ObjectIdSet());
306 this->delegate_
.TriggerOnInvalidatorStateChange(INVALIDATIONS_ENABLED
);
307 EXPECT_EQ(INVALIDATIONS_ENABLED
, handler1
.GetInvalidatorState());
308 EXPECT_EQ(INVALIDATIONS_ENABLED
, handler2
.GetInvalidatorState());
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());
320 this->delegate_
.TriggerOnInvalidatorStateChange(TRANSIENT_INVALIDATION_ERROR
);
321 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR
, handler1
.GetInvalidatorState());
322 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR
, handler2
.GetInvalidatorState());
324 invalidator
->UnregisterHandler(&handler2
);
325 invalidator
->UnregisterHandler(&handler1
);
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
{
335 explicit BoundFakeInvalidationHandler(const Invalidator
& invalidator
);
336 virtual ~BoundFakeInvalidationHandler();
338 // Returns the last return value of GetInvalidatorState() on the
339 // bound invalidator from the last time the invalidator state
341 InvalidatorState
GetLastRetrievedState() const;
343 // InvalidationHandler implementation.
344 virtual void OnInvalidatorStateChange(InvalidatorState state
) OVERRIDE
;
347 const Invalidator
& invalidator_
;
348 InvalidatorState last_retrieved_state_
;
350 DISALLOW_COPY_AND_ASSIGN(BoundFakeInvalidationHandler
);
353 } // namespace internal
355 TYPED_TEST_P(InvalidatorTest
, GetInvalidatorStateAlwaysCurrent
) {
356 Invalidator
* const invalidator
= this->CreateAndInitializeInvalidator();
358 internal::BoundFakeInvalidationHandler
handler(*invalidator
);
359 invalidator
->RegisterHandler(&handler
);
361 this->delegate_
.TriggerOnInvalidatorStateChange(INVALIDATIONS_ENABLED
);
362 EXPECT_EQ(INVALIDATIONS_ENABLED
, handler
.GetInvalidatorState());
363 EXPECT_EQ(INVALIDATIONS_ENABLED
, handler
.GetLastRetrievedState());
365 this->delegate_
.TriggerOnInvalidatorStateChange(TRANSIENT_INVALIDATION_ERROR
);
366 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR
, handler
.GetInvalidatorState());
367 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR
, handler
.GetLastRetrievedState());
369 invalidator
->UnregisterHandler(&handler
);
372 REGISTER_TYPED_TEST_CASE_P(InvalidatorTest
,
373 Basic
, MultipleHandlers
, EmptySetUnregisters
,
374 GetInvalidatorStateAlwaysCurrent
);
376 } // namespace syncer
378 #endif // SYNC_NOTIFIER_INVALIDATOR_TEST_TEMPLATE_H_