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 |