• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "sync/engine/download.h"
6 
7 #include "base/message_loop/message_loop.h"
8 #include "base/stl_util.h"
9 #include "sync/engine/sync_directory_update_handler.h"
10 #include "sync/internal_api/public/base/model_type_test_util.h"
11 #include "sync/protocol/sync.pb.h"
12 #include "sync/sessions/debug_info_getter.h"
13 #include "sync/sessions/nudge_tracker.h"
14 #include "sync/sessions/status_controller.h"
15 #include "sync/syncable/directory.h"
16 #include "sync/test/engine/fake_model_worker.h"
17 #include "sync/test/engine/test_directory_setter_upper.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 DownloadUpdatesTest : public ::testing::Test {
27  protected:
DownloadUpdatesTest()28   DownloadUpdatesTest()
29       : update_handler_map_deleter_(&update_handler_map_) {
30   }
31 
SetUp()32   virtual void SetUp() {
33     dir_maker_.SetUp();
34 
35     AddUpdateHandler(AUTOFILL, GROUP_DB);
36     AddUpdateHandler(BOOKMARKS, GROUP_UI);
37     AddUpdateHandler(PREFERENCES, GROUP_UI);
38   }
39 
TearDown()40   virtual void TearDown() {
41     dir_maker_.TearDown();
42   }
43 
proto_request_types()44   ModelTypeSet proto_request_types() {
45     ModelTypeSet types;
46     for (UpdateHandlerMap::iterator it = update_handler_map_.begin();
47          it != update_handler_map_.end(); ++it) {
48       types.Put(it->first);
49     }
50     return types;
51   }
52 
directory()53   syncable::Directory* directory() {
54     return dir_maker_.directory();
55   }
56 
update_handler_map()57   UpdateHandlerMap* update_handler_map() {
58     return &update_handler_map_;
59   }
60 
InitFakeUpdateResponse(sync_pb::GetUpdatesResponse * response)61   void InitFakeUpdateResponse(sync_pb::GetUpdatesResponse* response) {
62     ModelTypeSet types = proto_request_types();
63 
64     for (ModelTypeSet::Iterator it = types.First(); it.Good(); it.Inc()) {
65       sync_pb::DataTypeProgressMarker* marker =
66           response->add_new_progress_marker();
67       marker->set_data_type_id(GetSpecificsFieldNumberFromModelType(it.Get()));
68       marker->set_token("foobarbaz");
69     }
70 
71     response->set_changes_remaining(0);
72   }
73 
74  private:
AddUpdateHandler(ModelType type,ModelSafeGroup group)75   void AddUpdateHandler(ModelType type, ModelSafeGroup group) {
76     DCHECK(directory());
77     scoped_refptr<ModelSafeWorker> worker = new FakeModelWorker(group);
78     SyncDirectoryUpdateHandler* handler =
79         new SyncDirectoryUpdateHandler(directory(), type, worker);
80     update_handler_map_.insert(std::make_pair(type, handler));
81   }
82 
83   base::MessageLoop loop_;  // Needed for directory init.
84   TestDirectorySetterUpper dir_maker_;
85 
86   UpdateHandlerMap update_handler_map_;
87   STLValueDeleter<UpdateHandlerMap> update_handler_map_deleter_;
88 
89   DISALLOW_COPY_AND_ASSIGN(DownloadUpdatesTest);
90 };
91 
92 // Basic test to make sure nudges are expressed properly in the request.
TEST_F(DownloadUpdatesTest,BookmarkNudge)93 TEST_F(DownloadUpdatesTest, BookmarkNudge) {
94   sessions::NudgeTracker nudge_tracker;
95   nudge_tracker.RecordLocalChange(ModelTypeSet(BOOKMARKS));
96 
97   sync_pb::ClientToServerMessage msg;
98   download::BuildNormalDownloadUpdatesImpl(proto_request_types(),
99                                            update_handler_map(),
100                                            nudge_tracker,
101                                            msg.mutable_get_updates());
102 
103   const sync_pb::GetUpdatesMessage& gu_msg = msg.get_updates();
104   EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::LOCAL,
105             gu_msg.caller_info().source());
106   EXPECT_EQ(sync_pb::SyncEnums::GU_TRIGGER, gu_msg.get_updates_origin());
107   for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) {
108     syncer::ModelType type = GetModelTypeFromSpecificsFieldNumber(
109         gu_msg.from_progress_marker(i).data_type_id());
110 
111     const sync_pb::DataTypeProgressMarker& progress_marker =
112         gu_msg.from_progress_marker(i);
113     const sync_pb::GetUpdateTriggers& gu_trigger =
114         progress_marker.get_update_triggers();
115 
116     // We perform some basic tests of GU trigger and source fields here.  The
117     // more complicated scenarios are tested by the NudgeTracker tests.
118     if (type == BOOKMARKS) {
119       EXPECT_TRUE(progress_marker.has_notification_hint());
120       EXPECT_EQ("", progress_marker.notification_hint());
121       EXPECT_EQ(1, gu_trigger.local_modification_nudges());
122       EXPECT_EQ(0, gu_trigger.datatype_refresh_nudges());
123     } else {
124       EXPECT_FALSE(progress_marker.has_notification_hint());
125       EXPECT_EQ(0, gu_trigger.local_modification_nudges());
126       EXPECT_EQ(0, gu_trigger.datatype_refresh_nudges());
127     }
128   }
129 }
130 
131 // Basic test to ensure invalidation payloads are expressed in the request.
TEST_F(DownloadUpdatesTest,NotifyMany)132 TEST_F(DownloadUpdatesTest, NotifyMany) {
133   sessions::NudgeTracker nudge_tracker;
134   nudge_tracker.RecordRemoteInvalidation(
135       BuildInvalidationMap(AUTOFILL, 1, "autofill_payload"));
136   nudge_tracker.RecordRemoteInvalidation(
137       BuildInvalidationMap(BOOKMARKS, 1, "bookmark_payload"));
138   nudge_tracker.RecordRemoteInvalidation(
139       BuildInvalidationMap(PREFERENCES, 1, "preferences_payload"));
140   ModelTypeSet notified_types;
141   notified_types.Put(AUTOFILL);
142   notified_types.Put(BOOKMARKS);
143   notified_types.Put(PREFERENCES);
144 
145   sync_pb::ClientToServerMessage msg;
146   download::BuildNormalDownloadUpdatesImpl(proto_request_types(),
147                                            update_handler_map(),
148                                            nudge_tracker,
149                                            msg.mutable_get_updates());
150 
151   const sync_pb::GetUpdatesMessage& gu_msg = msg.get_updates();
152   EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::NOTIFICATION,
153             gu_msg.caller_info().source());
154   EXPECT_EQ(sync_pb::SyncEnums::GU_TRIGGER, gu_msg.get_updates_origin());
155   for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) {
156     syncer::ModelType type = GetModelTypeFromSpecificsFieldNumber(
157         gu_msg.from_progress_marker(i).data_type_id());
158 
159     const sync_pb::DataTypeProgressMarker& progress_marker =
160         gu_msg.from_progress_marker(i);
161     const sync_pb::GetUpdateTriggers& gu_trigger =
162         progress_marker.get_update_triggers();
163 
164     // We perform some basic tests of GU trigger and source fields here.  The
165     // more complicated scenarios are tested by the NudgeTracker tests.
166     if (notified_types.Has(type)) {
167       EXPECT_TRUE(progress_marker.has_notification_hint());
168       EXPECT_FALSE(progress_marker.notification_hint().empty());
169       EXPECT_EQ(1, gu_trigger.notification_hint_size());
170     } else {
171       EXPECT_FALSE(progress_marker.has_notification_hint());
172       EXPECT_EQ(0, gu_trigger.notification_hint_size());
173     }
174   }
175 }
176 
TEST_F(DownloadUpdatesTest,ConfigureTest)177 TEST_F(DownloadUpdatesTest, ConfigureTest) {
178   sync_pb::ClientToServerMessage msg;
179   download::BuildDownloadUpdatesForConfigureImpl(
180       proto_request_types(),
181       update_handler_map(),
182       sync_pb::GetUpdatesCallerInfo::RECONFIGURATION,
183       msg.mutable_get_updates());
184 
185   const sync_pb::GetUpdatesMessage& gu_msg = msg.get_updates();
186 
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(proto_request_types().Equals(progress_types));
198 }
199 
TEST_F(DownloadUpdatesTest,PollTest)200 TEST_F(DownloadUpdatesTest, PollTest) {
201   sync_pb::ClientToServerMessage msg;
202   download::BuildDownloadUpdatesForPollImpl(
203       proto_request_types(),
204       update_handler_map(),
205       msg.mutable_get_updates());
206 
207   const sync_pb::GetUpdatesMessage& gu_msg = msg.get_updates();
208 
209   EXPECT_EQ(sync_pb::SyncEnums::PERIODIC, gu_msg.get_updates_origin());
210   EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::PERIODIC,
211             gu_msg.caller_info().source());
212 
213   ModelTypeSet progress_types;
214   for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) {
215     syncer::ModelType type = GetModelTypeFromSpecificsFieldNumber(
216         gu_msg.from_progress_marker(i).data_type_id());
217     progress_types.Put(type);
218   }
219   EXPECT_TRUE(proto_request_types().Equals(progress_types));
220 }
221 
222 // Verify that a bogus response message is detected.
TEST_F(DownloadUpdatesTest,InvalidResponse)223 TEST_F(DownloadUpdatesTest, InvalidResponse) {
224   sync_pb::GetUpdatesResponse gu_response;
225   InitFakeUpdateResponse(&gu_response);
226 
227   // This field is essential for making the client stop looping.  If it's unset
228   // then something is very wrong.  The client should detect this.
229   gu_response.clear_changes_remaining();
230 
231   sessions::StatusController status;
232   SyncerError error = download::ProcessResponse(gu_response,
233                                                 proto_request_types(),
234                                                 update_handler_map(),
235                                                 &status);
236   EXPECT_EQ(error, SERVER_RESPONSE_VALIDATION_FAILED);
237 }
238 
239 // Verify that we correctly detect when there's more work to be done.
TEST_F(DownloadUpdatesTest,MoreToDownloadResponse)240 TEST_F(DownloadUpdatesTest, MoreToDownloadResponse) {
241   sync_pb::GetUpdatesResponse gu_response;
242   InitFakeUpdateResponse(&gu_response);
243   gu_response.set_changes_remaining(1);
244 
245   sessions::StatusController status;
246   SyncerError error = download::ProcessResponse(gu_response,
247                                                 proto_request_types(),
248                                                 update_handler_map(),
249                                                 &status);
250   EXPECT_EQ(error, SERVER_MORE_TO_DOWNLOAD);
251 }
252 
253 // A simple scenario: No updates returned and nothing more to download.
TEST_F(DownloadUpdatesTest,NormalResponseTest)254 TEST_F(DownloadUpdatesTest, NormalResponseTest) {
255   sync_pb::GetUpdatesResponse gu_response;
256   InitFakeUpdateResponse(&gu_response);
257   gu_response.set_changes_remaining(0);
258 
259   sessions::StatusController status;
260   SyncerError error = download::ProcessResponse(gu_response,
261                                                 proto_request_types(),
262                                                 update_handler_map(),
263                                                 &status);
264   EXPECT_EQ(error, SYNCER_OK);
265 }
266 
267 class DownloadUpdatesDebugInfoTest : public ::testing::Test {
268  public:
DownloadUpdatesDebugInfoTest()269   DownloadUpdatesDebugInfoTest() {}
~DownloadUpdatesDebugInfoTest()270   virtual ~DownloadUpdatesDebugInfoTest() {}
271 
status()272   sessions::StatusController* status() {
273     return &status_;
274   }
275 
debug_info_getter()276   sessions::DebugInfoGetter* debug_info_getter() {
277     return &debug_info_getter_;
278   }
279 
AddDebugEvent()280   void AddDebugEvent() {
281     debug_info_getter_.AddDebugEvent();
282   }
283 
284  private:
285   sessions::StatusController status_;
286   MockDebugInfoGetter debug_info_getter_;
287 };
288 
289 
290 // Verify CopyClientDebugInfo when there are no events to upload.
TEST_F(DownloadUpdatesDebugInfoTest,VerifyCopyClientDebugInfo_Empty)291 TEST_F(DownloadUpdatesDebugInfoTest, VerifyCopyClientDebugInfo_Empty) {
292   sync_pb::DebugInfo debug_info;
293   download::CopyClientDebugInfo(debug_info_getter(), &debug_info);
294   EXPECT_EQ(0, debug_info.events_size());
295 }
296 
TEST_F(DownloadUpdatesDebugInfoTest,VerifyCopyOverwrites)297 TEST_F(DownloadUpdatesDebugInfoTest, VerifyCopyOverwrites) {
298   sync_pb::DebugInfo debug_info;
299   AddDebugEvent();
300   download::CopyClientDebugInfo(debug_info_getter(), &debug_info);
301   EXPECT_EQ(1, debug_info.events_size());
302   download::CopyClientDebugInfo(debug_info_getter(), &debug_info);
303   EXPECT_EQ(1, debug_info.events_size());
304 }
305 
306 }  // namespace syncer
307