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