• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/notifier/fake_invalidation_handler.h"
12 #include "sync/notifier/invalidator_test_template.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 
15 namespace syncer {
16 
17 namespace {
18 
19 class P2PInvalidatorTestDelegate {
20  public:
P2PInvalidatorTestDelegate()21   P2PInvalidatorTestDelegate() : fake_push_client_(NULL) {}
22 
~P2PInvalidatorTestDelegate()23   ~P2PInvalidatorTestDelegate() {
24     DestroyInvalidator();
25   }
26 
CreateInvalidator(const std::string & invalidator_client_id,const std::string & initial_state,const base::WeakPtr<InvalidationStateTracker> & invalidation_state_tracker)27   void CreateInvalidator(
28       const std::string& invalidator_client_id,
29       const std::string& initial_state,
30       const base::WeakPtr<InvalidationStateTracker>&
31           invalidation_state_tracker) {
32     DCHECK(!fake_push_client_);
33     DCHECK(!invalidator_.get());
34     fake_push_client_ = new notifier::FakePushClient();
35     invalidator_.reset(
36         new P2PInvalidator(
37             scoped_ptr<notifier::PushClient>(fake_push_client_),
38             invalidator_client_id,
39             NOTIFY_OTHERS));
40   }
41 
GetInvalidator()42   P2PInvalidator* GetInvalidator() {
43     return invalidator_.get();
44   }
45 
GetPushClient()46   notifier::FakePushClient* GetPushClient() {
47     return fake_push_client_;
48   }
49 
DestroyInvalidator()50   void DestroyInvalidator() {
51     invalidator_.reset();
52     fake_push_client_ = NULL;
53   }
54 
WaitForInvalidator()55   void WaitForInvalidator() {
56     // Do Nothing.
57   }
58 
TriggerOnInvalidatorStateChange(InvalidatorState state)59   void TriggerOnInvalidatorStateChange(InvalidatorState state) {
60     if (state == INVALIDATIONS_ENABLED) {
61       fake_push_client_->EnableNotifications();
62     } else {
63       fake_push_client_->DisableNotifications(ToNotifierReasonForTest(state));
64     }
65   }
66 
TriggerOnIncomingInvalidation(const ObjectIdInvalidationMap & invalidation_map)67   void TriggerOnIncomingInvalidation(
68       const ObjectIdInvalidationMap& invalidation_map) {
69     const P2PNotificationData notification_data(
70         std::string(), NOTIFY_ALL, invalidation_map);
71     notifier::Notification notification;
72     notification.channel = kSyncP2PNotificationChannel;
73     notification.data = notification_data.ToString();
74     fake_push_client_->SimulateIncomingNotification(notification);
75   }
76 
77  private:
78   // Owned by |invalidator_|.
79   notifier::FakePushClient* fake_push_client_;
80   scoped_ptr<P2PInvalidator> invalidator_;
81 };
82 
83 class P2PInvalidatorTest : public testing::Test {
84  protected:
P2PInvalidatorTest()85   P2PInvalidatorTest()
86       : next_sent_notification_to_reflect_(0) {
87     delegate_.CreateInvalidator("sender",
88                                 "fake_state",
89                                 base::WeakPtr<InvalidationStateTracker>());
90     delegate_.GetInvalidator()->RegisterHandler(&fake_handler_);
91   }
92 
~P2PInvalidatorTest()93   virtual ~P2PInvalidatorTest() {
94     delegate_.GetInvalidator()->UnregisterHandler(&fake_handler_);
95   }
96 
MakeInvalidationMap(ModelTypeSet types)97   ObjectIdInvalidationMap MakeInvalidationMap(ModelTypeSet types) {
98     ObjectIdInvalidationMap invalidations;
99     ObjectIdSet ids = ModelTypeSetToObjectIdSet(types);
100     return ObjectIdInvalidationMap::InvalidateAll(ids);
101   }
102 
103   // Simulate receiving all the notifications we sent out since last
104   // time this was called.
ReflectSentNotifications()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.
TEST_F(P2PInvalidatorTest,P2PNotificationTarget)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.
TEST_F(P2PInvalidatorTest,P2PNotificationDataIsTargeted)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.
TEST_F(P2PInvalidatorTest,P2PNotificationDataDefault)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       "{\"invalidations\":[],\"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.
TEST_F(P2PInvalidatorTest,P2PNotificationDataNonDefault)179 TEST_F(P2PInvalidatorTest, P2PNotificationDataNonDefault) {
180   ObjectIdInvalidationMap invalidation_map =
181       ObjectIdInvalidationMap::InvalidateAll(
182           ModelTypeSetToObjectIdSet(ModelTypeSet(BOOKMARKS, THEMES)));
183   const P2PNotificationData notification_data("sender",
184                                               NOTIFY_ALL,
185                                               invalidation_map);
186   EXPECT_TRUE(notification_data.IsTargeted("sender"));
187   EXPECT_TRUE(notification_data.IsTargeted("other1"));
188   EXPECT_TRUE(notification_data.IsTargeted("other2"));
189   EXPECT_EQ(invalidation_map, notification_data.GetIdInvalidationMap());
190   const std::string& notification_data_str = notification_data.ToString();
191   EXPECT_EQ(
192       "{\"invalidations\":["
193       "{\"isUnknownVersion\":true,"
194        "\"objectId\":{\"name\":\"BOOKMARK\",\"source\":1004}},"
195       "{\"isUnknownVersion\":true,"
196        "\"objectId\":{\"name\":\"THEME\",\"source\":1004}}"
197       "],\"notificationType\":\"notifyAll\","
198       "\"senderId\":\"sender\"}", notification_data_str);
199 
200   P2PNotificationData notification_data_parsed;
201   EXPECT_TRUE(notification_data_parsed.ResetFromString(notification_data_str));
202   EXPECT_TRUE(notification_data.Equals(notification_data_parsed));
203 }
204 
205 // Set up the P2PInvalidator, simulate a successful connection, and send
206 // a notification with the default target (NOTIFY_OTHERS).  The
207 // observer should receive only a notification from the call to
208 // UpdateEnabledTypes().
TEST_F(P2PInvalidatorTest,NotificationsBasic)209 TEST_F(P2PInvalidatorTest, NotificationsBasic) {
210   const ModelTypeSet enabled_types(BOOKMARKS, PREFERENCES);
211 
212   P2PInvalidator* const invalidator = delegate_.GetInvalidator();
213   notifier::FakePushClient* const push_client = delegate_.GetPushClient();
214 
215   invalidator->UpdateRegisteredIds(&fake_handler_,
216                                    ModelTypeSetToObjectIdSet(enabled_types));
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(
239       MakeInvalidationMap(enabled_types),
240       Eq(fake_handler_.GetLastInvalidationMap()));
241 
242   // Sent with target NOTIFY_OTHERS so should not be propagated to
243   // |fake_handler_|.
244   invalidator->SendInvalidation(
245       ModelTypeSetToObjectIdSet(ModelTypeSet(THEMES, APPS)));
246 
247   ReflectSentNotifications();
248   EXPECT_EQ(1, fake_handler_.GetInvalidationCount());
249 }
250 
251 // Set up the P2PInvalidator and send out notifications with various
252 // target settings.  The notifications received by the observer should
253 // be consistent with the target settings.
TEST_F(P2PInvalidatorTest,SendNotificationData)254 TEST_F(P2PInvalidatorTest, SendNotificationData) {
255   const ModelTypeSet enabled_types(BOOKMARKS, PREFERENCES, THEMES);
256   const ModelTypeSet changed_types(THEMES, APPS);
257   const ModelTypeSet expected_types(THEMES);
258 
259   const ObjectIdInvalidationMap& invalidation_map =
260       MakeInvalidationMap(changed_types);
261 
262   P2PInvalidator* const invalidator = delegate_.GetInvalidator();
263   notifier::FakePushClient* const push_client = delegate_.GetPushClient();
264 
265   invalidator->UpdateRegisteredIds(&fake_handler_,
266                                    ModelTypeSetToObjectIdSet(enabled_types));
267 
268   invalidator->UpdateCredentials("foo@bar.com", "fake_token");
269 
270   ReflectSentNotifications();
271   push_client->EnableNotifications();
272   EXPECT_EQ(INVALIDATIONS_ENABLED, fake_handler_.GetInvalidatorState());
273 
274   ReflectSentNotifications();
275   EXPECT_EQ(1, fake_handler_.GetInvalidationCount());
276   EXPECT_EQ(ModelTypeSetToObjectIdSet(enabled_types),
277             fake_handler_.GetLastInvalidationMap().GetObjectIds());
278 
279   // Should be dropped.
280   invalidator->SendNotificationDataForTest(P2PNotificationData());
281   ReflectSentNotifications();
282   EXPECT_EQ(1, fake_handler_.GetInvalidationCount());
283 
284   const ObjectIdSet& expected_ids = ModelTypeSetToObjectIdSet(expected_types);
285 
286   // Should be propagated.
287   invalidator->SendNotificationDataForTest(
288       P2PNotificationData("sender", NOTIFY_SELF, invalidation_map));
289   ReflectSentNotifications();
290   EXPECT_EQ(2, fake_handler_.GetInvalidationCount());
291   EXPECT_EQ(expected_ids,
292             fake_handler_.GetLastInvalidationMap().GetObjectIds());
293 
294   // Should be dropped.
295   invalidator->SendNotificationDataForTest(
296       P2PNotificationData("sender2", NOTIFY_SELF, invalidation_map));
297   ReflectSentNotifications();
298   EXPECT_EQ(2, fake_handler_.GetInvalidationCount());
299 
300   // Should be dropped.
301   invalidator->SendNotificationDataForTest(
302       P2PNotificationData("sender", NOTIFY_SELF, ObjectIdInvalidationMap()));
303   ReflectSentNotifications();
304   EXPECT_EQ(2, fake_handler_.GetInvalidationCount());
305 
306   // Should be dropped.
307   invalidator->SendNotificationDataForTest(
308       P2PNotificationData("sender", NOTIFY_OTHERS, invalidation_map));
309   ReflectSentNotifications();
310   EXPECT_EQ(2, fake_handler_.GetInvalidationCount());
311 
312   // Should be propagated.
313   invalidator->SendNotificationDataForTest(
314       P2PNotificationData("sender2", NOTIFY_OTHERS, invalidation_map));
315   ReflectSentNotifications();
316   EXPECT_EQ(3, fake_handler_.GetInvalidationCount());
317   EXPECT_EQ(expected_ids,
318             fake_handler_.GetLastInvalidationMap().GetObjectIds());
319 
320   // Should be dropped.
321   invalidator->SendNotificationDataForTest(
322       P2PNotificationData("sender2", NOTIFY_OTHERS, ObjectIdInvalidationMap()));
323   ReflectSentNotifications();
324   EXPECT_EQ(3, fake_handler_.GetInvalidationCount());
325 
326   // Should be propagated.
327   invalidator->SendNotificationDataForTest(
328       P2PNotificationData("sender", NOTIFY_ALL, invalidation_map));
329   ReflectSentNotifications();
330   EXPECT_EQ(4, fake_handler_.GetInvalidationCount());
331   EXPECT_EQ(expected_ids,
332             fake_handler_.GetLastInvalidationMap().GetObjectIds());
333 
334   // Should be propagated.
335   invalidator->SendNotificationDataForTest(
336       P2PNotificationData("sender2", NOTIFY_ALL, invalidation_map));
337   ReflectSentNotifications();
338   EXPECT_EQ(5, fake_handler_.GetInvalidationCount());
339   EXPECT_EQ(expected_ids,
340             fake_handler_.GetLastInvalidationMap().GetObjectIds());
341 
342   // Should be dropped.
343   invalidator->SendNotificationDataForTest(
344   P2PNotificationData("sender2", NOTIFY_ALL, ObjectIdInvalidationMap()));
345   ReflectSentNotifications();
346   EXPECT_EQ(5, fake_handler_.GetInvalidationCount());
347 }
348 
349 INSTANTIATE_TYPED_TEST_CASE_P(
350     P2PInvalidatorTest, InvalidatorTest,
351     P2PInvalidatorTestDelegate);
352 
353 }  // namespace
354 
355 }  // namespace syncer
356