• 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 "sync/engine/get_updates_processor.h"
6 
7 #include "base/message_loop/message_loop.h"
8 #include "base/stl_util.h"
9 #include "sync/engine/get_updates_delegate.h"
10 #include "sync/engine/update_handler.h"
11 #include "sync/internal_api/public/base/model_type_test_util.h"
12 #include "sync/protocol/sync.pb.h"
13 #include "sync/sessions/debug_info_getter.h"
14 #include "sync/sessions/nudge_tracker.h"
15 #include "sync/sessions/status_controller.h"
16 #include "sync/test/engine/fake_model_worker.h"
17 #include "sync/test/engine/mock_update_handler.h"
18 #include "sync/test/sessions/mock_debug_info_getter.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 
21 namespace syncer {
22 
23 using sessions::MockDebugInfoGetter;
24 
25 // A test fixture for tests exercising download updates functions.
26 class GetUpdatesProcessorTest : public ::testing::Test {
27  protected:
GetUpdatesProcessorTest()28   GetUpdatesProcessorTest() :
29     kTestStartTime(base::TimeTicks::Now()),
30     update_handler_deleter_(&update_handler_map_) {}
31 
SetUp()32   virtual void SetUp() {
33     AddUpdateHandler(AUTOFILL);
34     AddUpdateHandler(BOOKMARKS);
35     AddUpdateHandler(PREFERENCES);
36   }
37 
enabled_types()38   ModelTypeSet enabled_types() {
39     return enabled_types_;
40   }
41 
BuildGetUpdatesProcessor(const GetUpdatesDelegate & delegate)42   scoped_ptr<GetUpdatesProcessor> BuildGetUpdatesProcessor(
43       const GetUpdatesDelegate& delegate) {
44     return scoped_ptr<GetUpdatesProcessor>(
45         new GetUpdatesProcessor(&update_handler_map_, delegate));
46   }
47 
InitFakeUpdateResponse(sync_pb::GetUpdatesResponse * response)48   void InitFakeUpdateResponse(sync_pb::GetUpdatesResponse* response) {
49     ModelTypeSet types = enabled_types();
50 
51     for (ModelTypeSet::Iterator it = types.First(); it.Good(); it.Inc()) {
52       sync_pb::DataTypeProgressMarker* marker =
53           response->add_new_progress_marker();
54       marker->set_data_type_id(GetSpecificsFieldNumberFromModelType(it.Get()));
55       marker->set_token("foobarbaz");
56       sync_pb::DataTypeContext* context = response->add_context_mutations();
57       context->set_data_type_id(GetSpecificsFieldNumberFromModelType(it.Get()));
58       context->set_version(1);
59       context->set_context("context");
60     }
61 
62     response->set_changes_remaining(0);
63   }
64 
GetHandler(ModelType type)65   const UpdateHandler* GetHandler(ModelType type) {
66     UpdateHandlerMap::iterator it = update_handler_map_.find(type);
67     if (it == update_handler_map_.end())
68       return NULL;
69     return it->second;
70   }
71 
72   const base::TimeTicks kTestStartTime;
73 
74  protected:
AddUpdateHandler(ModelType type)75   MockUpdateHandler* AddUpdateHandler(ModelType type) {
76     enabled_types_.Put(type);
77 
78     MockUpdateHandler* handler = new MockUpdateHandler(type);
79     update_handler_map_.insert(std::make_pair(type, handler));
80 
81     return handler;
82   }
83 
84  private:
85   ModelTypeSet enabled_types_;
86   UpdateHandlerMap update_handler_map_;
87   STLValueDeleter<UpdateHandlerMap> update_handler_deleter_;
88   scoped_ptr<GetUpdatesProcessor> get_updates_processor_;
89 
90   DISALLOW_COPY_AND_ASSIGN(GetUpdatesProcessorTest);
91 };
92 
93 // Basic test to make sure nudges are expressed properly in the request.
TEST_F(GetUpdatesProcessorTest,BookmarkNudge)94 TEST_F(GetUpdatesProcessorTest, BookmarkNudge) {
95   sessions::NudgeTracker nudge_tracker;
96   nudge_tracker.RecordLocalChange(ModelTypeSet(BOOKMARKS));
97 
98   sync_pb::ClientToServerMessage message;
99   NormalGetUpdatesDelegate normal_delegate(nudge_tracker);
100   scoped_ptr<GetUpdatesProcessor> processor(
101       BuildGetUpdatesProcessor(normal_delegate));
102   processor->PrepareGetUpdates(enabled_types(), &message);
103 
104   const sync_pb::GetUpdatesMessage& gu_msg = message.get_updates();
105   EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::LOCAL,
106             gu_msg.caller_info().source());
107   EXPECT_EQ(sync_pb::SyncEnums::GU_TRIGGER, gu_msg.get_updates_origin());
108   for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) {
109     syncer::ModelType type = GetModelTypeFromSpecificsFieldNumber(
110         gu_msg.from_progress_marker(i).data_type_id());
111 
112     const sync_pb::DataTypeProgressMarker& progress_marker =
113         gu_msg.from_progress_marker(i);
114     const sync_pb::GetUpdateTriggers& gu_trigger =
115         progress_marker.get_update_triggers();
116 
117     // We perform some basic tests of GU trigger and source fields here.  The
118     // more complicated scenarios are tested by the NudgeTracker tests.
119     if (type == BOOKMARKS) {
120       EXPECT_TRUE(progress_marker.has_notification_hint());
121       EXPECT_EQ("", progress_marker.notification_hint());
122       EXPECT_EQ(1, gu_trigger.local_modification_nudges());
123       EXPECT_EQ(0, gu_trigger.datatype_refresh_nudges());
124     } else {
125       EXPECT_FALSE(progress_marker.has_notification_hint());
126       EXPECT_EQ(0, gu_trigger.local_modification_nudges());
127       EXPECT_EQ(0, gu_trigger.datatype_refresh_nudges());
128     }
129   }
130 }
131 
132 // Basic test to ensure invalidation payloads are expressed in the request.
TEST_F(GetUpdatesProcessorTest,NotifyMany)133 TEST_F(GetUpdatesProcessorTest, NotifyMany) {
134   sessions::NudgeTracker nudge_tracker;
135   nudge_tracker.RecordRemoteInvalidation(
136       BuildInvalidationMap(AUTOFILL, 1, "autofill_payload"));
137   nudge_tracker.RecordRemoteInvalidation(
138       BuildInvalidationMap(BOOKMARKS, 1, "bookmark_payload"));
139   nudge_tracker.RecordRemoteInvalidation(
140       BuildInvalidationMap(PREFERENCES, 1, "preferences_payload"));
141   ModelTypeSet notified_types;
142   notified_types.Put(AUTOFILL);
143   notified_types.Put(BOOKMARKS);
144   notified_types.Put(PREFERENCES);
145 
146   sync_pb::ClientToServerMessage message;
147   NormalGetUpdatesDelegate normal_delegate(nudge_tracker);
148   scoped_ptr<GetUpdatesProcessor> processor(
149       BuildGetUpdatesProcessor(normal_delegate));
150   processor->PrepareGetUpdates(enabled_types(), &message);
151 
152   const sync_pb::GetUpdatesMessage& gu_msg = message.get_updates();
153   EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::NOTIFICATION,
154             gu_msg.caller_info().source());
155   EXPECT_EQ(sync_pb::SyncEnums::GU_TRIGGER, gu_msg.get_updates_origin());
156   for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) {
157     syncer::ModelType type = GetModelTypeFromSpecificsFieldNumber(
158         gu_msg.from_progress_marker(i).data_type_id());
159 
160     const sync_pb::DataTypeProgressMarker& progress_marker =
161         gu_msg.from_progress_marker(i);
162     const sync_pb::GetUpdateTriggers& gu_trigger =
163         progress_marker.get_update_triggers();
164 
165     // We perform some basic tests of GU trigger and source fields here.  The
166     // more complicated scenarios are tested by the NudgeTracker tests.
167     if (notified_types.Has(type)) {
168       EXPECT_TRUE(progress_marker.has_notification_hint());
169       EXPECT_FALSE(progress_marker.notification_hint().empty());
170       EXPECT_EQ(1, gu_trigger.notification_hint_size());
171     } else {
172       EXPECT_FALSE(progress_marker.has_notification_hint());
173       EXPECT_EQ(0, gu_trigger.notification_hint_size());
174     }
175   }
176 }
177 
TEST_F(GetUpdatesProcessorTest,ConfigureTest)178 TEST_F(GetUpdatesProcessorTest, ConfigureTest) {
179   sync_pb::ClientToServerMessage message;
180   ConfigureGetUpdatesDelegate configure_delegate(
181       sync_pb::GetUpdatesCallerInfo::RECONFIGURATION);
182   scoped_ptr<GetUpdatesProcessor> processor(
183       BuildGetUpdatesProcessor(configure_delegate));
184   processor->PrepareGetUpdates(enabled_types(), &message);
185 
186   const sync_pb::GetUpdatesMessage& gu_msg = message.get_updates();
187   EXPECT_EQ(sync_pb::SyncEnums::RECONFIGURATION, gu_msg.get_updates_origin());
188   EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RECONFIGURATION,
189             gu_msg.caller_info().source());
190 
191   ModelTypeSet progress_types;
192   for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) {
193     syncer::ModelType type = GetModelTypeFromSpecificsFieldNumber(
194         gu_msg.from_progress_marker(i).data_type_id());
195     progress_types.Put(type);
196   }
197   EXPECT_TRUE(enabled_types().Equals(progress_types));
198 }
199 
TEST_F(GetUpdatesProcessorTest,PollTest)200 TEST_F(GetUpdatesProcessorTest, PollTest) {
201   sync_pb::ClientToServerMessage message;
202   PollGetUpdatesDelegate poll_delegate;
203   scoped_ptr<GetUpdatesProcessor> processor(
204       BuildGetUpdatesProcessor(poll_delegate));
205   processor->PrepareGetUpdates(enabled_types(), &message);
206 
207   const sync_pb::GetUpdatesMessage& gu_msg = message.get_updates();
208   EXPECT_EQ(sync_pb::SyncEnums::PERIODIC, gu_msg.get_updates_origin());
209   EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::PERIODIC,
210             gu_msg.caller_info().source());
211 
212   ModelTypeSet progress_types;
213   for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) {
214     syncer::ModelType type = GetModelTypeFromSpecificsFieldNumber(
215         gu_msg.from_progress_marker(i).data_type_id());
216     progress_types.Put(type);
217   }
218   EXPECT_TRUE(enabled_types().Equals(progress_types));
219 }
220 
TEST_F(GetUpdatesProcessorTest,RetryTest)221 TEST_F(GetUpdatesProcessorTest, RetryTest) {
222   sessions::NudgeTracker nudge_tracker;
223 
224   // Schedule a retry.
225   base::TimeTicks t1 = kTestStartTime;
226   nudge_tracker.SetNextRetryTime(t1);
227 
228   // Get the nudge tracker to think the retry is due.
229   nudge_tracker.SetSyncCycleStartTime(t1 + base::TimeDelta::FromSeconds(1));
230 
231   sync_pb::ClientToServerMessage message;
232   NormalGetUpdatesDelegate normal_delegate(nudge_tracker);
233   scoped_ptr<GetUpdatesProcessor> processor(
234       BuildGetUpdatesProcessor(normal_delegate));
235   processor->PrepareGetUpdates(enabled_types(), &message);
236 
237   const sync_pb::GetUpdatesMessage& gu_msg = message.get_updates();
238   EXPECT_EQ(sync_pb::SyncEnums::RETRY, gu_msg.get_updates_origin());
239   EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RETRY,
240             gu_msg.caller_info().source());
241   EXPECT_TRUE(gu_msg.is_retry());
242 
243   ModelTypeSet progress_types;
244   for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) {
245     syncer::ModelType type = GetModelTypeFromSpecificsFieldNumber(
246         gu_msg.from_progress_marker(i).data_type_id());
247     progress_types.Put(type);
248   }
249   EXPECT_TRUE(enabled_types().Equals(progress_types));
250 }
251 
TEST_F(GetUpdatesProcessorTest,NudgeWithRetryTest)252 TEST_F(GetUpdatesProcessorTest, NudgeWithRetryTest) {
253   sessions::NudgeTracker nudge_tracker;
254 
255   // Schedule a retry.
256   base::TimeTicks t1 = kTestStartTime;
257   nudge_tracker.SetNextRetryTime(t1);
258 
259   // Get the nudge tracker to think the retry is due.
260   nudge_tracker.SetSyncCycleStartTime(t1 + base::TimeDelta::FromSeconds(1));
261 
262   // Record a local change, too.
263   nudge_tracker.RecordLocalChange(ModelTypeSet(BOOKMARKS));
264 
265   sync_pb::ClientToServerMessage message;
266   NormalGetUpdatesDelegate normal_delegate(nudge_tracker);
267   scoped_ptr<GetUpdatesProcessor> processor(
268       BuildGetUpdatesProcessor(normal_delegate));
269   processor->PrepareGetUpdates(enabled_types(), &message);
270 
271   const sync_pb::GetUpdatesMessage& gu_msg = message.get_updates();
272   EXPECT_NE(sync_pb::SyncEnums::RETRY, gu_msg.get_updates_origin());
273   EXPECT_NE(sync_pb::GetUpdatesCallerInfo::RETRY,
274             gu_msg.caller_info().source());
275 
276   EXPECT_TRUE(gu_msg.is_retry());
277 }
278 
279 // Verify that a bogus response message is detected.
TEST_F(GetUpdatesProcessorTest,InvalidResponse)280 TEST_F(GetUpdatesProcessorTest, InvalidResponse) {
281   sync_pb::GetUpdatesResponse gu_response;
282   InitFakeUpdateResponse(&gu_response);
283 
284   // This field is essential for making the client stop looping.  If it's unset
285   // then something is very wrong.  The client should detect this.
286   gu_response.clear_changes_remaining();
287 
288   sessions::NudgeTracker nudge_tracker;
289   NormalGetUpdatesDelegate normal_delegate(nudge_tracker);
290   sessions::StatusController status;
291   scoped_ptr<GetUpdatesProcessor> processor(
292       BuildGetUpdatesProcessor(normal_delegate));
293   SyncerError error = processor->ProcessResponse(gu_response,
294                                                  enabled_types(),
295                                                  &status);
296   EXPECT_EQ(error, SERVER_RESPONSE_VALIDATION_FAILED);
297 }
298 
299 // Verify that we correctly detect when there's more work to be done.
TEST_F(GetUpdatesProcessorTest,MoreToDownloadResponse)300 TEST_F(GetUpdatesProcessorTest, MoreToDownloadResponse) {
301   sync_pb::GetUpdatesResponse gu_response;
302   InitFakeUpdateResponse(&gu_response);
303   gu_response.set_changes_remaining(1);
304 
305   sessions::NudgeTracker nudge_tracker;
306   NormalGetUpdatesDelegate normal_delegate(nudge_tracker);
307   sessions::StatusController status;
308   scoped_ptr<GetUpdatesProcessor> processor(
309       BuildGetUpdatesProcessor(normal_delegate));
310   SyncerError error = processor->ProcessResponse(gu_response,
311                                                  enabled_types(),
312                                                  &status);
313   EXPECT_EQ(error, SERVER_MORE_TO_DOWNLOAD);
314 }
315 
316 // A simple scenario: No updates returned and nothing more to download.
TEST_F(GetUpdatesProcessorTest,NormalResponseTest)317 TEST_F(GetUpdatesProcessorTest, NormalResponseTest) {
318   sync_pb::GetUpdatesResponse gu_response;
319   InitFakeUpdateResponse(&gu_response);
320   gu_response.set_changes_remaining(0);
321 
322   sessions::NudgeTracker nudge_tracker;
323   NormalGetUpdatesDelegate normal_delegate(nudge_tracker);
324   sessions::StatusController status;
325   scoped_ptr<GetUpdatesProcessor> processor(
326       BuildGetUpdatesProcessor(normal_delegate));
327   SyncerError error = processor->ProcessResponse(gu_response,
328                                                  enabled_types(),
329                                                  &status);
330   EXPECT_EQ(error, SYNCER_OK);
331 }
332 
333 // Variant of GetUpdatesProcessor test designed to test update application.
334 //
335 // Maintains two enabled types, but requests that updates be applied for only
336 // one of them.
337 class GetUpdatesProcessorApplyUpdatesTest : public GetUpdatesProcessorTest {
338  public:
GetUpdatesProcessorApplyUpdatesTest()339   GetUpdatesProcessorApplyUpdatesTest() {}
~GetUpdatesProcessorApplyUpdatesTest()340   virtual ~GetUpdatesProcessorApplyUpdatesTest() {}
341 
SetUp()342   virtual void SetUp() OVERRIDE {
343     bookmarks_handler_ = AddUpdateHandler(BOOKMARKS);
344     autofill_handler_ = AddUpdateHandler(AUTOFILL);
345   }
346 
GetGuTypes()347   ModelTypeSet GetGuTypes() {
348     return ModelTypeSet(AUTOFILL);
349   }
350 
GetNonAppliedHandler()351   MockUpdateHandler* GetNonAppliedHandler() {
352     return bookmarks_handler_;
353   }
354 
GetAppliedHandler()355   MockUpdateHandler* GetAppliedHandler() {
356     return autofill_handler_;
357   }
358 
359  private:
360   MockUpdateHandler* bookmarks_handler_;
361   MockUpdateHandler* autofill_handler_;
362 };
363 
364 // Verify that a normal cycle applies updates non-passively to the specified
365 // types.
TEST_F(GetUpdatesProcessorApplyUpdatesTest,Normal)366 TEST_F(GetUpdatesProcessorApplyUpdatesTest, Normal) {
367   sessions::NudgeTracker nudge_tracker;
368   NormalGetUpdatesDelegate normal_delegate(nudge_tracker);
369   scoped_ptr<GetUpdatesProcessor> processor(
370       BuildGetUpdatesProcessor(normal_delegate));
371 
372   EXPECT_EQ(0, GetNonAppliedHandler()->GetApplyUpdatesCount());
373   EXPECT_EQ(0, GetAppliedHandler()->GetApplyUpdatesCount());
374 
375   sessions::StatusController status;
376   processor->ApplyUpdates(GetGuTypes(), &status);
377 
378   EXPECT_EQ(0, GetNonAppliedHandler()->GetApplyUpdatesCount());
379   EXPECT_EQ(1, GetAppliedHandler()->GetApplyUpdatesCount());
380 
381   EXPECT_EQ(0, GetNonAppliedHandler()->GetPassiveApplyUpdatesCount());
382   EXPECT_EQ(0, GetAppliedHandler()->GetPassiveApplyUpdatesCount());
383 }
384 
385 // Verify that a configure cycle applies updates passively to the specified
386 // types.
TEST_F(GetUpdatesProcessorApplyUpdatesTest,Configure)387 TEST_F(GetUpdatesProcessorApplyUpdatesTest, Configure) {
388   ConfigureGetUpdatesDelegate configure_delegate(
389       sync_pb::GetUpdatesCallerInfo::RECONFIGURATION);
390   scoped_ptr<GetUpdatesProcessor> processor(
391       BuildGetUpdatesProcessor(configure_delegate));
392 
393   EXPECT_EQ(0, GetNonAppliedHandler()->GetPassiveApplyUpdatesCount());
394   EXPECT_EQ(0, GetAppliedHandler()->GetPassiveApplyUpdatesCount());
395 
396   sessions::StatusController status;
397   processor->ApplyUpdates(GetGuTypes(), &status);
398 
399   EXPECT_EQ(0, GetNonAppliedHandler()->GetPassiveApplyUpdatesCount());
400   EXPECT_EQ(1, GetAppliedHandler()->GetPassiveApplyUpdatesCount());
401 
402   EXPECT_EQ(0, GetNonAppliedHandler()->GetApplyUpdatesCount());
403   EXPECT_EQ(0, GetAppliedHandler()->GetApplyUpdatesCount());
404 }
405 
406 // Verify that a poll cycle applies updates non-passively to the specified
407 // types.
TEST_F(GetUpdatesProcessorApplyUpdatesTest,Poll)408 TEST_F(GetUpdatesProcessorApplyUpdatesTest, Poll) {
409   PollGetUpdatesDelegate poll_delegate;
410   scoped_ptr<GetUpdatesProcessor> processor(
411       BuildGetUpdatesProcessor(poll_delegate));
412 
413   EXPECT_EQ(0, GetNonAppliedHandler()->GetApplyUpdatesCount());
414   EXPECT_EQ(0, GetAppliedHandler()->GetApplyUpdatesCount());
415 
416   sessions::StatusController status;
417   processor->ApplyUpdates(GetGuTypes(), &status);
418 
419   EXPECT_EQ(0, GetNonAppliedHandler()->GetApplyUpdatesCount());
420   EXPECT_EQ(1, GetAppliedHandler()->GetApplyUpdatesCount());
421 
422   EXPECT_EQ(0, GetNonAppliedHandler()->GetPassiveApplyUpdatesCount());
423   EXPECT_EQ(0, GetAppliedHandler()->GetPassiveApplyUpdatesCount());
424 }
425 
426 class DownloadUpdatesDebugInfoTest : public ::testing::Test {
427  public:
DownloadUpdatesDebugInfoTest()428   DownloadUpdatesDebugInfoTest() {}
~DownloadUpdatesDebugInfoTest()429   virtual ~DownloadUpdatesDebugInfoTest() {}
430 
status()431   sessions::StatusController* status() {
432     return &status_;
433   }
434 
debug_info_getter()435   sessions::DebugInfoGetter* debug_info_getter() {
436     return &debug_info_getter_;
437   }
438 
AddDebugEvent()439   void AddDebugEvent() {
440     debug_info_getter_.AddDebugEvent();
441   }
442 
443  private:
444   sessions::StatusController status_;
445   MockDebugInfoGetter debug_info_getter_;
446 };
447 
448 // Verify CopyClientDebugInfo when there are no events to upload.
TEST_F(DownloadUpdatesDebugInfoTest,VerifyCopyClientDebugInfo_Empty)449 TEST_F(DownloadUpdatesDebugInfoTest, VerifyCopyClientDebugInfo_Empty) {
450   sync_pb::DebugInfo debug_info;
451   GetUpdatesProcessor::CopyClientDebugInfo(debug_info_getter(), &debug_info);
452   EXPECT_EQ(0, debug_info.events_size());
453 }
454 
TEST_F(DownloadUpdatesDebugInfoTest,VerifyCopyOverwrites)455 TEST_F(DownloadUpdatesDebugInfoTest, VerifyCopyOverwrites) {
456   sync_pb::DebugInfo debug_info;
457   AddDebugEvent();
458   GetUpdatesProcessor::CopyClientDebugInfo(debug_info_getter(), &debug_info);
459   EXPECT_EQ(1, debug_info.events_size());
460   GetUpdatesProcessor::CopyClientDebugInfo(debug_info_getter(), &debug_info);
461   EXPECT_EQ(1, debug_info.events_size());
462 }
463 
464 }  // namespace syncer
465