Chromium Code Reviews| 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 SetStateDeprecated(), SetUniqueId(), or | |
| 40 // // UpdateCredentials() on the Invalidator implementation. Should block | |
| 41 // // until the effects of the 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 OnNotificationsEnabled() to be called on all | |
| 50 // // observers of the Invalidator implementation. | |
| 51 // void TriggerOnNotificationsEnabled() { | |
| 52 // ... | |
| 53 // } | |
| 54 // | |
| 55 // // Should cause OnIncomingNotification() to be called on all | |
| 56 // // observers of the Invalidator implementation with the given | |
| 57 // // parameters. | |
| 58 // void TriggerOnIncomingNotification(const ObjectIdStateMap& id_state_map, | |
| 59 // IncomingNotificationSource source) { | |
| 60 // ... | |
| 61 // } | |
| 62 // | |
| 63 // // Should cause OnNotificationsDisabled() to be called on all | |
| 64 // // observers of the Invalidator implementation with the given | |
| 65 // // parameters. | |
| 66 // void TriggerOnNotificationsDisabled( | |
| 67 // NotificationsDisabledReason reason) { | |
| 68 // ... | |
| 69 // } | |
| 70 // | |
| 71 // // Returns whether or not the notifier handles storing the old | |
| 72 // // (deprecated) notifier state. | |
| 73 // static bool InvalidatorHandlesDeprecatedState() { | |
| 74 // return false; | |
| 75 // } | |
| 76 // }; | |
| 77 // | |
| 78 // The InvalidatorTest test harness will have a member variable of | |
| 79 // this delegate type and will call its functions in the various | |
| 80 // tests. | |
| 81 // | |
| 82 // Then you simply #include this file as well as gtest.h and add the | |
| 83 // following statement to my_sync_notifier_unittest.cc: | |
| 84 // | |
| 85 // INSTANTIATE_TYPED_TEST_CASE_P( | |
| 86 // MyInvalidator, InvalidatorTest, MyInvalidatorTestDelegate); | |
| 87 // | |
| 88 // Easy! | |
| 89 | |
| 90 #ifndef SYNC_NOTIFIER_INVALIDATOR_TEST_TEMPLATE_H_ | |
| 91 #define SYNC_NOTIFIER_INVALIDATOR_TEST_TEMPLATE_H_ | |
| 92 | |
| 93 #include "google/cacheinvalidation/include/types.h" | |
| 94 #include "google/cacheinvalidation/types.pb.h" | |
| 95 #include "sync/notifier/fake_invalidation_handler.h" | |
| 96 #include "sync/notifier/fake_invalidation_state_tracker.h" | |
| 97 #include "sync/notifier/invalidator.h" | |
| 98 #include "sync/notifier/object_id_state_map.h" | |
| 99 #include "sync/notifier/object_id_state_map_test_util.h" | |
| 100 #include "testing/gtest/include/gtest/gtest.h" | |
| 101 | |
| 102 namespace syncer { | |
| 103 | |
| 104 template <typename InvalidatorTestDelegate> | |
| 105 class InvalidatorTest : public testing::Test { | |
| 106 protected: | |
| 107 InvalidatorTest() | |
| 108 : id1(ipc::invalidation::ObjectSource::TEST, "a"), | |
| 109 id2(ipc::invalidation::ObjectSource::TEST, "b"), | |
| 110 id3(ipc::invalidation::ObjectSource::TEST, "c"), | |
| 111 id4(ipc::invalidation::ObjectSource::TEST, "d") { | |
| 112 } | |
| 113 | |
| 114 Invalidator* CreateAndInitializeInvalidator() { | |
| 115 this->delegate_.CreateInvalidator("fake_initial_state", | |
|
Nicolas Zea
2012/08/29 23:41:05
why are all the "this->"'s necessary?
akalin
2012/08/30 22:20:38
Basically because they're type-parametrized tests
| |
| 116 this->fake_tracker_.AsWeakPtr()); | |
| 117 Invalidator* const invalidator = this->delegate_.GetInvalidator(); | |
| 118 | |
| 119 // TODO(tim): This call should be a no-op. Remove once bug 124140 and | |
|
Nicolas Zea
2012/08/29 23:41:05
this bug is fixed, do we still need the call aroun
akalin
2012/08/30 22:20:38
Actually, I think we still can't remove it yet? I
| |
| 120 // associated issues are fixed. | |
| 121 invalidator->SetStateDeprecated("fake_state"); | |
| 122 this->delegate_.WaitForInvalidator(); | |
| 123 // We don't expect |fake_tracker_|'s state to change, as we | |
| 124 // initialized with non-empty initial_invalidation_state above. | |
| 125 EXPECT_TRUE(this->fake_tracker_.GetInvalidationState().empty()); | |
| 126 invalidator->SetUniqueId("fake_id"); | |
| 127 this->delegate_.WaitForInvalidator(); | |
| 128 invalidator->UpdateCredentials("foo@bar.com", "fake_token"); | |
| 129 this->delegate_.WaitForInvalidator(); | |
| 130 | |
| 131 return invalidator; | |
| 132 } | |
| 133 | |
| 134 FakeInvalidationStateTracker fake_tracker_; | |
| 135 InvalidatorTestDelegate delegate_; | |
| 136 | |
| 137 const invalidation::ObjectId id1; | |
| 138 const invalidation::ObjectId id2; | |
| 139 const invalidation::ObjectId id3; | |
| 140 const invalidation::ObjectId id4; | |
| 141 }; | |
| 142 | |
| 143 TYPED_TEST_CASE_P(InvalidatorTest); | |
| 144 | |
| 145 // Initialize the invalidator, register a handler, register some IDs for that | |
| 146 // handler, and then unregister the handler, dispatching invalidations in | |
| 147 // between. The handler should only see invalidations when its registered and | |
| 148 // its IDs are registered. | |
| 149 TYPED_TEST_P(InvalidatorTest, Basic) { | |
| 150 Invalidator* const invalidator = this->CreateAndInitializeInvalidator(); | |
| 151 | |
| 152 FakeInvalidationHandler handler; | |
| 153 | |
| 154 invalidator->RegisterHandler(&handler); | |
| 155 | |
| 156 ObjectIdStateMap states; | |
| 157 states[this->id1].payload = "1"; | |
| 158 states[this->id2].payload = "2"; | |
| 159 states[this->id3].payload = "3"; | |
| 160 | |
| 161 // Should be ignored since no IDs are registered to |handler|. | |
| 162 this->delegate_.TriggerOnIncomingNotification(states, REMOTE_NOTIFICATION); | |
| 163 EXPECT_EQ(0, handler.GetNotificationCount()); | |
| 164 | |
| 165 ObjectIdSet ids; | |
| 166 ids.insert(this->id1); | |
| 167 ids.insert(this->id2); | |
| 168 invalidator->UpdateRegisteredIds(&handler, ids); | |
| 169 | |
| 170 this->delegate_.TriggerOnNotificationsEnabled(); | |
| 171 EXPECT_EQ(NO_NOTIFICATION_ERROR, | |
| 172 handler.GetNotificationsDisabledReason()); | |
| 173 | |
| 174 ObjectIdStateMap expected_states; | |
| 175 expected_states[this->id1].payload = "1"; | |
| 176 expected_states[this->id2].payload = "2"; | |
| 177 | |
| 178 this->delegate_.TriggerOnIncomingNotification(states, REMOTE_NOTIFICATION); | |
| 179 EXPECT_EQ(1, handler.GetNotificationCount()); | |
| 180 EXPECT_THAT( | |
| 181 expected_states, | |
| 182 Eq(handler.GetLastNotificationIdStateMap())); | |
| 183 EXPECT_EQ(REMOTE_NOTIFICATION, handler.GetLastNotificationSource()); | |
| 184 | |
| 185 ids.erase(this->id1); | |
| 186 ids.insert(this->id3); | |
| 187 invalidator->UpdateRegisteredIds(&handler, ids); | |
| 188 | |
| 189 expected_states.erase(this->id1); | |
| 190 expected_states[this->id3].payload = "3"; | |
| 191 | |
| 192 // Removed object IDs should not be notified, newly-added ones should. | |
| 193 this->delegate_.TriggerOnIncomingNotification(states, REMOTE_NOTIFICATION); | |
| 194 EXPECT_EQ(2, handler.GetNotificationCount()); | |
| 195 EXPECT_THAT( | |
| 196 expected_states, | |
| 197 Eq(handler.GetLastNotificationIdStateMap())); | |
| 198 EXPECT_EQ(REMOTE_NOTIFICATION, handler.GetLastNotificationSource()); | |
| 199 | |
| 200 this->delegate_.TriggerOnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR); | |
| 201 EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR, | |
| 202 handler.GetNotificationsDisabledReason()); | |
| 203 | |
| 204 this->delegate_.TriggerOnNotificationsDisabled( | |
| 205 NOTIFICATION_CREDENTIALS_REJECTED); | |
| 206 EXPECT_EQ(NOTIFICATION_CREDENTIALS_REJECTED, | |
| 207 handler.GetNotificationsDisabledReason()); | |
| 208 | |
| 209 invalidator->UnregisterHandler(&handler); | |
| 210 | |
| 211 // Should be ignored since |handler| isn't registered anymore. | |
| 212 this->delegate_.TriggerOnIncomingNotification(states, REMOTE_NOTIFICATION); | |
| 213 EXPECT_EQ(2, handler.GetNotificationCount()); | |
| 214 } | |
| 215 | |
| 216 // Register handlers and some IDs for those handlers, register a handler with | |
| 217 // no IDs, and register a handler with some IDs but unregister it. Then, | |
| 218 // dispatch some notifications and invalidations. Handlers that are registered | |
| 219 // should get notifications, and the ones that have registered IDs should | |
| 220 // receive invalidations for those IDs. | |
| 221 TYPED_TEST_P(InvalidatorTest, MultipleHandlers) { | |
| 222 Invalidator* const invalidator = this->CreateAndInitializeInvalidator(); | |
| 223 | |
| 224 FakeInvalidationHandler handler1; | |
| 225 FakeInvalidationHandler handler2; | |
| 226 FakeInvalidationHandler handler3; | |
| 227 FakeInvalidationHandler handler4; | |
| 228 | |
| 229 invalidator->RegisterHandler(&handler1); | |
| 230 invalidator->RegisterHandler(&handler2); | |
| 231 invalidator->RegisterHandler(&handler3); | |
| 232 invalidator->RegisterHandler(&handler4); | |
| 233 | |
| 234 { | |
| 235 ObjectIdSet ids; | |
| 236 ids.insert(this->id1); | |
| 237 ids.insert(this->id2); | |
| 238 invalidator->UpdateRegisteredIds(&handler1, ids); | |
| 239 } | |
| 240 | |
| 241 { | |
| 242 ObjectIdSet ids; | |
| 243 ids.insert(this->id3); | |
| 244 invalidator->UpdateRegisteredIds(&handler2, ids); | |
| 245 } | |
| 246 | |
| 247 // Don't register any IDs for handler3. | |
| 248 | |
| 249 { | |
| 250 ObjectIdSet ids; | |
| 251 ids.insert(this->id4); | |
| 252 invalidator->UpdateRegisteredIds(&handler4, ids); | |
| 253 } | |
| 254 | |
| 255 invalidator->UnregisterHandler(&handler4); | |
| 256 | |
| 257 this->delegate_.TriggerOnNotificationsEnabled(); | |
| 258 EXPECT_EQ(NO_NOTIFICATION_ERROR, | |
| 259 handler1.GetNotificationsDisabledReason()); | |
| 260 EXPECT_EQ(NO_NOTIFICATION_ERROR, | |
| 261 handler2.GetNotificationsDisabledReason()); | |
| 262 EXPECT_EQ(NO_NOTIFICATION_ERROR, | |
| 263 handler3.GetNotificationsDisabledReason()); | |
| 264 EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR, | |
| 265 handler4.GetNotificationsDisabledReason()); | |
| 266 | |
| 267 { | |
| 268 ObjectIdStateMap states; | |
| 269 states[this->id1].payload = "1"; | |
| 270 states[this->id2].payload = "2"; | |
| 271 states[this->id3].payload = "3"; | |
| 272 states[this->id4].payload = "4"; | |
| 273 this->delegate_.TriggerOnIncomingNotification(states, REMOTE_NOTIFICATION); | |
| 274 | |
| 275 ObjectIdStateMap expected_states; | |
| 276 expected_states[this->id1].payload = "1"; | |
| 277 expected_states[this->id2].payload = "2"; | |
| 278 | |
| 279 EXPECT_EQ(1, handler1.GetNotificationCount()); | |
| 280 EXPECT_THAT( | |
| 281 expected_states, | |
| 282 Eq(handler1.GetLastNotificationIdStateMap())); | |
| 283 EXPECT_EQ(REMOTE_NOTIFICATION, handler1.GetLastNotificationSource()); | |
| 284 | |
| 285 expected_states.clear(); | |
| 286 expected_states[this->id3].payload = "3"; | |
| 287 | |
| 288 EXPECT_EQ(1, handler2.GetNotificationCount()); | |
| 289 EXPECT_THAT( | |
| 290 expected_states, | |
| 291 Eq(handler2.GetLastNotificationIdStateMap())); | |
| 292 EXPECT_EQ(REMOTE_NOTIFICATION, handler2.GetLastNotificationSource()); | |
| 293 | |
| 294 EXPECT_EQ(0, handler3.GetNotificationCount()); | |
| 295 EXPECT_EQ(0, handler4.GetNotificationCount()); | |
| 296 } | |
| 297 | |
| 298 this->delegate_.TriggerOnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR); | |
| 299 EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR, | |
| 300 handler1.GetNotificationsDisabledReason()); | |
| 301 EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR, | |
| 302 handler2.GetNotificationsDisabledReason()); | |
| 303 EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR, | |
| 304 handler3.GetNotificationsDisabledReason()); | |
| 305 EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR, | |
| 306 handler4.GetNotificationsDisabledReason()); | |
| 307 } | |
| 308 | |
| 309 // Make sure that passing an empty set to UpdateRegisteredIds clears the | |
| 310 // corresponding entries for the handler. | |
| 311 TYPED_TEST_P(InvalidatorTest, EmptySetUnregisters) { | |
| 312 Invalidator* const invalidator = this->CreateAndInitializeInvalidator(); | |
| 313 | |
| 314 FakeInvalidationHandler handler1; | |
| 315 | |
| 316 // Control observer. | |
| 317 FakeInvalidationHandler handler2; | |
| 318 | |
| 319 invalidator->RegisterHandler(&handler1); | |
| 320 invalidator->RegisterHandler(&handler2); | |
| 321 | |
| 322 { | |
| 323 ObjectIdSet ids; | |
| 324 ids.insert(this->id1); | |
| 325 ids.insert(this->id2); | |
| 326 invalidator->UpdateRegisteredIds(&handler1, ids); | |
| 327 } | |
| 328 | |
| 329 { | |
| 330 ObjectIdSet ids; | |
| 331 ids.insert(this->id3); | |
| 332 invalidator->UpdateRegisteredIds(&handler2, ids); | |
| 333 } | |
| 334 | |
| 335 // Unregister the IDs for the first observer. It should not receive any | |
| 336 // further invalidations. | |
| 337 invalidator->UpdateRegisteredIds(&handler1, ObjectIdSet()); | |
| 338 | |
| 339 this->delegate_.TriggerOnNotificationsEnabled(); | |
| 340 EXPECT_EQ(NO_NOTIFICATION_ERROR, | |
| 341 handler1.GetNotificationsDisabledReason()); | |
| 342 EXPECT_EQ(NO_NOTIFICATION_ERROR, | |
| 343 handler2.GetNotificationsDisabledReason()); | |
| 344 | |
| 345 { | |
| 346 ObjectIdStateMap states; | |
| 347 states[this->id1].payload = "1"; | |
| 348 states[this->id2].payload = "2"; | |
| 349 states[this->id3].payload = "3"; | |
| 350 this->delegate_.TriggerOnIncomingNotification(states, REMOTE_NOTIFICATION); | |
| 351 EXPECT_EQ(0, handler1.GetNotificationCount()); | |
| 352 EXPECT_EQ(1, handler2.GetNotificationCount()); | |
| 353 } | |
| 354 | |
| 355 this->delegate_.TriggerOnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR); | |
| 356 EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR, | |
| 357 handler1.GetNotificationsDisabledReason()); | |
| 358 EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR, | |
| 359 handler2.GetNotificationsDisabledReason()); | |
| 360 } | |
| 361 | |
| 362 // Initialize the invalidator with an empty initial state. Call the deprecated | |
| 363 // state setter function a number of times, destroying and re-creating the | |
| 364 // invalidator in between. Only the first one should take effect (i.e., state | |
| 365 // migration should only happen once). | |
| 366 TYPED_TEST_P(InvalidatorTest, MigrateState) { | |
| 367 if (!this->delegate_.InvalidatorHandlesDeprecatedState()) { | |
| 368 DLOG(INFO) << "This Invalidator doesn't handle deprecated state; " | |
| 369 << "skipping"; | |
| 370 return; | |
| 371 } | |
| 372 | |
| 373 this->delegate_.CreateInvalidator(std::string(), | |
| 374 this->fake_tracker_.AsWeakPtr()); | |
|
Nicolas Zea
2012/08/29 23:41:05
fix indent
akalin
2012/08/30 22:20:38
Done.
| |
| 375 Invalidator* invalidator = this->delegate_.GetInvalidator(); | |
| 376 | |
| 377 invalidator->SetStateDeprecated("fake_state"); | |
| 378 this->delegate_.WaitForInvalidator(); | |
| 379 EXPECT_EQ("fake_state", this->fake_tracker_.GetInvalidationState()); | |
| 380 | |
| 381 // Should do nothing. | |
| 382 invalidator->SetStateDeprecated("spurious_fake_state"); | |
| 383 this->delegate_.WaitForInvalidator(); | |
| 384 EXPECT_EQ("fake_state", this->fake_tracker_.GetInvalidationState()); | |
| 385 | |
| 386 // Pretend that Chrome has shut down. | |
| 387 this->delegate_.DestroyInvalidator(); | |
| 388 this->delegate_.CreateInvalidator("fake_state", | |
| 389 this->fake_tracker_.AsWeakPtr()); | |
| 390 invalidator = this->delegate_.GetInvalidator(); | |
| 391 | |
| 392 // Should do nothing. | |
| 393 invalidator->SetStateDeprecated("more_spurious_fake_state"); | |
| 394 this->delegate_.WaitForInvalidator(); | |
| 395 EXPECT_EQ("fake_state", this->fake_tracker_.GetInvalidationState()); | |
| 396 } | |
| 397 | |
| 398 REGISTER_TYPED_TEST_CASE_P(InvalidatorTest, | |
| 399 Basic, MultipleHandlers, EmptySetUnregisters, | |
| 400 MigrateState); | |
| 401 | |
| 402 } // namespace syncer | |
| 403 | |
| 404 #endif // SYNC_NOTIFIER_INVALIDATOR_TEST_TEMPLATE_H_ | |
| OLD | NEW |