| OLD | NEW |
| (Empty) |
| 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 "components/invalidation/fake_invalidation_handler.h" | |
| 77 #include "components/invalidation/invalidation_service.h" | |
| 78 #include "content/public/test/test_browser_thread_bundle.h" | |
| 79 #include "google/cacheinvalidation/include/types.h" | |
| 80 #include "google/cacheinvalidation/types.pb.h" | |
| 81 #include "sync/internal_api/public/base/ack_handle.h" | |
| 82 #include "sync/internal_api/public/base/invalidation.h" | |
| 83 #include "sync/internal_api/public/base/object_id_invalidation_map_test_util.h" | |
| 84 #include "sync/notifier/object_id_invalidation_map.h" | |
| 85 #include "testing/gtest/include/gtest/gtest.h" | |
| 86 | |
| 87 template <typename InvalidatorTestDelegate> | |
| 88 class InvalidationServiceTest : public testing::Test { | |
| 89 protected: | |
| 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, | |
| 95 "PUSH_MESSAGE") { | |
| 96 } | |
| 97 | |
| 98 invalidation::InvalidationService* | |
| 99 CreateAndInitializeInvalidationService() { | |
| 100 this->delegate_.CreateInvalidationService(); | |
| 101 return this->delegate_.GetInvalidationService(); | |
| 102 } | |
| 103 | |
| 104 content::TestBrowserThreadBundle thread_bundle_; | |
| 105 InvalidatorTestDelegate delegate_; | |
| 106 | |
| 107 const invalidation::ObjectId id1; | |
| 108 const invalidation::ObjectId id2; | |
| 109 const invalidation::ObjectId id3; | |
| 110 const invalidation::ObjectId id4; | |
| 111 }; | |
| 112 | |
| 113 TYPED_TEST_CASE_P(InvalidationServiceTest); | |
| 114 | |
| 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(); | |
| 122 | |
| 123 syncer::FakeInvalidationHandler handler; | |
| 124 | |
| 125 invalidator->RegisterInvalidationHandler(&handler); | |
| 126 | |
| 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")); | |
| 131 | |
| 132 // Should be ignored since no IDs are registered to |handler|. | |
| 133 this->delegate_.TriggerOnIncomingInvalidation(invalidation_map); | |
| 134 EXPECT_EQ(0, handler.GetInvalidationCount()); | |
| 135 | |
| 136 syncer::ObjectIdSet ids; | |
| 137 ids.insert(this->id1); | |
| 138 ids.insert(this->id2); | |
| 139 invalidator->UpdateRegisteredInvalidationIds(&handler, ids); | |
| 140 | |
| 141 this->delegate_.TriggerOnInvalidatorStateChange( | |
| 142 syncer::INVALIDATIONS_ENABLED); | |
| 143 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler.GetInvalidatorState()); | |
| 144 | |
| 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")); | |
| 148 | |
| 149 this->delegate_.TriggerOnIncomingInvalidation(invalidation_map); | |
| 150 EXPECT_EQ(1, handler.GetInvalidationCount()); | |
| 151 EXPECT_THAT(expected_invalidations, Eq(handler.GetLastInvalidationMap())); | |
| 152 | |
| 153 ids.erase(this->id1); | |
| 154 ids.insert(this->id3); | |
| 155 invalidator->UpdateRegisteredInvalidationIds(&handler, ids); | |
| 156 | |
| 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")); | |
| 160 | |
| 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())); | |
| 165 | |
| 166 this->delegate_.TriggerOnInvalidatorStateChange( | |
| 167 syncer::TRANSIENT_INVALIDATION_ERROR); | |
| 168 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR, | |
| 169 handler.GetInvalidatorState()); | |
| 170 | |
| 171 this->delegate_.TriggerOnInvalidatorStateChange( | |
| 172 syncer::INVALIDATIONS_ENABLED); | |
| 173 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, | |
| 174 handler.GetInvalidatorState()); | |
| 175 | |
| 176 invalidator->UnregisterInvalidationHandler(&handler); | |
| 177 | |
| 178 // Should be ignored since |handler| isn't registered anymore. | |
| 179 this->delegate_.TriggerOnIncomingInvalidation(invalidation_map); | |
| 180 EXPECT_EQ(2, handler.GetInvalidationCount()); | |
| 181 } | |
| 182 | |
| 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(); | |
| 191 | |
| 192 syncer::FakeInvalidationHandler handler1; | |
| 193 syncer::FakeInvalidationHandler handler2; | |
| 194 syncer::FakeInvalidationHandler handler3; | |
| 195 syncer::FakeInvalidationHandler handler4; | |
| 196 | |
| 197 invalidator->RegisterInvalidationHandler(&handler1); | |
| 198 invalidator->RegisterInvalidationHandler(&handler2); | |
| 199 invalidator->RegisterInvalidationHandler(&handler3); | |
| 200 invalidator->RegisterInvalidationHandler(&handler4); | |
| 201 | |
| 202 { | |
| 203 syncer::ObjectIdSet ids; | |
| 204 ids.insert(this->id1); | |
| 205 ids.insert(this->id2); | |
| 206 invalidator->UpdateRegisteredInvalidationIds(&handler1, ids); | |
| 207 } | |
| 208 | |
| 209 { | |
| 210 syncer::ObjectIdSet ids; | |
| 211 ids.insert(this->id3); | |
| 212 invalidator->UpdateRegisteredInvalidationIds(&handler2, ids); | |
| 213 } | |
| 214 | |
| 215 // Don't register any IDs for handler3. | |
| 216 | |
| 217 { | |
| 218 syncer::ObjectIdSet ids; | |
| 219 ids.insert(this->id4); | |
| 220 invalidator->UpdateRegisteredInvalidationIds(&handler4, ids); | |
| 221 } | |
| 222 | |
| 223 invalidator->UnregisterInvalidationHandler(&handler4); | |
| 224 | |
| 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()); | |
| 232 | |
| 233 { | |
| 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); | |
| 240 | |
| 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")); | |
| 246 | |
| 247 EXPECT_EQ(1, handler1.GetInvalidationCount()); | |
| 248 EXPECT_THAT(expected_invalidations, Eq(handler1.GetLastInvalidationMap())); | |
| 249 | |
| 250 expected_invalidations = syncer::ObjectIdInvalidationMap(); | |
| 251 expected_invalidations.Insert( | |
| 252 syncer::Invalidation::Init(this->id3, 3, "3")); | |
| 253 | |
| 254 EXPECT_EQ(1, handler2.GetInvalidationCount()); | |
| 255 EXPECT_THAT(expected_invalidations, Eq(handler2.GetLastInvalidationMap())); | |
| 256 | |
| 257 EXPECT_EQ(0, handler3.GetInvalidationCount()); | |
| 258 EXPECT_EQ(0, handler4.GetInvalidationCount()); | |
| 259 } | |
| 260 | |
| 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()); | |
| 271 | |
| 272 invalidator->UnregisterInvalidationHandler(&handler3); | |
| 273 invalidator->UnregisterInvalidationHandler(&handler2); | |
| 274 invalidator->UnregisterInvalidationHandler(&handler1); | |
| 275 } | |
| 276 | |
| 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(); | |
| 282 | |
| 283 syncer::FakeInvalidationHandler handler1; | |
| 284 | |
| 285 // Control observer. | |
| 286 syncer::FakeInvalidationHandler handler2; | |
| 287 | |
| 288 invalidator->RegisterInvalidationHandler(&handler1); | |
| 289 invalidator->RegisterInvalidationHandler(&handler2); | |
| 290 | |
| 291 { | |
| 292 syncer::ObjectIdSet ids; | |
| 293 ids.insert(this->id1); | |
| 294 ids.insert(this->id2); | |
| 295 invalidator->UpdateRegisteredInvalidationIds(&handler1, ids); | |
| 296 } | |
| 297 | |
| 298 { | |
| 299 syncer::ObjectIdSet ids; | |
| 300 ids.insert(this->id3); | |
| 301 invalidator->UpdateRegisteredInvalidationIds(&handler2, ids); | |
| 302 } | |
| 303 | |
| 304 // Unregister the IDs for the first observer. It should not receive any | |
| 305 // further invalidations. | |
| 306 invalidator->UpdateRegisteredInvalidationIds(&handler1, | |
| 307 syncer::ObjectIdSet()); | |
| 308 | |
| 309 this->delegate_.TriggerOnInvalidatorStateChange( | |
| 310 syncer::INVALIDATIONS_ENABLED); | |
| 311 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler1.GetInvalidatorState()); | |
| 312 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler2.GetInvalidatorState()); | |
| 313 | |
| 314 { | |
| 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()); | |
| 322 } | |
| 323 | |
| 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()); | |
| 330 | |
| 331 invalidator->UnregisterInvalidationHandler(&handler2); | |
| 332 invalidator->UnregisterInvalidationHandler(&handler1); | |
| 333 } | |
| 334 | |
| 335 namespace internal { | |
| 336 | |
| 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 { | |
| 341 public: | |
| 342 explicit BoundFakeInvalidationHandler( | |
| 343 const invalidation::InvalidationService& invalidator); | |
| 344 virtual ~BoundFakeInvalidationHandler(); | |
| 345 | |
| 346 // Returns the last return value of GetInvalidatorState() on the | |
| 347 // bound invalidator from the last time the invalidator state | |
| 348 // changed. | |
| 349 syncer::InvalidatorState GetLastRetrievedState() const; | |
| 350 | |
| 351 // InvalidationHandler implementation. | |
| 352 virtual void OnInvalidatorStateChange( | |
| 353 syncer::InvalidatorState state) OVERRIDE; | |
| 354 | |
| 355 private: | |
| 356 const invalidation::InvalidationService& invalidator_; | |
| 357 syncer::InvalidatorState last_retrieved_state_; | |
| 358 | |
| 359 DISALLOW_COPY_AND_ASSIGN(BoundFakeInvalidationHandler); | |
| 360 }; | |
| 361 | |
| 362 } // namespace internal | |
| 363 | |
| 364 TYPED_TEST_P(InvalidationServiceTest, GetInvalidatorStateAlwaysCurrent) { | |
| 365 invalidation::InvalidationService* const invalidator = | |
| 366 this->CreateAndInitializeInvalidationService(); | |
| 367 | |
| 368 internal::BoundFakeInvalidationHandler handler(*invalidator); | |
| 369 invalidator->RegisterInvalidationHandler(&handler); | |
| 370 | |
| 371 this->delegate_.TriggerOnInvalidatorStateChange( | |
| 372 syncer::INVALIDATIONS_ENABLED); | |
| 373 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler.GetInvalidatorState()); | |
| 374 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler.GetLastRetrievedState()); | |
| 375 | |
| 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()); | |
| 382 | |
| 383 invalidator->UnregisterInvalidationHandler(&handler); | |
| 384 } | |
| 385 | |
| 386 REGISTER_TYPED_TEST_CASE_P(InvalidationServiceTest, | |
| 387 Basic, MultipleHandlers, EmptySetUnregisters, | |
| 388 GetInvalidatorStateAlwaysCurrent); | |
| 389 | |
| 390 #endif // CHROME_BROWSER_INVALIDATION_INVALIDATION_SERVICE_TEST_TEMPLATE_H_ | |
| OLD | NEW |