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.
5 #include "sync/engine/get_updates_processor.h"
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/mock_invalidation.h"
19 #include "sync/test/sessions/mock_debug_info_getter.h"
20 #include "testing/gtest/include/gtest/gtest.h"
26 scoped_ptr
<InvalidationInterface
> BuildInvalidation(
28 const std::string
& payload
) {
29 return MockInvalidation::Build(version
, payload
)
30 .PassAs
<InvalidationInterface
>();
35 using sessions::MockDebugInfoGetter
;
37 // A test fixture for tests exercising download updates functions.
38 class GetUpdatesProcessorTest
: public ::testing::Test
{
40 GetUpdatesProcessorTest() :
41 kTestStartTime(base::TimeTicks::Now()),
42 update_handler_deleter_(&update_handler_map_
) {}
44 virtual void SetUp() {
45 AddUpdateHandler(AUTOFILL
);
46 AddUpdateHandler(BOOKMARKS
);
47 AddUpdateHandler(PREFERENCES
);
50 ModelTypeSet
enabled_types() {
51 return enabled_types_
;
54 scoped_ptr
<GetUpdatesProcessor
> BuildGetUpdatesProcessor(
55 const GetUpdatesDelegate
& delegate
) {
56 return scoped_ptr
<GetUpdatesProcessor
>(
57 new GetUpdatesProcessor(&update_handler_map_
, delegate
));
60 void InitFakeUpdateResponse(sync_pb::GetUpdatesResponse
* response
) {
61 ModelTypeSet types
= enabled_types();
63 for (ModelTypeSet::Iterator it
= types
.First(); it
.Good(); it
.Inc()) {
64 sync_pb::DataTypeProgressMarker
* marker
=
65 response
->add_new_progress_marker();
66 marker
->set_data_type_id(GetSpecificsFieldNumberFromModelType(it
.Get()));
67 marker
->set_token("foobarbaz");
68 sync_pb::DataTypeContext
* context
= response
->add_context_mutations();
69 context
->set_data_type_id(GetSpecificsFieldNumberFromModelType(it
.Get()));
70 context
->set_version(1);
71 context
->set_context("context");
74 response
->set_changes_remaining(0);
77 const UpdateHandler
* GetHandler(ModelType type
) {
78 UpdateHandlerMap::iterator it
= update_handler_map_
.find(type
);
79 if (it
== update_handler_map_
.end())
84 const base::TimeTicks kTestStartTime
;
87 MockUpdateHandler
* AddUpdateHandler(ModelType type
) {
88 enabled_types_
.Put(type
);
90 MockUpdateHandler
* handler
= new MockUpdateHandler(type
);
91 update_handler_map_
.insert(std::make_pair(type
, handler
));
97 ModelTypeSet enabled_types_
;
98 UpdateHandlerMap update_handler_map_
;
99 STLValueDeleter
<UpdateHandlerMap
> update_handler_deleter_
;
100 scoped_ptr
<GetUpdatesProcessor
> get_updates_processor_
;
102 DISALLOW_COPY_AND_ASSIGN(GetUpdatesProcessorTest
);
105 // Basic test to make sure nudges are expressed properly in the request.
106 TEST_F(GetUpdatesProcessorTest
, BookmarkNudge
) {
107 sessions::NudgeTracker nudge_tracker
;
108 nudge_tracker
.RecordLocalChange(ModelTypeSet(BOOKMARKS
));
110 sync_pb::ClientToServerMessage message
;
111 NormalGetUpdatesDelegate
normal_delegate(nudge_tracker
);
112 scoped_ptr
<GetUpdatesProcessor
> processor(
113 BuildGetUpdatesProcessor(normal_delegate
));
114 processor
->PrepareGetUpdates(enabled_types(), &message
);
116 const sync_pb::GetUpdatesMessage
& gu_msg
= message
.get_updates();
117 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::LOCAL
,
118 gu_msg
.caller_info().source());
119 EXPECT_EQ(sync_pb::SyncEnums::GU_TRIGGER
, gu_msg
.get_updates_origin());
120 for (int i
= 0; i
< gu_msg
.from_progress_marker_size(); ++i
) {
121 syncer::ModelType type
= GetModelTypeFromSpecificsFieldNumber(
122 gu_msg
.from_progress_marker(i
).data_type_id());
124 const sync_pb::DataTypeProgressMarker
& progress_marker
=
125 gu_msg
.from_progress_marker(i
);
126 const sync_pb::GetUpdateTriggers
& gu_trigger
=
127 progress_marker
.get_update_triggers();
129 // We perform some basic tests of GU trigger and source fields here. The
130 // more complicated scenarios are tested by the NudgeTracker tests.
131 if (type
== BOOKMARKS
) {
132 EXPECT_TRUE(progress_marker
.has_notification_hint());
133 EXPECT_EQ("", progress_marker
.notification_hint());
134 EXPECT_EQ(1, gu_trigger
.local_modification_nudges());
135 EXPECT_EQ(0, gu_trigger
.datatype_refresh_nudges());
137 EXPECT_FALSE(progress_marker
.has_notification_hint());
138 EXPECT_EQ(0, gu_trigger
.local_modification_nudges());
139 EXPECT_EQ(0, gu_trigger
.datatype_refresh_nudges());
144 // Basic test to ensure invalidation payloads are expressed in the request.
145 TEST_F(GetUpdatesProcessorTest
, NotifyMany
) {
146 sessions::NudgeTracker nudge_tracker
;
147 nudge_tracker
.RecordRemoteInvalidation(
148 AUTOFILL
, BuildInvalidation(1, "autofill_payload"));
149 nudge_tracker
.RecordRemoteInvalidation(
150 BOOKMARKS
, BuildInvalidation(1, "bookmark_payload"));
151 nudge_tracker
.RecordRemoteInvalidation(
152 PREFERENCES
, BuildInvalidation(1, "preferences_payload"));
153 ModelTypeSet notified_types
;
154 notified_types
.Put(AUTOFILL
);
155 notified_types
.Put(BOOKMARKS
);
156 notified_types
.Put(PREFERENCES
);
158 sync_pb::ClientToServerMessage message
;
159 NormalGetUpdatesDelegate
normal_delegate(nudge_tracker
);
160 scoped_ptr
<GetUpdatesProcessor
> processor(
161 BuildGetUpdatesProcessor(normal_delegate
));
162 processor
->PrepareGetUpdates(enabled_types(), &message
);
164 const sync_pb::GetUpdatesMessage
& gu_msg
= message
.get_updates();
165 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::NOTIFICATION
,
166 gu_msg
.caller_info().source());
167 EXPECT_EQ(sync_pb::SyncEnums::GU_TRIGGER
, gu_msg
.get_updates_origin());
168 for (int i
= 0; i
< gu_msg
.from_progress_marker_size(); ++i
) {
169 syncer::ModelType type
= GetModelTypeFromSpecificsFieldNumber(
170 gu_msg
.from_progress_marker(i
).data_type_id());
172 const sync_pb::DataTypeProgressMarker
& progress_marker
=
173 gu_msg
.from_progress_marker(i
);
174 const sync_pb::GetUpdateTriggers
& gu_trigger
=
175 progress_marker
.get_update_triggers();
177 // We perform some basic tests of GU trigger and source fields here. The
178 // more complicated scenarios are tested by the NudgeTracker tests.
179 if (notified_types
.Has(type
)) {
180 EXPECT_TRUE(progress_marker
.has_notification_hint());
181 EXPECT_FALSE(progress_marker
.notification_hint().empty());
182 EXPECT_EQ(1, gu_trigger
.notification_hint_size());
184 EXPECT_FALSE(progress_marker
.has_notification_hint());
185 EXPECT_EQ(0, gu_trigger
.notification_hint_size());
190 TEST_F(GetUpdatesProcessorTest
, ConfigureTest
) {
191 sync_pb::ClientToServerMessage message
;
192 ConfigureGetUpdatesDelegate
configure_delegate(
193 sync_pb::GetUpdatesCallerInfo::RECONFIGURATION
);
194 scoped_ptr
<GetUpdatesProcessor
> processor(
195 BuildGetUpdatesProcessor(configure_delegate
));
196 processor
->PrepareGetUpdates(enabled_types(), &message
);
198 const sync_pb::GetUpdatesMessage
& gu_msg
= message
.get_updates();
199 EXPECT_EQ(sync_pb::SyncEnums::RECONFIGURATION
, gu_msg
.get_updates_origin());
200 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RECONFIGURATION
,
201 gu_msg
.caller_info().source());
203 ModelTypeSet progress_types
;
204 for (int i
= 0; i
< gu_msg
.from_progress_marker_size(); ++i
) {
205 syncer::ModelType type
= GetModelTypeFromSpecificsFieldNumber(
206 gu_msg
.from_progress_marker(i
).data_type_id());
207 progress_types
.Put(type
);
209 EXPECT_TRUE(enabled_types().Equals(progress_types
));
212 TEST_F(GetUpdatesProcessorTest
, PollTest
) {
213 sync_pb::ClientToServerMessage message
;
214 PollGetUpdatesDelegate poll_delegate
;
215 scoped_ptr
<GetUpdatesProcessor
> processor(
216 BuildGetUpdatesProcessor(poll_delegate
));
217 processor
->PrepareGetUpdates(enabled_types(), &message
);
219 const sync_pb::GetUpdatesMessage
& gu_msg
= message
.get_updates();
220 EXPECT_EQ(sync_pb::SyncEnums::PERIODIC
, gu_msg
.get_updates_origin());
221 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::PERIODIC
,
222 gu_msg
.caller_info().source());
224 ModelTypeSet progress_types
;
225 for (int i
= 0; i
< gu_msg
.from_progress_marker_size(); ++i
) {
226 syncer::ModelType type
= GetModelTypeFromSpecificsFieldNumber(
227 gu_msg
.from_progress_marker(i
).data_type_id());
228 progress_types
.Put(type
);
230 EXPECT_TRUE(enabled_types().Equals(progress_types
));
233 TEST_F(GetUpdatesProcessorTest
, RetryTest
) {
234 sessions::NudgeTracker nudge_tracker
;
237 base::TimeTicks t1
= kTestStartTime
;
238 nudge_tracker
.SetNextRetryTime(t1
);
240 // Get the nudge tracker to think the retry is due.
241 nudge_tracker
.SetSyncCycleStartTime(t1
+ base::TimeDelta::FromSeconds(1));
243 sync_pb::ClientToServerMessage message
;
244 NormalGetUpdatesDelegate
normal_delegate(nudge_tracker
);
245 scoped_ptr
<GetUpdatesProcessor
> processor(
246 BuildGetUpdatesProcessor(normal_delegate
));
247 processor
->PrepareGetUpdates(enabled_types(), &message
);
249 const sync_pb::GetUpdatesMessage
& gu_msg
= message
.get_updates();
250 EXPECT_EQ(sync_pb::SyncEnums::RETRY
, gu_msg
.get_updates_origin());
251 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RETRY
,
252 gu_msg
.caller_info().source());
253 EXPECT_TRUE(gu_msg
.is_retry());
255 ModelTypeSet progress_types
;
256 for (int i
= 0; i
< gu_msg
.from_progress_marker_size(); ++i
) {
257 syncer::ModelType type
= GetModelTypeFromSpecificsFieldNumber(
258 gu_msg
.from_progress_marker(i
).data_type_id());
259 progress_types
.Put(type
);
261 EXPECT_TRUE(enabled_types().Equals(progress_types
));
264 TEST_F(GetUpdatesProcessorTest
, NudgeWithRetryTest
) {
265 sessions::NudgeTracker nudge_tracker
;
268 base::TimeTicks t1
= kTestStartTime
;
269 nudge_tracker
.SetNextRetryTime(t1
);
271 // Get the nudge tracker to think the retry is due.
272 nudge_tracker
.SetSyncCycleStartTime(t1
+ base::TimeDelta::FromSeconds(1));
274 // Record a local change, too.
275 nudge_tracker
.RecordLocalChange(ModelTypeSet(BOOKMARKS
));
277 sync_pb::ClientToServerMessage message
;
278 NormalGetUpdatesDelegate
normal_delegate(nudge_tracker
);
279 scoped_ptr
<GetUpdatesProcessor
> processor(
280 BuildGetUpdatesProcessor(normal_delegate
));
281 processor
->PrepareGetUpdates(enabled_types(), &message
);
283 const sync_pb::GetUpdatesMessage
& gu_msg
= message
.get_updates();
284 EXPECT_NE(sync_pb::SyncEnums::RETRY
, gu_msg
.get_updates_origin());
285 EXPECT_NE(sync_pb::GetUpdatesCallerInfo::RETRY
,
286 gu_msg
.caller_info().source());
288 EXPECT_TRUE(gu_msg
.is_retry());
291 // Verify that a bogus response message is detected.
292 TEST_F(GetUpdatesProcessorTest
, InvalidResponse
) {
293 sync_pb::GetUpdatesResponse gu_response
;
294 InitFakeUpdateResponse(&gu_response
);
296 // This field is essential for making the client stop looping. If it's unset
297 // then something is very wrong. The client should detect this.
298 gu_response
.clear_changes_remaining();
300 sessions::NudgeTracker nudge_tracker
;
301 NormalGetUpdatesDelegate
normal_delegate(nudge_tracker
);
302 sessions::StatusController status
;
303 scoped_ptr
<GetUpdatesProcessor
> processor(
304 BuildGetUpdatesProcessor(normal_delegate
));
305 SyncerError error
= processor
->ProcessResponse(gu_response
,
308 EXPECT_EQ(error
, SERVER_RESPONSE_VALIDATION_FAILED
);
311 // Verify that we correctly detect when there's more work to be done.
312 TEST_F(GetUpdatesProcessorTest
, MoreToDownloadResponse
) {
313 sync_pb::GetUpdatesResponse gu_response
;
314 InitFakeUpdateResponse(&gu_response
);
315 gu_response
.set_changes_remaining(1);
317 sessions::NudgeTracker nudge_tracker
;
318 NormalGetUpdatesDelegate
normal_delegate(nudge_tracker
);
319 sessions::StatusController status
;
320 scoped_ptr
<GetUpdatesProcessor
> processor(
321 BuildGetUpdatesProcessor(normal_delegate
));
322 SyncerError error
= processor
->ProcessResponse(gu_response
,
325 EXPECT_EQ(error
, SERVER_MORE_TO_DOWNLOAD
);
328 // A simple scenario: No updates returned and nothing more to download.
329 TEST_F(GetUpdatesProcessorTest
, NormalResponseTest
) {
330 sync_pb::GetUpdatesResponse gu_response
;
331 InitFakeUpdateResponse(&gu_response
);
332 gu_response
.set_changes_remaining(0);
334 sessions::NudgeTracker nudge_tracker
;
335 NormalGetUpdatesDelegate
normal_delegate(nudge_tracker
);
336 sessions::StatusController status
;
337 scoped_ptr
<GetUpdatesProcessor
> processor(
338 BuildGetUpdatesProcessor(normal_delegate
));
339 SyncerError error
= processor
->ProcessResponse(gu_response
,
342 EXPECT_EQ(error
, SYNCER_OK
);
345 // Variant of GetUpdatesProcessor test designed to test update application.
347 // Maintains two enabled types, but requests that updates be applied for only
349 class GetUpdatesProcessorApplyUpdatesTest
: public GetUpdatesProcessorTest
{
351 GetUpdatesProcessorApplyUpdatesTest() {}
352 virtual ~GetUpdatesProcessorApplyUpdatesTest() {}
354 virtual void SetUp() OVERRIDE
{
355 bookmarks_handler_
= AddUpdateHandler(BOOKMARKS
);
356 autofill_handler_
= AddUpdateHandler(AUTOFILL
);
359 ModelTypeSet
GetGuTypes() {
360 return ModelTypeSet(AUTOFILL
);
363 MockUpdateHandler
* GetNonAppliedHandler() {
364 return bookmarks_handler_
;
367 MockUpdateHandler
* GetAppliedHandler() {
368 return autofill_handler_
;
372 MockUpdateHandler
* bookmarks_handler_
;
373 MockUpdateHandler
* autofill_handler_
;
376 // Verify that a normal cycle applies updates non-passively to the specified
378 TEST_F(GetUpdatesProcessorApplyUpdatesTest
, Normal
) {
379 sessions::NudgeTracker nudge_tracker
;
380 NormalGetUpdatesDelegate
normal_delegate(nudge_tracker
);
381 scoped_ptr
<GetUpdatesProcessor
> processor(
382 BuildGetUpdatesProcessor(normal_delegate
));
384 EXPECT_EQ(0, GetNonAppliedHandler()->GetApplyUpdatesCount());
385 EXPECT_EQ(0, GetAppliedHandler()->GetApplyUpdatesCount());
387 sessions::StatusController status
;
388 processor
->ApplyUpdates(GetGuTypes(), &status
);
390 EXPECT_EQ(0, GetNonAppliedHandler()->GetApplyUpdatesCount());
391 EXPECT_EQ(1, GetAppliedHandler()->GetApplyUpdatesCount());
393 EXPECT_EQ(0, GetNonAppliedHandler()->GetPassiveApplyUpdatesCount());
394 EXPECT_EQ(0, GetAppliedHandler()->GetPassiveApplyUpdatesCount());
397 // Verify that a configure cycle applies updates passively to the specified
399 TEST_F(GetUpdatesProcessorApplyUpdatesTest
, Configure
) {
400 ConfigureGetUpdatesDelegate
configure_delegate(
401 sync_pb::GetUpdatesCallerInfo::RECONFIGURATION
);
402 scoped_ptr
<GetUpdatesProcessor
> processor(
403 BuildGetUpdatesProcessor(configure_delegate
));
405 EXPECT_EQ(0, GetNonAppliedHandler()->GetPassiveApplyUpdatesCount());
406 EXPECT_EQ(0, GetAppliedHandler()->GetPassiveApplyUpdatesCount());
408 sessions::StatusController status
;
409 processor
->ApplyUpdates(GetGuTypes(), &status
);
411 EXPECT_EQ(0, GetNonAppliedHandler()->GetPassiveApplyUpdatesCount());
412 EXPECT_EQ(1, GetAppliedHandler()->GetPassiveApplyUpdatesCount());
414 EXPECT_EQ(0, GetNonAppliedHandler()->GetApplyUpdatesCount());
415 EXPECT_EQ(0, GetAppliedHandler()->GetApplyUpdatesCount());
418 // Verify that a poll cycle applies updates non-passively to the specified
420 TEST_F(GetUpdatesProcessorApplyUpdatesTest
, Poll
) {
421 PollGetUpdatesDelegate poll_delegate
;
422 scoped_ptr
<GetUpdatesProcessor
> processor(
423 BuildGetUpdatesProcessor(poll_delegate
));
425 EXPECT_EQ(0, GetNonAppliedHandler()->GetApplyUpdatesCount());
426 EXPECT_EQ(0, GetAppliedHandler()->GetApplyUpdatesCount());
428 sessions::StatusController status
;
429 processor
->ApplyUpdates(GetGuTypes(), &status
);
431 EXPECT_EQ(0, GetNonAppliedHandler()->GetApplyUpdatesCount());
432 EXPECT_EQ(1, GetAppliedHandler()->GetApplyUpdatesCount());
434 EXPECT_EQ(0, GetNonAppliedHandler()->GetPassiveApplyUpdatesCount());
435 EXPECT_EQ(0, GetAppliedHandler()->GetPassiveApplyUpdatesCount());
438 class DownloadUpdatesDebugInfoTest
: public ::testing::Test
{
440 DownloadUpdatesDebugInfoTest() {}
441 virtual ~DownloadUpdatesDebugInfoTest() {}
443 sessions::StatusController
* status() {
447 sessions::DebugInfoGetter
* debug_info_getter() {
448 return &debug_info_getter_
;
451 void AddDebugEvent() {
452 debug_info_getter_
.AddDebugEvent();
456 sessions::StatusController status_
;
457 MockDebugInfoGetter debug_info_getter_
;
460 // Verify CopyClientDebugInfo when there are no events to upload.
461 TEST_F(DownloadUpdatesDebugInfoTest
, VerifyCopyClientDebugInfo_Empty
) {
462 sync_pb::DebugInfo debug_info
;
463 GetUpdatesProcessor::CopyClientDebugInfo(debug_info_getter(), &debug_info
);
464 EXPECT_EQ(0, debug_info
.events_size());
467 TEST_F(DownloadUpdatesDebugInfoTest
, VerifyCopyOverwrites
) {
468 sync_pb::DebugInfo debug_info
;
470 GetUpdatesProcessor::CopyClientDebugInfo(debug_info_getter(), &debug_info
);
471 EXPECT_EQ(1, debug_info
.events_size());
472 GetUpdatesProcessor::CopyClientDebugInfo(debug_info_getter(), &debug_info
);
473 EXPECT_EQ(1, debug_info
.events_size());
476 } // namespace syncer