• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
P2PInvalidatorTestDelegate()23   P2PInvalidatorTestDelegate() : fake_push_client_(NULL) {}
24 
~P2PInvalidatorTestDelegate()25   ~P2PInvalidatorTestDelegate() {
26     DestroyInvalidator();
27   }
28 
CreateInvalidator(const std::string & invalidator_client_id,const std::string & initial_state,const base::WeakPtr<InvalidationStateTracker> & invalidation_state_tracker)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 
GetInvalidator()44   P2PInvalidator* GetInvalidator() {
45     return invalidator_.get();
46   }
47 
GetPushClient()48   notifier::FakePushClient* GetPushClient() {
49     return fake_push_client_;
50   }
51 
DestroyInvalidator()52   void DestroyInvalidator() {
53     invalidator_.reset();
54     fake_push_client_ = NULL;
55   }
56 
WaitForInvalidator()57   void WaitForInvalidator() {
58     // Do Nothing.
59   }
60 
TriggerOnInvalidatorStateChange(InvalidatorState state)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 
TriggerOnIncomingInvalidation(const ObjectIdInvalidationMap & invalidation_map)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:
P2PInvalidatorTest()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 
~P2PInvalidatorTest()95   virtual ~P2PInvalidatorTest() {
96     delegate_.GetInvalidator()->UnregisterHandler(&fake_handler_);
97   }
98 
MakeInvalidationMap(ModelTypeSet types)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.
ReflectSentNotifications()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.
TEST_F(P2PInvalidatorTest,P2PNotificationTarget)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.
TEST_F(P2PInvalidatorTest,P2PNotificationDataIsTargeted)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.
TEST_F(P2PInvalidatorTest,P2PNotificationDataDefault)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.
TEST_F(P2PInvalidatorTest,P2PNotificationDataNonDefault)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().
TEST_F(P2PInvalidatorTest,NotificationsBasic)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@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.
TEST_F(P2PInvalidatorTest,SendNotificationData)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@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