Home | History | Annotate | Download | only in notifier
      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 #include "sync/notifier/p2p_invalidator.h"
      6 
      7 #include <cstddef>
      8 
      9 #include "jingle/notifier/listener/fake_push_client.h"
     10 #include "sync/internal_api/public/base/model_type.h"
     11 #include "sync/internal_api/public/base/model_type_invalidation_map.h"
     12 #include "sync/notifier/fake_invalidation_handler.h"
     13 #include "sync/notifier/invalidator_test_template.h"
     14 #include "sync/notifier/object_id_invalidation_map_test_util.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   ModelTypeInvalidationMap MakeInvalidationMap(ModelTypeSet types) {
    100     return ModelTypeSetToInvalidationMap(types, std::string());
    101   }
    102 
    103   // Simulate receiving all the notifications we sent out since last
    104   // time this was called.
    105   void ReflectSentNotifications() {
    106     const std::vector<notifier::Notification>& sent_notifications =
    107         delegate_.GetPushClient()->sent_notifications();
    108     for(size_t i = next_sent_notification_to_reflect_;
    109         i < sent_notifications.size(); ++i) {
    110       delegate_.GetInvalidator()->OnIncomingNotification(sent_notifications[i]);
    111     }
    112     next_sent_notification_to_reflect_ = sent_notifications.size();
    113   }
    114 
    115   FakeInvalidationHandler fake_handler_;
    116   P2PInvalidatorTestDelegate delegate_;
    117 
    118  private:
    119   size_t next_sent_notification_to_reflect_;
    120 };
    121 
    122 // Make sure the P2PNotificationTarget <-> string conversions work.
    123 TEST_F(P2PInvalidatorTest, P2PNotificationTarget) {
    124   for (int i = FIRST_NOTIFICATION_TARGET;
    125        i <= LAST_NOTIFICATION_TARGET; ++i) {
    126     P2PNotificationTarget target = static_cast<P2PNotificationTarget>(i);
    127     const std::string& target_str = P2PNotificationTargetToString(target);
    128     EXPECT_FALSE(target_str.empty());
    129     EXPECT_EQ(target, P2PNotificationTargetFromString(target_str));
    130   }
    131   EXPECT_EQ(NOTIFY_SELF, P2PNotificationTargetFromString("unknown"));
    132 }
    133 
    134 // Make sure notification targeting works correctly.
    135 TEST_F(P2PInvalidatorTest, P2PNotificationDataIsTargeted) {
    136   {
    137     const P2PNotificationData notification_data(
    138         "sender", NOTIFY_SELF, ObjectIdInvalidationMap());
    139     EXPECT_TRUE(notification_data.IsTargeted("sender"));
    140     EXPECT_FALSE(notification_data.IsTargeted("other1"));
    141     EXPECT_FALSE(notification_data.IsTargeted("other2"));
    142   }
    143   {
    144     const P2PNotificationData notification_data(
    145         "sender", NOTIFY_OTHERS, ObjectIdInvalidationMap());
    146     EXPECT_FALSE(notification_data.IsTargeted("sender"));
    147     EXPECT_TRUE(notification_data.IsTargeted("other1"));
    148     EXPECT_TRUE(notification_data.IsTargeted("other2"));
    149   }
    150   {
    151     const P2PNotificationData notification_data(
    152         "sender", NOTIFY_ALL, ObjectIdInvalidationMap());
    153     EXPECT_TRUE(notification_data.IsTargeted("sender"));
    154     EXPECT_TRUE(notification_data.IsTargeted("other1"));
    155     EXPECT_TRUE(notification_data.IsTargeted("other2"));
    156   }
    157 }
    158 
    159 // Make sure the P2PNotificationData <-> string conversions work for a
    160 // default-constructed P2PNotificationData.
    161 TEST_F(P2PInvalidatorTest, P2PNotificationDataDefault) {
    162   const P2PNotificationData notification_data;
    163   EXPECT_TRUE(notification_data.IsTargeted(std::string()));
    164   EXPECT_FALSE(notification_data.IsTargeted("other1"));
    165   EXPECT_FALSE(notification_data.IsTargeted("other2"));
    166   EXPECT_TRUE(notification_data.GetIdInvalidationMap().empty());
    167   const std::string& notification_data_str = notification_data.ToString();
    168   EXPECT_EQ(
    169       "{\"idInvalidationMap\":[],\"notificationType\":\"notifySelf\","
    170       "\"senderId\":\"\"}", notification_data_str);
    171 
    172   P2PNotificationData notification_data_parsed;
    173   EXPECT_TRUE(notification_data_parsed.ResetFromString(notification_data_str));
    174   EXPECT_TRUE(notification_data.Equals(notification_data_parsed));
    175 }
    176 
    177 // Make sure the P2PNotificationData <-> string conversions work for a
    178 // non-default-constructed P2PNotificationData.
    179 TEST_F(P2PInvalidatorTest, P2PNotificationDataNonDefault) {
    180   const ObjectIdInvalidationMap& invalidation_map =
    181       ObjectIdSetToInvalidationMap(
    182           ModelTypeSetToObjectIdSet(ModelTypeSet(BOOKMARKS, THEMES)),
    183           Invalidation::kUnknownVersion,
    184           std::string());
    185   const P2PNotificationData notification_data(
    186       "sender", NOTIFY_ALL, invalidation_map);
    187   EXPECT_TRUE(notification_data.IsTargeted("sender"));
    188   EXPECT_TRUE(notification_data.IsTargeted("other1"));
    189   EXPECT_TRUE(notification_data.IsTargeted("other2"));
    190   EXPECT_THAT(invalidation_map,
    191               Eq(notification_data.GetIdInvalidationMap()));
    192   const std::string& notification_data_str = notification_data.ToString();
    193   EXPECT_EQ(
    194       "{\"idInvalidationMap\":["
    195       "{\"objectId\":{\"name\":\"BOOKMARK\",\"source\":1004},"
    196       "\"state\":{\"ackHandle\":{\"state\":\"\",\"timestamp\":\"0\"},"
    197       "\"payload\":\"\",\"version\":\"-1\"}},"
    198       "{\"objectId\":{\"name\":\"THEME\",\"source\":1004},"
    199       "\"state\":{\"ackHandle\":{\"state\":\"\",\"timestamp\":\"0\"},"
    200       "\"payload\":\"\",\"version\":\"-1\"}}"
    201       "],\"notificationType\":\"notifyAll\","
    202       "\"senderId\":\"sender\"}", notification_data_str);
    203 
    204   P2PNotificationData notification_data_parsed;
    205   EXPECT_TRUE(notification_data_parsed.ResetFromString(notification_data_str));
    206   EXPECT_TRUE(notification_data.Equals(notification_data_parsed));
    207 }
    208 
    209 // Set up the P2PInvalidator, simulate a successful connection, and send
    210 // a notification with the default target (NOTIFY_OTHERS).  The
    211 // observer should receive only a notification from the call to
    212 // UpdateEnabledTypes().
    213 TEST_F(P2PInvalidatorTest, NotificationsBasic) {
    214   const ModelTypeSet enabled_types(BOOKMARKS, PREFERENCES);
    215 
    216   P2PInvalidator* const invalidator = delegate_.GetInvalidator();
    217   notifier::FakePushClient* const push_client = delegate_.GetPushClient();
    218 
    219   invalidator->UpdateRegisteredIds(&fake_handler_,
    220                                    ModelTypeSetToObjectIdSet(enabled_types));
    221 
    222   const char kEmail[] = "foo (at) bar.com";
    223   const char kToken[] = "token";
    224   invalidator->UpdateCredentials(kEmail, kToken);
    225   {
    226     notifier::Subscription expected_subscription;
    227     expected_subscription.channel = kSyncP2PNotificationChannel;
    228     expected_subscription.from = kEmail;
    229     EXPECT_TRUE(notifier::SubscriptionListsEqual(
    230         push_client->subscriptions(),
    231         notifier::SubscriptionList(1, expected_subscription)));
    232   }
    233   EXPECT_EQ(kEmail, push_client->email());
    234   EXPECT_EQ(kToken, push_client->token());
    235 
    236   ReflectSentNotifications();
    237   push_client->EnableNotifications();
    238   EXPECT_EQ(INVALIDATIONS_ENABLED, fake_handler_.GetInvalidatorState());
    239 
    240   ReflectSentNotifications();
    241   EXPECT_EQ(1, fake_handler_.GetInvalidationCount());
    242   EXPECT_THAT(
    243       ModelTypeInvalidationMapToObjectIdInvalidationMap(
    244           MakeInvalidationMap(enabled_types)),
    245       Eq(fake_handler_.GetLastInvalidationMap()));
    246 
    247   // Sent with target NOTIFY_OTHERS so should not be propagated to
    248   // |fake_handler_|.
    249   {
    250     const ObjectIdInvalidationMap& invalidation_map =
    251         ObjectIdSetToInvalidationMap(
    252             ModelTypeSetToObjectIdSet(ModelTypeSet(THEMES, APPS)),
    253             Invalidation::kUnknownVersion,
    254             std::string());
    255     invalidator->SendInvalidation(invalidation_map);
    256   }
    257 
    258   ReflectSentNotifications();
    259   EXPECT_EQ(1, fake_handler_.GetInvalidationCount());
    260 }
    261 
    262 // Set up the P2PInvalidator and send out notifications with various
    263 // target settings.  The notifications received by the observer should
    264 // be consistent with the target settings.
    265 TEST_F(P2PInvalidatorTest, SendNotificationData) {
    266   const ModelTypeSet enabled_types(BOOKMARKS, PREFERENCES, THEMES);
    267   const ModelTypeSet changed_types(THEMES, APPS);
    268   const ModelTypeSet expected_types(THEMES);
    269 
    270   const ObjectIdInvalidationMap& invalidation_map =
    271       ObjectIdSetToInvalidationMap(ModelTypeSetToObjectIdSet(changed_types),
    272                                    Invalidation::kUnknownVersion,
    273                                    std::string());
    274 
    275   P2PInvalidator* const invalidator = delegate_.GetInvalidator();
    276   notifier::FakePushClient* const push_client = delegate_.GetPushClient();
    277 
    278   invalidator->UpdateRegisteredIds(&fake_handler_,
    279                                    ModelTypeSetToObjectIdSet(enabled_types));
    280 
    281   invalidator->UpdateCredentials("foo (at) bar.com", "fake_token");
    282 
    283   ReflectSentNotifications();
    284   push_client->EnableNotifications();
    285   EXPECT_EQ(INVALIDATIONS_ENABLED, fake_handler_.GetInvalidatorState());
    286 
    287   ReflectSentNotifications();
    288   EXPECT_EQ(1, fake_handler_.GetInvalidationCount());
    289   EXPECT_THAT(
    290       ModelTypeInvalidationMapToObjectIdInvalidationMap(
    291           MakeInvalidationMap(enabled_types)),
    292       Eq(fake_handler_.GetLastInvalidationMap()));
    293 
    294   // Should be dropped.
    295   invalidator->SendNotificationDataForTest(P2PNotificationData());
    296   ReflectSentNotifications();
    297   EXPECT_EQ(1, fake_handler_.GetInvalidationCount());
    298 
    299   const ObjectIdInvalidationMap& expected_ids =
    300       ModelTypeInvalidationMapToObjectIdInvalidationMap(
    301           MakeInvalidationMap(expected_types));
    302 
    303   // Should be propagated.
    304   invalidator->SendNotificationDataForTest(
    305       P2PNotificationData("sender", NOTIFY_SELF, invalidation_map));
    306   ReflectSentNotifications();
    307   EXPECT_EQ(2, fake_handler_.GetInvalidationCount());
    308   EXPECT_THAT(expected_ids, Eq(fake_handler_.GetLastInvalidationMap()));
    309 
    310   // Should be dropped.
    311   invalidator->SendNotificationDataForTest(
    312       P2PNotificationData("sender2", NOTIFY_SELF, invalidation_map));
    313   ReflectSentNotifications();
    314   EXPECT_EQ(2, fake_handler_.GetInvalidationCount());
    315 
    316   // Should be dropped.
    317   invalidator->SendNotificationDataForTest(
    318       P2PNotificationData("sender", NOTIFY_SELF, ObjectIdInvalidationMap()));
    319   ReflectSentNotifications();
    320   EXPECT_EQ(2, fake_handler_.GetInvalidationCount());
    321 
    322   // Should be dropped.
    323   invalidator->SendNotificationDataForTest(
    324       P2PNotificationData("sender", NOTIFY_OTHERS, invalidation_map));
    325   ReflectSentNotifications();
    326   EXPECT_EQ(2, fake_handler_.GetInvalidationCount());
    327 
    328   // Should be propagated.
    329   invalidator->SendNotificationDataForTest(
    330       P2PNotificationData("sender2", NOTIFY_OTHERS, invalidation_map));
    331   ReflectSentNotifications();
    332   EXPECT_EQ(3, fake_handler_.GetInvalidationCount());
    333   EXPECT_THAT(expected_ids, Eq(fake_handler_.GetLastInvalidationMap()));
    334 
    335   // Should be dropped.
    336   invalidator->SendNotificationDataForTest(
    337       P2PNotificationData("sender2", NOTIFY_OTHERS, ObjectIdInvalidationMap()));
    338   ReflectSentNotifications();
    339   EXPECT_EQ(3, fake_handler_.GetInvalidationCount());
    340 
    341   // Should be propagated.
    342   invalidator->SendNotificationDataForTest(
    343       P2PNotificationData("sender", NOTIFY_ALL, invalidation_map));
    344   ReflectSentNotifications();
    345   EXPECT_EQ(4, fake_handler_.GetInvalidationCount());
    346   EXPECT_THAT(expected_ids, Eq(fake_handler_.GetLastInvalidationMap()));
    347 
    348   // Should be propagated.
    349   invalidator->SendNotificationDataForTest(
    350       P2PNotificationData("sender2", NOTIFY_ALL, invalidation_map));
    351   ReflectSentNotifications();
    352   EXPECT_EQ(5, fake_handler_.GetInvalidationCount());
    353   EXPECT_THAT(expected_ids, Eq(fake_handler_.GetLastInvalidationMap()));
    354 
    355   // Should be dropped.
    356   invalidator->SendNotificationDataForTest(
    357   P2PNotificationData("sender2", NOTIFY_ALL, ObjectIdInvalidationMap()));
    358   ReflectSentNotifications();
    359   EXPECT_EQ(5, fake_handler_.GetInvalidationCount());
    360 }
    361 
    362 INSTANTIATE_TYPED_TEST_CASE_P(
    363     P2PInvalidatorTest, InvalidatorTest,
    364     P2PInvalidatorTestDelegate);
    365 
    366 }  // namespace
    367 
    368 }  // namespace syncer
    369