Home | History | Annotate | Download | only in invalidation
      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