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 #include "components/invalidation/p2p_invalidator.h" 6 7 #include <cstddef> 8 9 #include "components/invalidation/fake_invalidation_handler.h" 10 #include "components/invalidation/invalidator_test_template.h" 11 #include "components/invalidation/notifier_reason_util.h" 12 #include "jingle/notifier/listener/fake_push_client.h" 13 #include "sync/internal_api/public/base/invalidator_state.h" 14 #include "sync/internal_api/public/base/model_type.h" 15 #include "testing/gtest/include/gtest/gtest.h" 16 17 namespace syncer { 18 19 namespace { 20 21 class P2PInvalidatorTestDelegate { 22 public: 23 P2PInvalidatorTestDelegate() : fake_push_client_(NULL) {} 24 25 ~P2PInvalidatorTestDelegate() { 26 DestroyInvalidator(); 27 } 28 29 void CreateInvalidator( 30 const std::string& invalidator_client_id, 31 const std::string& initial_state, 32 const base::WeakPtr<InvalidationStateTracker>& 33 invalidation_state_tracker) { 34 DCHECK(!fake_push_client_); 35 DCHECK(!invalidator_.get()); 36 fake_push_client_ = new notifier::FakePushClient(); 37 invalidator_.reset( 38 new P2PInvalidator( 39 scoped_ptr<notifier::PushClient>(fake_push_client_), 40 invalidator_client_id, 41 NOTIFY_OTHERS)); 42 } 43 44 P2PInvalidator* GetInvalidator() { 45 return invalidator_.get(); 46 } 47 48 notifier::FakePushClient* GetPushClient() { 49 return fake_push_client_; 50 } 51 52 void DestroyInvalidator() { 53 invalidator_.reset(); 54 fake_push_client_ = NULL; 55 } 56 57 void WaitForInvalidator() { 58 // Do Nothing. 59 } 60 61 void TriggerOnInvalidatorStateChange(InvalidatorState state) { 62 if (state == INVALIDATIONS_ENABLED) { 63 fake_push_client_->EnableNotifications(); 64 } else { 65 fake_push_client_->DisableNotifications(ToNotifierReasonForTest(state)); 66 } 67 } 68 69 void TriggerOnIncomingInvalidation( 70 const ObjectIdInvalidationMap& invalidation_map) { 71 const P2PNotificationData notification_data( 72 std::string(), NOTIFY_ALL, invalidation_map); 73 notifier::Notification notification; 74 notification.channel = kSyncP2PNotificationChannel; 75 notification.data = notification_data.ToString(); 76 fake_push_client_->SimulateIncomingNotification(notification); 77 } 78 79 private: 80 // Owned by |invalidator_|. 81 notifier::FakePushClient* fake_push_client_; 82 scoped_ptr<P2PInvalidator> invalidator_; 83 }; 84 85 class P2PInvalidatorTest : public testing::Test { 86 protected: 87 P2PInvalidatorTest() 88 : next_sent_notification_to_reflect_(0) { 89 delegate_.CreateInvalidator("sender", 90 "fake_state", 91 base::WeakPtr<InvalidationStateTracker>()); 92 delegate_.GetInvalidator()->RegisterHandler(&fake_handler_); 93 } 94 95 virtual ~P2PInvalidatorTest() { 96 delegate_.GetInvalidator()->UnregisterHandler(&fake_handler_); 97 } 98 99 ObjectIdInvalidationMap MakeInvalidationMap(ModelTypeSet types) { 100 ObjectIdInvalidationMap invalidations; 101 ObjectIdSet ids = ModelTypeSetToObjectIdSet(types); 102 return ObjectIdInvalidationMap::InvalidateAll(ids); 103 } 104 105 // Simulate receiving all the notifications we sent out since last 106 // time this was called. 107 void ReflectSentNotifications() { 108 const std::vector<notifier::Notification>& sent_notifications = 109 delegate_.GetPushClient()->sent_notifications(); 110 for(size_t i = next_sent_notification_to_reflect_; 111 i < sent_notifications.size(); ++i) { 112 delegate_.GetInvalidator()->OnIncomingNotification(sent_notifications[i]); 113 } 114 next_sent_notification_to_reflect_ = sent_notifications.size(); 115 } 116 117 FakeInvalidationHandler fake_handler_; 118 P2PInvalidatorTestDelegate delegate_; 119 120 private: 121 size_t next_sent_notification_to_reflect_; 122 }; 123 124 // Make sure the P2PNotificationTarget <-> string conversions work. 125 TEST_F(P2PInvalidatorTest, P2PNotificationTarget) { 126 for (int i = FIRST_NOTIFICATION_TARGET; 127 i <= LAST_NOTIFICATION_TARGET; ++i) { 128 P2PNotificationTarget target = static_cast<P2PNotificationTarget>(i); 129 const std::string& target_str = P2PNotificationTargetToString(target); 130 EXPECT_FALSE(target_str.empty()); 131 EXPECT_EQ(target, P2PNotificationTargetFromString(target_str)); 132 } 133 EXPECT_EQ(NOTIFY_SELF, P2PNotificationTargetFromString("unknown")); 134 } 135 136 // Make sure notification targeting works correctly. 137 TEST_F(P2PInvalidatorTest, P2PNotificationDataIsTargeted) { 138 { 139 const P2PNotificationData notification_data( 140 "sender", NOTIFY_SELF, ObjectIdInvalidationMap()); 141 EXPECT_TRUE(notification_data.IsTargeted("sender")); 142 EXPECT_FALSE(notification_data.IsTargeted("other1")); 143 EXPECT_FALSE(notification_data.IsTargeted("other2")); 144 } 145 { 146 const P2PNotificationData notification_data( 147 "sender", NOTIFY_OTHERS, ObjectIdInvalidationMap()); 148 EXPECT_FALSE(notification_data.IsTargeted("sender")); 149 EXPECT_TRUE(notification_data.IsTargeted("other1")); 150 EXPECT_TRUE(notification_data.IsTargeted("other2")); 151 } 152 { 153 const P2PNotificationData notification_data( 154 "sender", NOTIFY_ALL, ObjectIdInvalidationMap()); 155 EXPECT_TRUE(notification_data.IsTargeted("sender")); 156 EXPECT_TRUE(notification_data.IsTargeted("other1")); 157 EXPECT_TRUE(notification_data.IsTargeted("other2")); 158 } 159 } 160 161 // Make sure the P2PNotificationData <-> string conversions work for a 162 // default-constructed P2PNotificationData. 163 TEST_F(P2PInvalidatorTest, P2PNotificationDataDefault) { 164 const P2PNotificationData notification_data; 165 EXPECT_TRUE(notification_data.IsTargeted(std::string())); 166 EXPECT_FALSE(notification_data.IsTargeted("other1")); 167 EXPECT_FALSE(notification_data.IsTargeted("other2")); 168 EXPECT_TRUE(notification_data.GetIdInvalidationMap().Empty()); 169 const std::string& notification_data_str = notification_data.ToString(); 170 EXPECT_EQ( 171 "{\"invalidations\":[],\"notificationType\":\"notifySelf\"," 172 "\"senderId\":\"\"}", notification_data_str); 173 174 P2PNotificationData notification_data_parsed; 175 EXPECT_TRUE(notification_data_parsed.ResetFromString(notification_data_str)); 176 EXPECT_TRUE(notification_data.Equals(notification_data_parsed)); 177 } 178 179 // Make sure the P2PNotificationData <-> string conversions work for a 180 // non-default-constructed P2PNotificationData. 181 TEST_F(P2PInvalidatorTest, P2PNotificationDataNonDefault) { 182 ObjectIdInvalidationMap invalidation_map = 183 ObjectIdInvalidationMap::InvalidateAll( 184 ModelTypeSetToObjectIdSet(ModelTypeSet(BOOKMARKS, THEMES))); 185 const P2PNotificationData notification_data("sender", 186 NOTIFY_ALL, 187 invalidation_map); 188 EXPECT_TRUE(notification_data.IsTargeted("sender")); 189 EXPECT_TRUE(notification_data.IsTargeted("other1")); 190 EXPECT_TRUE(notification_data.IsTargeted("other2")); 191 EXPECT_EQ(invalidation_map, notification_data.GetIdInvalidationMap()); 192 const std::string& notification_data_str = notification_data.ToString(); 193 EXPECT_EQ( 194 "{\"invalidations\":[" 195 "{\"isUnknownVersion\":true," 196 "\"objectId\":{\"name\":\"BOOKMARK\",\"source\":1004}}," 197 "{\"isUnknownVersion\":true," 198 "\"objectId\":{\"name\":\"THEME\",\"source\":1004}}" 199 "],\"notificationType\":\"notifyAll\"," 200 "\"senderId\":\"sender\"}", notification_data_str); 201 202 P2PNotificationData notification_data_parsed; 203 EXPECT_TRUE(notification_data_parsed.ResetFromString(notification_data_str)); 204 EXPECT_TRUE(notification_data.Equals(notification_data_parsed)); 205 } 206 207 // Set up the P2PInvalidator, simulate a successful connection, and send 208 // a notification with the default target (NOTIFY_OTHERS). The 209 // observer should receive only a notification from the call to 210 // UpdateEnabledTypes(). 211 TEST_F(P2PInvalidatorTest, NotificationsBasic) { 212 const ModelTypeSet enabled_types(BOOKMARKS, PREFERENCES); 213 214 P2PInvalidator* const invalidator = delegate_.GetInvalidator(); 215 notifier::FakePushClient* const push_client = delegate_.GetPushClient(); 216 217 invalidator->UpdateRegisteredIds(&fake_handler_, 218 ModelTypeSetToObjectIdSet(enabled_types)); 219 220 const char kEmail[] = "foo (at) bar.com"; 221 const char kToken[] = "token"; 222 invalidator->UpdateCredentials(kEmail, kToken); 223 { 224 notifier::Subscription expected_subscription; 225 expected_subscription.channel = kSyncP2PNotificationChannel; 226 expected_subscription.from = kEmail; 227 EXPECT_TRUE(notifier::SubscriptionListsEqual( 228 push_client->subscriptions(), 229 notifier::SubscriptionList(1, expected_subscription))); 230 } 231 EXPECT_EQ(kEmail, push_client->email()); 232 EXPECT_EQ(kToken, push_client->token()); 233 234 ReflectSentNotifications(); 235 push_client->EnableNotifications(); 236 EXPECT_EQ(INVALIDATIONS_ENABLED, fake_handler_.GetInvalidatorState()); 237 238 ReflectSentNotifications(); 239 EXPECT_EQ(1, fake_handler_.GetInvalidationCount()); 240 EXPECT_THAT( 241 MakeInvalidationMap(enabled_types), 242 Eq(fake_handler_.GetLastInvalidationMap())); 243 244 // Sent with target NOTIFY_OTHERS so should not be propagated to 245 // |fake_handler_|. 246 invalidator->SendInvalidation( 247 ModelTypeSetToObjectIdSet(ModelTypeSet(THEMES, APPS))); 248 249 ReflectSentNotifications(); 250 EXPECT_EQ(1, fake_handler_.GetInvalidationCount()); 251 } 252 253 // Set up the P2PInvalidator and send out notifications with various 254 // target settings. The notifications received by the observer should 255 // be consistent with the target settings. 256 TEST_F(P2PInvalidatorTest, SendNotificationData) { 257 const ModelTypeSet enabled_types(BOOKMARKS, PREFERENCES, THEMES); 258 const ModelTypeSet changed_types(THEMES, APPS); 259 const ModelTypeSet expected_types(THEMES); 260 261 const ObjectIdInvalidationMap& invalidation_map = 262 MakeInvalidationMap(changed_types); 263 264 P2PInvalidator* const invalidator = delegate_.GetInvalidator(); 265 notifier::FakePushClient* const push_client = delegate_.GetPushClient(); 266 267 invalidator->UpdateRegisteredIds(&fake_handler_, 268 ModelTypeSetToObjectIdSet(enabled_types)); 269 270 invalidator->UpdateCredentials("foo (at) bar.com", "fake_token"); 271 272 ReflectSentNotifications(); 273 push_client->EnableNotifications(); 274 EXPECT_EQ(INVALIDATIONS_ENABLED, fake_handler_.GetInvalidatorState()); 275 276 ReflectSentNotifications(); 277 EXPECT_EQ(1, fake_handler_.GetInvalidationCount()); 278 EXPECT_EQ(ModelTypeSetToObjectIdSet(enabled_types), 279 fake_handler_.GetLastInvalidationMap().GetObjectIds()); 280 281 // Should be dropped. 282 invalidator->SendNotificationDataForTest(P2PNotificationData()); 283 ReflectSentNotifications(); 284 EXPECT_EQ(1, fake_handler_.GetInvalidationCount()); 285 286 const ObjectIdSet& expected_ids = ModelTypeSetToObjectIdSet(expected_types); 287 288 // Should be propagated. 289 invalidator->SendNotificationDataForTest( 290 P2PNotificationData("sender", NOTIFY_SELF, invalidation_map)); 291 ReflectSentNotifications(); 292 EXPECT_EQ(2, fake_handler_.GetInvalidationCount()); 293 EXPECT_EQ(expected_ids, 294 fake_handler_.GetLastInvalidationMap().GetObjectIds()); 295 296 // Should be dropped. 297 invalidator->SendNotificationDataForTest( 298 P2PNotificationData("sender2", NOTIFY_SELF, invalidation_map)); 299 ReflectSentNotifications(); 300 EXPECT_EQ(2, fake_handler_.GetInvalidationCount()); 301 302 // Should be dropped. 303 invalidator->SendNotificationDataForTest( 304 P2PNotificationData("sender", NOTIFY_SELF, ObjectIdInvalidationMap())); 305 ReflectSentNotifications(); 306 EXPECT_EQ(2, fake_handler_.GetInvalidationCount()); 307 308 // Should be dropped. 309 invalidator->SendNotificationDataForTest( 310 P2PNotificationData("sender", NOTIFY_OTHERS, invalidation_map)); 311 ReflectSentNotifications(); 312 EXPECT_EQ(2, fake_handler_.GetInvalidationCount()); 313 314 // Should be propagated. 315 invalidator->SendNotificationDataForTest( 316 P2PNotificationData("sender2", NOTIFY_OTHERS, invalidation_map)); 317 ReflectSentNotifications(); 318 EXPECT_EQ(3, fake_handler_.GetInvalidationCount()); 319 EXPECT_EQ(expected_ids, 320 fake_handler_.GetLastInvalidationMap().GetObjectIds()); 321 322 // Should be dropped. 323 invalidator->SendNotificationDataForTest( 324 P2PNotificationData("sender2", NOTIFY_OTHERS, ObjectIdInvalidationMap())); 325 ReflectSentNotifications(); 326 EXPECT_EQ(3, fake_handler_.GetInvalidationCount()); 327 328 // Should be propagated. 329 invalidator->SendNotificationDataForTest( 330 P2PNotificationData("sender", NOTIFY_ALL, invalidation_map)); 331 ReflectSentNotifications(); 332 EXPECT_EQ(4, fake_handler_.GetInvalidationCount()); 333 EXPECT_EQ(expected_ids, 334 fake_handler_.GetLastInvalidationMap().GetObjectIds()); 335 336 // Should be propagated. 337 invalidator->SendNotificationDataForTest( 338 P2PNotificationData("sender2", NOTIFY_ALL, invalidation_map)); 339 ReflectSentNotifications(); 340 EXPECT_EQ(5, fake_handler_.GetInvalidationCount()); 341 EXPECT_EQ(expected_ids, 342 fake_handler_.GetLastInvalidationMap().GetObjectIds()); 343 344 // Should be dropped. 345 invalidator->SendNotificationDataForTest( 346 P2PNotificationData("sender2", NOTIFY_ALL, ObjectIdInvalidationMap())); 347 ReflectSentNotifications(); 348 EXPECT_EQ(5, fake_handler_.GetInvalidationCount()); 349 } 350 351 INSTANTIATE_TYPED_TEST_CASE_P( 352 P2PInvalidatorTest, InvalidatorTest, 353 P2PInvalidatorTestDelegate); 354 355 } // namespace 356 357 } // namespace syncer 358