OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 COMPONENTS_INVALIDATION_INVALIDATION_SERVICE_TEST_TEMPLATE_H_ | |
72 #define COMPONENTS_INVALIDATION_INVALIDATION_SERVICE_TEST_TEMPLATE_H_ | |
73 | |
74 #include "base/basictypes.h" | |
75 #include "base/compiler_specific.h" | |
76 #include "components/invalidation/ack_handle.h" | |
77 #include "components/invalidation/fake_invalidation_handler.h" | |
78 #include "components/invalidation/invalidation.h" | |
79 #include "components/invalidation/invalidation_service.h" | |
80 #include "components/invalidation/object_id_invalidation_map.h" | |
81 #include "components/invalidation/object_id_invalidation_map_test_util.h" | |
82 #include "google/cacheinvalidation/include/types.h" | |
83 #include "google/cacheinvalidation/types.pb.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 EXPECT_TRUE(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 EXPECT_TRUE(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 EXPECT_TRUE(invalidator->UpdateRegisteredInvalidationIds(&handler1, ids)); | |
205 } | |
206 | |
207 { | |
208 syncer::ObjectIdSet ids; | |
209 ids.insert(this->id3); | |
210 EXPECT_TRUE(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 EXPECT_TRUE(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 // Multiple registrations by different handlers on the same object ID should | |
276 // return false. | |
277 TYPED_TEST_P(InvalidationServiceTest, MultipleRegistrations) { | |
278 invalidation::InvalidationService* const invalidator = | |
279 this->CreateAndInitializeInvalidationService(); | |
280 | |
281 syncer::FakeInvalidationHandler handler1; | |
282 syncer::FakeInvalidationHandler handler2; | |
283 | |
284 invalidator->RegisterInvalidationHandler(&handler1); | |
285 invalidator->RegisterInvalidationHandler(&handler2); | |
286 | |
287 // Registering both handlers for the same ObjectId. First call should succeed, | |
288 // second should fail. | |
289 syncer::ObjectIdSet ids; | |
290 ids.insert(this->id1); | |
291 EXPECT_TRUE(invalidator->UpdateRegisteredInvalidationIds(&handler1, ids)); | |
292 EXPECT_FALSE(invalidator->UpdateRegisteredInvalidationIds(&handler2, ids)); | |
293 | |
294 invalidator->UnregisterInvalidationHandler(&handler2); | |
295 invalidator->UnregisterInvalidationHandler(&handler1); | |
296 } | |
297 | |
298 // Make sure that passing an empty set to UpdateRegisteredInvalidationIds clears | |
299 // the corresponding entries for the handler. | |
300 TYPED_TEST_P(InvalidationServiceTest, EmptySetUnregisters) { | |
301 invalidation::InvalidationService* const invalidator = | |
302 this->CreateAndInitializeInvalidationService(); | |
303 | |
304 syncer::FakeInvalidationHandler handler1; | |
305 | |
306 // Control observer. | |
307 syncer::FakeInvalidationHandler handler2; | |
308 | |
309 invalidator->RegisterInvalidationHandler(&handler1); | |
310 invalidator->RegisterInvalidationHandler(&handler2); | |
311 | |
312 { | |
313 syncer::ObjectIdSet ids; | |
314 ids.insert(this->id1); | |
315 ids.insert(this->id2); | |
316 EXPECT_TRUE(invalidator->UpdateRegisteredInvalidationIds(&handler1, ids)); | |
317 } | |
318 | |
319 { | |
320 syncer::ObjectIdSet ids; | |
321 ids.insert(this->id3); | |
322 EXPECT_TRUE(invalidator->UpdateRegisteredInvalidationIds(&handler2, ids)); | |
323 } | |
324 | |
325 // Unregister the IDs for the first observer. It should not receive any | |
326 // further invalidations. | |
327 EXPECT_TRUE(invalidator->UpdateRegisteredInvalidationIds( | |
328 &handler1, syncer::ObjectIdSet())); | |
329 | |
330 this->delegate_.TriggerOnInvalidatorStateChange( | |
331 syncer::INVALIDATIONS_ENABLED); | |
332 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler1.GetInvalidatorState()); | |
333 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler2.GetInvalidatorState()); | |
334 | |
335 { | |
336 syncer::ObjectIdInvalidationMap invalidation_map; | |
337 invalidation_map.Insert(syncer::Invalidation::Init(this->id1, 1, "1")); | |
338 invalidation_map.Insert(syncer::Invalidation::Init(this->id2, 2, "2")); | |
339 invalidation_map.Insert(syncer::Invalidation::Init(this->id3, 3, "3")); | |
340 this->delegate_.TriggerOnIncomingInvalidation(invalidation_map); | |
341 EXPECT_EQ(0, handler1.GetInvalidationCount()); | |
342 EXPECT_EQ(1, handler2.GetInvalidationCount()); | |
343 } | |
344 | |
345 this->delegate_.TriggerOnInvalidatorStateChange( | |
346 syncer::TRANSIENT_INVALIDATION_ERROR); | |
347 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR, | |
348 handler1.GetInvalidatorState()); | |
349 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR, | |
350 handler2.GetInvalidatorState()); | |
351 | |
352 invalidator->UnregisterInvalidationHandler(&handler2); | |
353 invalidator->UnregisterInvalidationHandler(&handler1); | |
354 } | |
355 | |
356 namespace internal { | |
357 | |
358 // A FakeInvalidationHandler that is "bound" to a specific | |
359 // InvalidationService. This is for cross-referencing state information with | |
360 // the bound InvalidationService. | |
361 class BoundFakeInvalidationHandler : public syncer::FakeInvalidationHandler { | |
362 public: | |
363 explicit BoundFakeInvalidationHandler( | |
364 const invalidation::InvalidationService& invalidator); | |
365 ~BoundFakeInvalidationHandler() override; | |
366 | |
367 // Returns the last return value of GetInvalidatorState() on the | |
368 // bound invalidator from the last time the invalidator state | |
369 // changed. | |
370 syncer::InvalidatorState GetLastRetrievedState() const; | |
371 | |
372 // InvalidationHandler implementation. | |
373 void OnInvalidatorStateChange(syncer::InvalidatorState state) override; | |
374 | |
375 private: | |
376 const invalidation::InvalidationService& invalidator_; | |
377 syncer::InvalidatorState last_retrieved_state_; | |
378 | |
379 DISALLOW_COPY_AND_ASSIGN(BoundFakeInvalidationHandler); | |
380 }; | |
381 | |
382 } // namespace internal | |
383 | |
384 TYPED_TEST_P(InvalidationServiceTest, GetInvalidatorStateAlwaysCurrent) { | |
385 invalidation::InvalidationService* const invalidator = | |
386 this->CreateAndInitializeInvalidationService(); | |
387 | |
388 internal::BoundFakeInvalidationHandler handler(*invalidator); | |
389 invalidator->RegisterInvalidationHandler(&handler); | |
390 | |
391 this->delegate_.TriggerOnInvalidatorStateChange( | |
392 syncer::INVALIDATIONS_ENABLED); | |
393 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler.GetInvalidatorState()); | |
394 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler.GetLastRetrievedState()); | |
395 | |
396 this->delegate_.TriggerOnInvalidatorStateChange( | |
397 syncer::TRANSIENT_INVALIDATION_ERROR); | |
398 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR, | |
399 handler.GetInvalidatorState()); | |
400 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR, | |
401 handler.GetLastRetrievedState()); | |
402 | |
403 invalidator->UnregisterInvalidationHandler(&handler); | |
404 } | |
405 | |
406 REGISTER_TYPED_TEST_CASE_P(InvalidationServiceTest, | |
407 Basic, | |
408 MultipleHandlers, | |
409 MultipleRegistrations, | |
410 EmptySetUnregisters, | |
411 GetInvalidatorStateAlwaysCurrent); | |
412 | |
413 #endif // COMPONENTS_INVALIDATION_INVALIDATION_SERVICE_TEST_TEMPLATE_H_ | |
OLD | NEW |