OLD | NEW |
| (Empty) |
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 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 "google/cacheinvalidation/include/types.h" | |
85 #include "google/cacheinvalidation/types.pb.h" | |
86 #include "sync/internal_api/public/base/object_id_invalidation_map_test_util.h" | |
87 #include "sync/notifier/invalidator.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: | |
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 | |
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. | |
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. | |
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. | |
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 | |
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_ | |
OLD | NEW |