| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 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 InvalidationFrontend 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 MyInvalidationFrontend. Then you need to define a | |
| 10 // class called MyInvalidationFrontendTestDelegate in | |
| 11 // my_invalidation_frontend_unittest.cc like this: | |
| 12 // | |
| 13 // class MyInvalidationFrontendTestDelegate { | |
| 14 // public: | |
| 15 // MyInvalidationFrontendTestDelegate() ... | |
| 16 // | |
| 17 // ~MyInvalidationFrontendTestDelegate() { | |
| 18 // // DestroyInvalidator() may not be explicitly called by tests. | |
| 19 // DestroyInvalidator(); | |
| 20 // } | |
| 21 // | |
| 22 // // Create the InvalidationFrontend implementation with the given params. | |
| 23 // void CreateInvalidationFrontend() { | |
| 24 // ... | |
| 25 // } | |
| 26 // | |
| 27 // // Should return the InvalidationFrontend implementation. Only called | |
| 28 // // after CreateInvalidator and before DestroyInvalidator. | |
| 29 // MyInvalidationFrontend* GetInvalidationFrontend() { | |
| 30 // ... | |
| 31 // } | |
| 32 // | |
| 33 // // Destroy the InvalidationFrontend implementation. | |
| 34 // void DestroyInvalidationFrontend() { | |
| 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 InvalidationFrontend 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 InvalidationFrontend implementation with the given | |
| 50 // // parameters. | |
| 51 // void TriggerOnIncomingInvalidation( | |
| 52 // const ObjectIdInvalidationMap& invalidation_map) { | |
| 53 // ... | |
| 54 // } | |
| 55 // }; | |
| 56 // | |
| 57 // The InvalidationFrontendTest 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 // MyInvalidationFrontend, | |
| 66 // InvalidationFrontendTest, | |
| 67 // MyInvalidatorTestDelegate); | |
| 68 // | |
| 69 // Easy! | |
| 70 | |
| 71 #ifndef CHROME_BROWSER_INVALIDATION_INVALIDATION_FRONTEND_TEST_TEMPLATE_H_ | |
| 72 #define CHROME_BROWSER_INVALIDATION_INVALIDATION_FRONTEND_TEST_TEMPLATE_H_ | |
| 73 | |
| 74 #include "base/basictypes.h" | |
| 75 #include "base/compiler_specific.h" | |
| 76 #include "chrome/browser/invalidation/invalidation_frontend.h" | |
| 77 #include "google/cacheinvalidation/include/types.h" | |
| 78 #include "google/cacheinvalidation/types.pb.h" | |
| 79 #include "sync/notifier/fake_invalidation_handler.h" | |
| 80 #include "sync/notifier/object_id_invalidation_map.h" | |
| 81 #include "sync/notifier/object_id_invalidation_map_test_util.h" | |
| 82 #include "testing/gtest/include/gtest/gtest.h" | |
| 83 | |
| 84 template <typename InvalidatorTestDelegate> | |
| 85 class InvalidationFrontendTest : public testing::Test { | |
| 86 protected: | |
| 87 // Note: The IDs defined below must be valid. Otherwise they won't make it | |
| 88 // through the round-trip to ModelTypeInvalidationMap and back that the | |
| 89 // AndroidInvalidation test requires. | |
| 90 InvalidationFrontendTest() | |
| 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_SYNC, "EXPERIMENTS") { | |
| 95 } | |
| 96 | |
| 97 invalidation::InvalidationFrontend* | |
| 98 CreateAndInitializeInvalidationFrontend() { | |
| 99 this->delegate_.CreateInvalidationFrontend(); | |
| 100 return this->delegate_.GetInvalidationFrontend(); | |
| 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(InvalidationFrontendTest); | |
| 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(InvalidationFrontendTest, Basic) { | |
| 118 invalidation::InvalidationFrontend* const invalidator = | |
| 119 this->CreateAndInitializeInvalidationFrontend(); | |
| 120 | |
| 121 syncer::FakeInvalidationHandler handler; | |
| 122 | |
| 123 invalidator->RegisterInvalidationHandler(&handler); | |
| 124 | |
| 125 syncer::ObjectIdInvalidationMap states; | |
| 126 states[this->id1].payload = "1"; | |
| 127 states[this->id2].payload = "2"; | |
| 128 states[this->id3].payload = "3"; | |
| 129 | |
| 130 // Should be ignored since no IDs are registered to |handler|. | |
| 131 this->delegate_.TriggerOnIncomingInvalidation(states); | |
| 132 EXPECT_EQ(0, handler.GetInvalidationCount()); | |
| 133 | |
| 134 syncer::ObjectIdSet ids; | |
| 135 ids.insert(this->id1); | |
| 136 ids.insert(this->id2); | |
| 137 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_states; | |
| 144 expected_states[this->id1].payload = "1"; | |
| 145 expected_states[this->id2].payload = "2"; | |
| 146 | |
| 147 this->delegate_.TriggerOnIncomingInvalidation(states); | |
| 148 EXPECT_EQ(1, handler.GetInvalidationCount()); | |
| 149 EXPECT_THAT(expected_states, Eq(handler.GetLastInvalidationMap())); | |
| 150 | |
| 151 ids.erase(this->id1); | |
| 152 ids.insert(this->id3); | |
| 153 invalidator->UpdateRegisteredInvalidationIds(&handler, ids); | |
| 154 | |
| 155 expected_states.erase(this->id1); | |
| 156 expected_states[this->id3].payload = "3"; | |
| 157 | |
| 158 // Removed object IDs should not be notified, newly-added ones should. | |
| 159 this->delegate_.TriggerOnIncomingInvalidation(states); | |
| 160 EXPECT_EQ(2, handler.GetInvalidationCount()); | |
| 161 EXPECT_THAT(expected_states, Eq(handler.GetLastInvalidationMap())); | |
| 162 | |
| 163 this->delegate_.TriggerOnInvalidatorStateChange( | |
| 164 syncer::TRANSIENT_INVALIDATION_ERROR); | |
| 165 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR, | |
| 166 handler.GetInvalidatorState()); | |
| 167 | |
| 168 this->delegate_.TriggerOnInvalidatorStateChange( | |
| 169 syncer::INVALIDATION_CREDENTIALS_REJECTED); | |
| 170 EXPECT_EQ(syncer::INVALIDATION_CREDENTIALS_REJECTED, | |
| 171 handler.GetInvalidatorState()); | |
| 172 | |
| 173 invalidator->UnregisterInvalidationHandler(&handler); | |
| 174 | |
| 175 // Should be ignored since |handler| isn't registered anymore. | |
| 176 this->delegate_.TriggerOnIncomingInvalidation(states); | |
| 177 EXPECT_EQ(2, handler.GetInvalidationCount()); | |
| 178 } | |
| 179 | |
| 180 // Register handlers and some IDs for those handlers, register a handler with | |
| 181 // no IDs, and register a handler with some IDs but unregister it. Then, | |
| 182 // dispatch some invalidations and invalidations. Handlers that are registered | |
| 183 // should get invalidations, and the ones that have registered IDs should | |
| 184 // receive invalidations for those IDs. | |
| 185 TYPED_TEST_P(InvalidationFrontendTest, MultipleHandlers) { | |
| 186 invalidation::InvalidationFrontend* const invalidator = | |
| 187 this->CreateAndInitializeInvalidationFrontend(); | |
| 188 | |
| 189 syncer::FakeInvalidationHandler handler1; | |
| 190 syncer::FakeInvalidationHandler handler2; | |
| 191 syncer::FakeInvalidationHandler handler3; | |
| 192 syncer::FakeInvalidationHandler handler4; | |
| 193 | |
| 194 invalidator->RegisterInvalidationHandler(&handler1); | |
| 195 invalidator->RegisterInvalidationHandler(&handler2); | |
| 196 invalidator->RegisterInvalidationHandler(&handler3); | |
| 197 invalidator->RegisterInvalidationHandler(&handler4); | |
| 198 | |
| 199 { | |
| 200 syncer::ObjectIdSet ids; | |
| 201 ids.insert(this->id1); | |
| 202 ids.insert(this->id2); | |
| 203 invalidator->UpdateRegisteredInvalidationIds(&handler1, ids); | |
| 204 } | |
| 205 | |
| 206 { | |
| 207 syncer::ObjectIdSet ids; | |
| 208 ids.insert(this->id3); | |
| 209 invalidator->UpdateRegisteredInvalidationIds(&handler2, ids); | |
| 210 } | |
| 211 | |
| 212 // Don't register any IDs for handler3. | |
| 213 | |
| 214 { | |
| 215 syncer::ObjectIdSet ids; | |
| 216 ids.insert(this->id4); | |
| 217 invalidator->UpdateRegisteredInvalidationIds(&handler4, ids); | |
| 218 } | |
| 219 | |
| 220 invalidator->UnregisterInvalidationHandler(&handler4); | |
| 221 | |
| 222 this->delegate_.TriggerOnInvalidatorStateChange( | |
| 223 syncer::INVALIDATIONS_ENABLED); | |
| 224 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler1.GetInvalidatorState()); | |
| 225 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler2.GetInvalidatorState()); | |
| 226 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler3.GetInvalidatorState()); | |
| 227 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR, | |
| 228 handler4.GetInvalidatorState()); | |
| 229 | |
| 230 { | |
| 231 syncer::ObjectIdInvalidationMap states; | |
| 232 states[this->id1].payload = "1"; | |
| 233 states[this->id2].payload = "2"; | |
| 234 states[this->id3].payload = "3"; | |
| 235 states[this->id4].payload = "4"; | |
| 236 this->delegate_.TriggerOnIncomingInvalidation(states); | |
| 237 | |
| 238 syncer::ObjectIdInvalidationMap expected_states; | |
| 239 expected_states[this->id1].payload = "1"; | |
| 240 expected_states[this->id2].payload = "2"; | |
| 241 | |
| 242 EXPECT_EQ(1, handler1.GetInvalidationCount()); | |
| 243 EXPECT_THAT(expected_states, Eq(handler1.GetLastInvalidationMap())); | |
| 244 | |
| 245 expected_states.clear(); | |
| 246 expected_states[this->id3].payload = "3"; | |
| 247 | |
| 248 EXPECT_EQ(1, handler2.GetInvalidationCount()); | |
| 249 EXPECT_THAT(expected_states, Eq(handler2.GetLastInvalidationMap())); | |
| 250 | |
| 251 EXPECT_EQ(0, handler3.GetInvalidationCount()); | |
| 252 EXPECT_EQ(0, handler4.GetInvalidationCount()); | |
| 253 } | |
| 254 | |
| 255 this->delegate_.TriggerOnInvalidatorStateChange( | |
| 256 syncer::TRANSIENT_INVALIDATION_ERROR); | |
| 257 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR, | |
| 258 handler1.GetInvalidatorState()); | |
| 259 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR, | |
| 260 handler2.GetInvalidatorState()); | |
| 261 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR, | |
| 262 handler3.GetInvalidatorState()); | |
| 263 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR, | |
| 264 handler4.GetInvalidatorState()); | |
| 265 | |
| 266 invalidator->UnregisterInvalidationHandler(&handler3); | |
| 267 invalidator->UnregisterInvalidationHandler(&handler2); | |
| 268 invalidator->UnregisterInvalidationHandler(&handler1); | |
| 269 } | |
| 270 | |
| 271 // Make sure that passing an empty set to UpdateRegisteredInvalidationIds clears | |
| 272 // the corresponding entries for the handler. | |
| 273 TYPED_TEST_P(InvalidationFrontendTest, EmptySetUnregisters) { | |
| 274 invalidation::InvalidationFrontend* const invalidator = | |
| 275 this->CreateAndInitializeInvalidationFrontend(); | |
| 276 | |
| 277 syncer::FakeInvalidationHandler handler1; | |
| 278 | |
| 279 // Control observer. | |
| 280 syncer::FakeInvalidationHandler handler2; | |
| 281 | |
| 282 invalidator->RegisterInvalidationHandler(&handler1); | |
| 283 invalidator->RegisterInvalidationHandler(&handler2); | |
| 284 | |
| 285 { | |
| 286 syncer::ObjectIdSet ids; | |
| 287 ids.insert(this->id1); | |
| 288 ids.insert(this->id2); | |
| 289 invalidator->UpdateRegisteredInvalidationIds(&handler1, ids); | |
| 290 } | |
| 291 | |
| 292 { | |
| 293 syncer::ObjectIdSet ids; | |
| 294 ids.insert(this->id3); | |
| 295 invalidator->UpdateRegisteredInvalidationIds(&handler2, ids); | |
| 296 } | |
| 297 | |
| 298 // Unregister the IDs for the first observer. It should not receive any | |
| 299 // further invalidations. | |
| 300 invalidator->UpdateRegisteredInvalidationIds(&handler1, | |
| 301 syncer::ObjectIdSet()); | |
| 302 | |
| 303 this->delegate_.TriggerOnInvalidatorStateChange( | |
| 304 syncer::INVALIDATIONS_ENABLED); | |
| 305 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler1.GetInvalidatorState()); | |
| 306 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler2.GetInvalidatorState()); | |
| 307 | |
| 308 { | |
| 309 syncer::ObjectIdInvalidationMap states; | |
| 310 states[this->id1].payload = "1"; | |
| 311 states[this->id2].payload = "2"; | |
| 312 states[this->id3].payload = "3"; | |
| 313 this->delegate_.TriggerOnIncomingInvalidation(states); | |
| 314 EXPECT_EQ(0, handler1.GetInvalidationCount()); | |
| 315 EXPECT_EQ(1, handler2.GetInvalidationCount()); | |
| 316 } | |
| 317 | |
| 318 this->delegate_.TriggerOnInvalidatorStateChange( | |
| 319 syncer::TRANSIENT_INVALIDATION_ERROR); | |
| 320 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR, | |
| 321 handler1.GetInvalidatorState()); | |
| 322 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR, | |
| 323 handler2.GetInvalidatorState()); | |
| 324 | |
| 325 invalidator->UnregisterInvalidationHandler(&handler2); | |
| 326 invalidator->UnregisterInvalidationHandler(&handler1); | |
| 327 } | |
| 328 | |
| 329 namespace internal { | |
| 330 | |
| 331 // A FakeInvalidationHandler that is "bound" to a specific | |
| 332 // InvalidationFrontend. This is for cross-referencing state information with | |
| 333 // the bound InvalidationFrontend. | |
| 334 class BoundFakeInvalidationHandler : public syncer::FakeInvalidationHandler { | |
| 335 public: | |
| 336 explicit BoundFakeInvalidationHandler( | |
| 337 const invalidation::InvalidationFrontend& invalidator); | |
| 338 virtual ~BoundFakeInvalidationHandler(); | |
| 339 | |
| 340 // Returns the last return value of GetInvalidatorState() on the | |
| 341 // bound invalidator from the last time the invalidator state | |
| 342 // changed. | |
| 343 syncer::InvalidatorState GetLastRetrievedState() const; | |
| 344 | |
| 345 // InvalidationHandler implementation. | |
| 346 virtual void OnInvalidatorStateChange( | |
| 347 syncer::InvalidatorState state) OVERRIDE; | |
| 348 | |
| 349 private: | |
| 350 const invalidation::InvalidationFrontend& invalidator_; | |
| 351 syncer::InvalidatorState last_retrieved_state_; | |
| 352 | |
| 353 DISALLOW_COPY_AND_ASSIGN(BoundFakeInvalidationHandler); | |
| 354 }; | |
| 355 | |
| 356 } // namespace internal | |
| 357 | |
| 358 TYPED_TEST_P(InvalidationFrontendTest, GetInvalidatorStateAlwaysCurrent) { | |
| 359 invalidation::InvalidationFrontend* const invalidator = | |
| 360 this->CreateAndInitializeInvalidationFrontend(); | |
| 361 | |
| 362 internal::BoundFakeInvalidationHandler handler(*invalidator); | |
| 363 invalidator->RegisterInvalidationHandler(&handler); | |
| 364 | |
| 365 this->delegate_.TriggerOnInvalidatorStateChange( | |
| 366 syncer::INVALIDATIONS_ENABLED); | |
| 367 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler.GetInvalidatorState()); | |
| 368 EXPECT_EQ(syncer::INVALIDATIONS_ENABLED, handler.GetLastRetrievedState()); | |
| 369 | |
| 370 this->delegate_.TriggerOnInvalidatorStateChange( | |
| 371 syncer::TRANSIENT_INVALIDATION_ERROR); | |
| 372 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR, | |
| 373 handler.GetInvalidatorState()); | |
| 374 EXPECT_EQ(syncer::TRANSIENT_INVALIDATION_ERROR, | |
| 375 handler.GetLastRetrievedState()); | |
| 376 | |
| 377 invalidator->UnregisterInvalidationHandler(&handler); | |
| 378 } | |
| 379 | |
| 380 REGISTER_TYPED_TEST_CASE_P(InvalidationFrontendTest, | |
| 381 Basic, MultipleHandlers, EmptySetUnregisters, | |
| 382 GetInvalidatorStateAlwaysCurrent); | |
| 383 | |
| 384 #endif // CHROME_BROWSER_INVALIDATION_INVALIDATION_FRONTEND_TEST_TEMPLATE_H_ | |
| OLD | NEW |