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 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 SetUniqueId(), or UpdateCredentials() on the 40 // // Invalidator implementation. Should block until the effects of the 41 // // 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 OnInvalidatorStateChange() to be called on all 50 // // observers of the Invalidator implementation with the given 51 // // parameters. 52 // void TriggerOnInvalidatorStateChange(InvalidatorState state) { 53 // ... 54 // } 55 // 56 // // Should cause OnIncomingInvalidation() to be called on all 57 // // observers of the Invalidator implementation with the given 58 // // parameters. 59 // void TriggerOnIncomingInvalidation( 60 // const ObjectIdInvalidationMap& invalidation_map) { 61 // ... 62 // } 63 // }; 64 // 65 // The InvalidatorTest test harness will have a member variable of 66 // this delegate type and will call its functions in the various 67 // tests. 68 // 69 // Then you simply #include this file as well as gtest.h and add the 70 // following statement to my_sync_notifier_unittest.cc: 71 // 72 // INSTANTIATE_TYPED_TEST_CASE_P( 73 // MyInvalidator, InvalidatorTest, MyInvalidatorTestDelegate); 74 // 75 // Easy! 76 77 #ifndef COMPONENTS_INVALIDATION_INVALIDATOR_TEST_TEMPLATE_H_ 78 #define COMPONENTS_INVALIDATION_INVALIDATOR_TEST_TEMPLATE_H_ 79 80 #include "base/basictypes.h" 81 #include "base/compiler_specific.h" 82 #include "components/invalidation/fake_invalidation_handler.h" 83 #include "components/invalidation/fake_invalidation_state_tracker.h" 84 #include "google/cacheinvalidation/include/types.h" 85 #include "google/cacheinvalidation/types.pb.h" 86 #include "sync/internal_api/public/base/object_id_invalidation_map_test_util.h" 87 #include "sync/notifier/invalidator.h" 88 #include "testing/gtest/include/gtest/gtest.h" 89 90 namespace syncer { 91 92 template <typename InvalidatorTestDelegate> 93 class InvalidatorTest : public testing::Test { 94 protected: 95 InvalidatorTest() 96 : id1(ipc::invalidation::ObjectSource::TEST, "a"), 97 id2(ipc::invalidation::ObjectSource::TEST, "b"), 98 id3(ipc::invalidation::ObjectSource::TEST, "c"), 99 id4(ipc::invalidation::ObjectSource::TEST, "d") { 100 } 101 102 Invalidator* CreateAndInitializeInvalidator() { 103 this->delegate_.CreateInvalidator("fake_invalidator_client_id", 104 "fake_initial_state", 105 this->fake_tracker_.AsWeakPtr()); 106 Invalidator* const invalidator = this->delegate_.GetInvalidator(); 107 108 this->delegate_.WaitForInvalidator(); 109 invalidator->UpdateCredentials("foo (at) bar.com", "fake_token"); 110 this->delegate_.WaitForInvalidator(); 111 112 return invalidator; 113 } 114 115 FakeInvalidationStateTracker fake_tracker_; 116 InvalidatorTestDelegate delegate_; 117 118 const invalidation::ObjectId id1; 119 const invalidation::ObjectId id2; 120 const invalidation::ObjectId id3; 121 const invalidation::ObjectId id4; 122 }; 123 124 TYPED_TEST_CASE_P(InvalidatorTest); 125 126 // Initialize the invalidator, register a handler, register some IDs for that 127 // handler, and then unregister the handler, dispatching invalidations in 128 // between. The handler should only see invalidations when its registered and 129 // its IDs are registered. 130 TYPED_TEST_P(InvalidatorTest, Basic) { 131 Invalidator* const invalidator = this->CreateAndInitializeInvalidator(); 132 133 FakeInvalidationHandler handler; 134 135 invalidator->RegisterHandler(&handler); 136 137 ObjectIdInvalidationMap invalidation_map; 138 invalidation_map.Insert(Invalidation::Init(this->id1, 1, "1")); 139 invalidation_map.Insert(Invalidation::Init(this->id2, 2, "2")); 140 invalidation_map.Insert(Invalidation::Init(this->id3, 3, "3")); 141 142 // Should be ignored since no IDs are registered to |handler|. 143 this->delegate_.TriggerOnIncomingInvalidation(invalidation_map); 144 EXPECT_EQ(0, handler.GetInvalidationCount()); 145 146 ObjectIdSet ids; 147 ids.insert(this->id1); 148 ids.insert(this->id2); 149 invalidator->UpdateRegisteredIds(&handler, ids); 150 151 this->delegate_.TriggerOnInvalidatorStateChange(INVALIDATIONS_ENABLED); 152 EXPECT_EQ(INVALIDATIONS_ENABLED, handler.GetInvalidatorState()); 153 154 ObjectIdInvalidationMap expected_invalidations; 155 expected_invalidations.Insert(Invalidation::Init(this->id1, 1, "1")); 156 expected_invalidations.Insert(Invalidation::Init(this->id2, 2, "2")); 157 158 this->delegate_.TriggerOnIncomingInvalidation(invalidation_map); 159 EXPECT_EQ(1, handler.GetInvalidationCount()); 160 EXPECT_THAT(expected_invalidations, Eq(handler.GetLastInvalidationMap())); 161 162 ids.erase(this->id1); 163 ids.insert(this->id3); 164 invalidator->UpdateRegisteredIds(&handler, ids); 165 166 expected_invalidations = ObjectIdInvalidationMap(); 167 expected_invalidations.Insert(Invalidation::Init(this->id2, 2, "2")); 168 expected_invalidations.Insert(Invalidation::Init(this->id3, 3, "3")); 169 170 // Removed object IDs should not be notified, newly-added ones should. 171 this->delegate_.TriggerOnIncomingInvalidation(invalidation_map); 172 EXPECT_EQ(2, handler.GetInvalidationCount()); 173 EXPECT_THAT(expected_invalidations, Eq(handler.GetLastInvalidationMap())); 174 175 this->delegate_.TriggerOnInvalidatorStateChange(TRANSIENT_INVALIDATION_ERROR); 176 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, 177 handler.GetInvalidatorState()); 178 179 this->delegate_.TriggerOnInvalidatorStateChange( 180 INVALIDATION_CREDENTIALS_REJECTED); 181 EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED, 182 handler.GetInvalidatorState()); 183 184 invalidator->UnregisterHandler(&handler); 185 186 // Should be ignored since |handler| isn't registered anymore. 187 this->delegate_.TriggerOnIncomingInvalidation(invalidation_map); 188 EXPECT_EQ(2, handler.GetInvalidationCount()); 189 } 190 191 // Register handlers and some IDs for those handlers, register a handler with 192 // no IDs, and register a handler with some IDs but unregister it. Then, 193 // dispatch some invalidations and invalidations. Handlers that are registered 194 // should get invalidations, and the ones that have registered IDs should 195 // receive invalidations for those IDs. 196 TYPED_TEST_P(InvalidatorTest, MultipleHandlers) { 197 Invalidator* const invalidator = this->CreateAndInitializeInvalidator(); 198 199 FakeInvalidationHandler handler1; 200 FakeInvalidationHandler handler2; 201 FakeInvalidationHandler handler3; 202 FakeInvalidationHandler handler4; 203 204 invalidator->RegisterHandler(&handler1); 205 invalidator->RegisterHandler(&handler2); 206 invalidator->RegisterHandler(&handler3); 207 invalidator->RegisterHandler(&handler4); 208 209 { 210 ObjectIdSet ids; 211 ids.insert(this->id1); 212 ids.insert(this->id2); 213 invalidator->UpdateRegisteredIds(&handler1, ids); 214 } 215 216 { 217 ObjectIdSet ids; 218 ids.insert(this->id3); 219 invalidator->UpdateRegisteredIds(&handler2, ids); 220 } 221 222 // Don't register any IDs for handler3. 223 224 { 225 ObjectIdSet ids; 226 ids.insert(this->id4); 227 invalidator->UpdateRegisteredIds(&handler4, ids); 228 } 229 230 invalidator->UnregisterHandler(&handler4); 231 232 this->delegate_.TriggerOnInvalidatorStateChange(INVALIDATIONS_ENABLED); 233 EXPECT_EQ(INVALIDATIONS_ENABLED, handler1.GetInvalidatorState()); 234 EXPECT_EQ(INVALIDATIONS_ENABLED, handler2.GetInvalidatorState()); 235 EXPECT_EQ(INVALIDATIONS_ENABLED, handler3.GetInvalidatorState()); 236 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler4.GetInvalidatorState()); 237 238 { 239 ObjectIdInvalidationMap invalidation_map; 240 invalidation_map.Insert(Invalidation::Init(this->id1, 1, "1")); 241 invalidation_map.Insert(Invalidation::Init(this->id2, 2, "2")); 242 invalidation_map.Insert(Invalidation::Init(this->id3, 3, "3")); 243 invalidation_map.Insert(Invalidation::Init(this->id4, 4, "4")); 244 245 this->delegate_.TriggerOnIncomingInvalidation(invalidation_map); 246 247 ObjectIdInvalidationMap expected_invalidations; 248 expected_invalidations.Insert(Invalidation::Init(this->id1, 1, "1")); 249 expected_invalidations.Insert(Invalidation::Init(this->id2, 2, "2")); 250 251 EXPECT_EQ(1, handler1.GetInvalidationCount()); 252 EXPECT_THAT(expected_invalidations, Eq(handler1.GetLastInvalidationMap())); 253 254 expected_invalidations = ObjectIdInvalidationMap(); 255 expected_invalidations.Insert(Invalidation::Init(this->id3, 3, "3")); 256 257 EXPECT_EQ(1, handler2.GetInvalidationCount()); 258 EXPECT_THAT(expected_invalidations, Eq(handler2.GetLastInvalidationMap())); 259 260 EXPECT_EQ(0, handler3.GetInvalidationCount()); 261 EXPECT_EQ(0, handler4.GetInvalidationCount()); 262 } 263 264 this->delegate_.TriggerOnInvalidatorStateChange(TRANSIENT_INVALIDATION_ERROR); 265 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler1.GetInvalidatorState()); 266 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler2.GetInvalidatorState()); 267 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler3.GetInvalidatorState()); 268 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler4.GetInvalidatorState()); 269 270 invalidator->UnregisterHandler(&handler3); 271 invalidator->UnregisterHandler(&handler2); 272 invalidator->UnregisterHandler(&handler1); 273 } 274 275 // Make sure that passing an empty set to UpdateRegisteredIds clears the 276 // corresponding entries for the handler. 277 TYPED_TEST_P(InvalidatorTest, EmptySetUnregisters) { 278 Invalidator* const invalidator = this->CreateAndInitializeInvalidator(); 279 280 FakeInvalidationHandler handler1; 281 282 // Control observer. 283 FakeInvalidationHandler handler2; 284 285 invalidator->RegisterHandler(&handler1); 286 invalidator->RegisterHandler(&handler2); 287 288 { 289 ObjectIdSet ids; 290 ids.insert(this->id1); 291 ids.insert(this->id2); 292 invalidator->UpdateRegisteredIds(&handler1, ids); 293 } 294 295 { 296 ObjectIdSet ids; 297 ids.insert(this->id3); 298 invalidator->UpdateRegisteredIds(&handler2, ids); 299 } 300 301 // Unregister the IDs for the first observer. It should not receive any 302 // further invalidations. 303 invalidator->UpdateRegisteredIds(&handler1, ObjectIdSet()); 304 305 this->delegate_.TriggerOnInvalidatorStateChange(INVALIDATIONS_ENABLED); 306 EXPECT_EQ(INVALIDATIONS_ENABLED, handler1.GetInvalidatorState()); 307 EXPECT_EQ(INVALIDATIONS_ENABLED, handler2.GetInvalidatorState()); 308 309 { 310 ObjectIdInvalidationMap invalidation_map; 311 invalidation_map.Insert(Invalidation::Init(this->id1, 1, "1")); 312 invalidation_map.Insert(Invalidation::Init(this->id2, 2, "2")); 313 invalidation_map.Insert(Invalidation::Init(this->id3, 3, "3")); 314 this->delegate_.TriggerOnIncomingInvalidation(invalidation_map); 315 EXPECT_EQ(0, handler1.GetInvalidationCount()); 316 EXPECT_EQ(1, handler2.GetInvalidationCount()); 317 } 318 319 this->delegate_.TriggerOnInvalidatorStateChange(TRANSIENT_INVALIDATION_ERROR); 320 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler1.GetInvalidatorState()); 321 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler2.GetInvalidatorState()); 322 323 invalidator->UnregisterHandler(&handler2); 324 invalidator->UnregisterHandler(&handler1); 325 } 326 327 namespace internal { 328 329 // A FakeInvalidationHandler that is "bound" to a specific 330 // Invalidator. This is for cross-referencing state information with 331 // the bound Invalidator. 332 class BoundFakeInvalidationHandler : public FakeInvalidationHandler { 333 public: 334 explicit BoundFakeInvalidationHandler(const Invalidator& invalidator); 335 virtual ~BoundFakeInvalidationHandler(); 336 337 // Returns the last return value of GetInvalidatorState() on the 338 // bound invalidator from the last time the invalidator state 339 // changed. 340 InvalidatorState GetLastRetrievedState() const; 341 342 // InvalidationHandler implementation. 343 virtual void OnInvalidatorStateChange(InvalidatorState state) OVERRIDE; 344 345 private: 346 const Invalidator& invalidator_; 347 InvalidatorState last_retrieved_state_; 348 349 DISALLOW_COPY_AND_ASSIGN(BoundFakeInvalidationHandler); 350 }; 351 352 } // namespace internal 353 354 TYPED_TEST_P(InvalidatorTest, GetInvalidatorStateAlwaysCurrent) { 355 Invalidator* const invalidator = this->CreateAndInitializeInvalidator(); 356 357 internal::BoundFakeInvalidationHandler handler(*invalidator); 358 invalidator->RegisterHandler(&handler); 359 360 this->delegate_.TriggerOnInvalidatorStateChange(INVALIDATIONS_ENABLED); 361 EXPECT_EQ(INVALIDATIONS_ENABLED, handler.GetInvalidatorState()); 362 EXPECT_EQ(INVALIDATIONS_ENABLED, handler.GetLastRetrievedState()); 363 364 this->delegate_.TriggerOnInvalidatorStateChange(TRANSIENT_INVALIDATION_ERROR); 365 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler.GetInvalidatorState()); 366 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, handler.GetLastRetrievedState()); 367 368 invalidator->UnregisterHandler(&handler); 369 } 370 371 REGISTER_TYPED_TEST_CASE_P(InvalidatorTest, 372 Basic, MultipleHandlers, EmptySetUnregisters, 373 GetInvalidatorStateAlwaysCurrent); 374 375 } // namespace syncer 376 377 #endif // COMPONENTS_INVALIDATION_INVALIDATOR_TEST_TEMPLATE_H_ 378