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