1 // Copyright 2013 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/download.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/sync_directory_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/syncable/directory.h"
17 #include "sync/test/engine/fake_model_worker.h"
18 #include "sync/test/engine/test_directory_setter_upper.h"
19 #include "sync/test/sessions/mock_debug_info_getter.h"
20 #include "testing/gtest/include/gtest/gtest.h"
24 using sessions::MockDebugInfoGetter;
26 // A test fixture for tests exercising download updates functions.
27 class DownloadUpdatesTest : public ::testing::Test {
29 DownloadUpdatesTest() :
30 kTestStartTime(base::TimeTicks::Now()),
31 update_handler_deleter_(&update_handler_map_) {}
33 virtual void SetUp() {
36 AddUpdateHandler(AUTOFILL, GROUP_DB);
37 AddUpdateHandler(BOOKMARKS, GROUP_UI);
38 AddUpdateHandler(PREFERENCES, GROUP_UI);
41 virtual void TearDown() {
42 dir_maker_.TearDown();
45 ModelTypeSet request_types() {
46 return request_types_;
49 syncable::Directory* directory() {
50 return dir_maker_.directory();
53 scoped_ptr<GetUpdatesProcessor> BuildGetUpdatesProcessor(
54 const GetUpdatesDelegate& delegate) {
55 return scoped_ptr<GetUpdatesProcessor>(
56 new GetUpdatesProcessor(&update_handler_map_, delegate));
59 void InitFakeUpdateResponse(sync_pb::GetUpdatesResponse* response) {
60 ModelTypeSet types = request_types();
62 for (ModelTypeSet::Iterator it = types.First(); it.Good(); it.Inc()) {
63 sync_pb::DataTypeProgressMarker* marker =
64 response->add_new_progress_marker();
65 marker->set_data_type_id(GetSpecificsFieldNumberFromModelType(it.Get()));
66 marker->set_token("foobarbaz");
69 response->set_changes_remaining(0);
72 const base::TimeTicks kTestStartTime;
75 void AddUpdateHandler(ModelType type, ModelSafeGroup group) {
78 request_types_.Put(type);
80 scoped_refptr<ModelSafeWorker> worker = new FakeModelWorker(group);
81 SyncDirectoryUpdateHandler* handler =
82 new SyncDirectoryUpdateHandler(directory(), type, worker);
83 update_handler_map_.insert(std::make_pair(type, handler));
86 base::MessageLoop loop_; // Needed for directory init.
87 TestDirectorySetterUpper dir_maker_;
89 ModelTypeSet request_types_;
90 UpdateHandlerMap update_handler_map_;
91 STLValueDeleter<UpdateHandlerMap> update_handler_deleter_;
92 scoped_ptr<GetUpdatesProcessor> get_updates_processor_;
94 DISALLOW_COPY_AND_ASSIGN(DownloadUpdatesTest);
97 // Basic test to make sure nudges are expressed properly in the request.
98 TEST_F(DownloadUpdatesTest, BookmarkNudge) {
99 sessions::NudgeTracker nudge_tracker;
100 nudge_tracker.RecordLocalChange(ModelTypeSet(BOOKMARKS));
102 sync_pb::GetUpdatesMessage gu_msg;
103 NormalGetUpdatesDelegate normal_delegate(nudge_tracker);
104 scoped_ptr<GetUpdatesProcessor> processor(
105 BuildGetUpdatesProcessor(normal_delegate));
106 processor->PrepareGetUpdates(request_types(), &gu_msg);
108 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::LOCAL,
109 gu_msg.caller_info().source());
110 EXPECT_EQ(sync_pb::SyncEnums::GU_TRIGGER, gu_msg.get_updates_origin());
111 for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) {
112 syncer::ModelType type = GetModelTypeFromSpecificsFieldNumber(
113 gu_msg.from_progress_marker(i).data_type_id());
115 const sync_pb::DataTypeProgressMarker& progress_marker =
116 gu_msg.from_progress_marker(i);
117 const sync_pb::GetUpdateTriggers& gu_trigger =
118 progress_marker.get_update_triggers();
120 // We perform some basic tests of GU trigger and source fields here. The
121 // more complicated scenarios are tested by the NudgeTracker tests.
122 if (type == BOOKMARKS) {
123 EXPECT_TRUE(progress_marker.has_notification_hint());
124 EXPECT_EQ("", progress_marker.notification_hint());
125 EXPECT_EQ(1, gu_trigger.local_modification_nudges());
126 EXPECT_EQ(0, gu_trigger.datatype_refresh_nudges());
128 EXPECT_FALSE(progress_marker.has_notification_hint());
129 EXPECT_EQ(0, gu_trigger.local_modification_nudges());
130 EXPECT_EQ(0, gu_trigger.datatype_refresh_nudges());
135 // Basic test to ensure invalidation payloads are expressed in the request.
136 TEST_F(DownloadUpdatesTest, NotifyMany) {
137 sessions::NudgeTracker nudge_tracker;
138 nudge_tracker.RecordRemoteInvalidation(
139 BuildInvalidationMap(AUTOFILL, 1, "autofill_payload"));
140 nudge_tracker.RecordRemoteInvalidation(
141 BuildInvalidationMap(BOOKMARKS, 1, "bookmark_payload"));
142 nudge_tracker.RecordRemoteInvalidation(
143 BuildInvalidationMap(PREFERENCES, 1, "preferences_payload"));
144 ModelTypeSet notified_types;
145 notified_types.Put(AUTOFILL);
146 notified_types.Put(BOOKMARKS);
147 notified_types.Put(PREFERENCES);
149 sync_pb::GetUpdatesMessage gu_msg;
150 NormalGetUpdatesDelegate normal_delegate(nudge_tracker);
151 scoped_ptr<GetUpdatesProcessor> processor(
152 BuildGetUpdatesProcessor(normal_delegate));
153 processor->PrepareGetUpdates(request_types(), &gu_msg);
155 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::NOTIFICATION,
156 gu_msg.caller_info().source());
157 EXPECT_EQ(sync_pb::SyncEnums::GU_TRIGGER, gu_msg.get_updates_origin());
158 for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) {
159 syncer::ModelType type = GetModelTypeFromSpecificsFieldNumber(
160 gu_msg.from_progress_marker(i).data_type_id());
162 const sync_pb::DataTypeProgressMarker& progress_marker =
163 gu_msg.from_progress_marker(i);
164 const sync_pb::GetUpdateTriggers& gu_trigger =
165 progress_marker.get_update_triggers();
167 // We perform some basic tests of GU trigger and source fields here. The
168 // more complicated scenarios are tested by the NudgeTracker tests.
169 if (notified_types.Has(type)) {
170 EXPECT_TRUE(progress_marker.has_notification_hint());
171 EXPECT_FALSE(progress_marker.notification_hint().empty());
172 EXPECT_EQ(1, gu_trigger.notification_hint_size());
174 EXPECT_FALSE(progress_marker.has_notification_hint());
175 EXPECT_EQ(0, gu_trigger.notification_hint_size());
180 TEST_F(DownloadUpdatesTest, ConfigureTest) {
181 sync_pb::GetUpdatesMessage gu_msg;
182 ConfigureGetUpdatesDelegate configure_delegate(
183 sync_pb::GetUpdatesCallerInfo::RECONFIGURATION);
184 scoped_ptr<GetUpdatesProcessor> processor(
185 BuildGetUpdatesProcessor(configure_delegate));
186 processor->PrepareGetUpdates(request_types(), &gu_msg);
188 EXPECT_EQ(sync_pb::SyncEnums::RECONFIGURATION, gu_msg.get_updates_origin());
189 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RECONFIGURATION,
190 gu_msg.caller_info().source());
192 ModelTypeSet progress_types;
193 for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) {
194 syncer::ModelType type = GetModelTypeFromSpecificsFieldNumber(
195 gu_msg.from_progress_marker(i).data_type_id());
196 progress_types.Put(type);
198 EXPECT_TRUE(request_types().Equals(progress_types));
201 TEST_F(DownloadUpdatesTest, PollTest) {
202 sync_pb::GetUpdatesMessage gu_msg;
203 PollGetUpdatesDelegate poll_delegate;
204 scoped_ptr<GetUpdatesProcessor> processor(
205 BuildGetUpdatesProcessor(poll_delegate));
206 processor->PrepareGetUpdates(request_types(), &gu_msg);
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());
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);
218 EXPECT_TRUE(request_types().Equals(progress_types));
221 TEST_F(DownloadUpdatesTest, RetryTest) {
222 sessions::NudgeTracker nudge_tracker;
225 base::TimeTicks t1 = kTestStartTime;
226 nudge_tracker.SetNextRetryTime(t1);
228 // Get the nudge tracker to think the retry is due.
229 nudge_tracker.SetSyncCycleStartTime(t1 + base::TimeDelta::FromSeconds(1));
231 sync_pb::GetUpdatesMessage gu_msg;
232 RetryGetUpdatesDelegate retry_delegate;
233 scoped_ptr<GetUpdatesProcessor> processor(
234 BuildGetUpdatesProcessor(retry_delegate));
235 processor->PrepareGetUpdates(request_types(), &gu_msg);
237 EXPECT_EQ(sync_pb::SyncEnums::RETRY, gu_msg.get_updates_origin());
238 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RETRY,
239 gu_msg.caller_info().source());
240 EXPECT_TRUE(gu_msg.is_retry());
242 ModelTypeSet progress_types;
243 for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) {
244 syncer::ModelType type = GetModelTypeFromSpecificsFieldNumber(
245 gu_msg.from_progress_marker(i).data_type_id());
246 progress_types.Put(type);
248 EXPECT_TRUE(request_types().Equals(progress_types));
251 TEST_F(DownloadUpdatesTest, NudgeWithRetryTest) {
252 sessions::NudgeTracker nudge_tracker;
255 base::TimeTicks t1 = kTestStartTime;
256 nudge_tracker.SetNextRetryTime(t1);
258 // Get the nudge tracker to think the retry is due.
259 nudge_tracker.SetSyncCycleStartTime(t1 + base::TimeDelta::FromSeconds(1));
261 // Record a local change, too.
262 nudge_tracker.RecordLocalChange(ModelTypeSet(BOOKMARKS));
264 sync_pb::GetUpdatesMessage gu_msg;
265 NormalGetUpdatesDelegate normal_delegate(nudge_tracker);
266 scoped_ptr<GetUpdatesProcessor> processor(
267 BuildGetUpdatesProcessor(normal_delegate));
268 processor->PrepareGetUpdates(request_types(), &gu_msg);
270 EXPECT_NE(sync_pb::SyncEnums::RETRY, gu_msg.get_updates_origin());
271 EXPECT_NE(sync_pb::GetUpdatesCallerInfo::RETRY,
272 gu_msg.caller_info().source());
274 EXPECT_TRUE(gu_msg.is_retry());
277 // Verify that a bogus response message is detected.
278 TEST_F(DownloadUpdatesTest, InvalidResponse) {
279 sync_pb::GetUpdatesResponse gu_response;
280 InitFakeUpdateResponse(&gu_response);
282 // This field is essential for making the client stop looping. If it's unset
283 // then something is very wrong. The client should detect this.
284 gu_response.clear_changes_remaining();
286 sessions::NudgeTracker nudge_tracker;
287 NormalGetUpdatesDelegate normal_delegate(nudge_tracker);
288 sessions::StatusController status;
289 scoped_ptr<GetUpdatesProcessor> processor(
290 BuildGetUpdatesProcessor(normal_delegate));
291 SyncerError error = download::ProcessResponse(gu_response,
295 EXPECT_EQ(error, SERVER_RESPONSE_VALIDATION_FAILED);
298 // Verify that we correctly detect when there's more work to be done.
299 TEST_F(DownloadUpdatesTest, MoreToDownloadResponse) {
300 sync_pb::GetUpdatesResponse gu_response;
301 InitFakeUpdateResponse(&gu_response);
302 gu_response.set_changes_remaining(1);
304 sessions::NudgeTracker nudge_tracker;
305 NormalGetUpdatesDelegate normal_delegate(nudge_tracker);
306 sessions::StatusController status;
307 scoped_ptr<GetUpdatesProcessor> processor(
308 BuildGetUpdatesProcessor(normal_delegate));
309 SyncerError error = download::ProcessResponse(gu_response,
313 EXPECT_EQ(error, SERVER_MORE_TO_DOWNLOAD);
316 // A simple scenario: No updates returned and nothing more to download.
317 TEST_F(DownloadUpdatesTest, NormalResponseTest) {
318 sync_pb::GetUpdatesResponse gu_response;
319 InitFakeUpdateResponse(&gu_response);
320 gu_response.set_changes_remaining(0);
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 = download::ProcessResponse(gu_response,
331 EXPECT_EQ(error, SYNCER_OK);
334 class DownloadUpdatesDebugInfoTest : public ::testing::Test {
336 DownloadUpdatesDebugInfoTest() {}
337 virtual ~DownloadUpdatesDebugInfoTest() {}
339 sessions::StatusController* status() {
343 sessions::DebugInfoGetter* debug_info_getter() {
344 return &debug_info_getter_;
347 void AddDebugEvent() {
348 debug_info_getter_.AddDebugEvent();
352 sessions::StatusController status_;
353 MockDebugInfoGetter debug_info_getter_;
357 // Verify CopyClientDebugInfo when there are no events to upload.
358 TEST_F(DownloadUpdatesDebugInfoTest, VerifyCopyClientDebugInfo_Empty) {
359 sync_pb::DebugInfo debug_info;
360 download::CopyClientDebugInfo(debug_info_getter(), &debug_info);
361 EXPECT_EQ(0, debug_info.events_size());
364 TEST_F(DownloadUpdatesDebugInfoTest, VerifyCopyOverwrites) {
365 sync_pb::DebugInfo debug_info;
367 download::CopyClientDebugInfo(debug_info_getter(), &debug_info);
368 EXPECT_EQ(1, debug_info.events_size());
369 download::CopyClientDebugInfo(debug_info_getter(), &debug_info);
370 EXPECT_EQ(1, debug_info.events_size());
373 } // namespace syncer