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/mock_invalidation.h" 19 #include "sync/test/sessions/mock_debug_info_getter.h" 20 #include "testing/gtest/include/gtest/gtest.h" 21 22 namespace syncer { 23 24 namespace { 25 26 scoped_ptr<InvalidationInterface> BuildInvalidation( 27 int64 version, 28 const std::string& payload) { 29 return MockInvalidation::Build(version, payload) 30 .PassAs<InvalidationInterface>(); 31 } 32 33 } // namespace 34 35 using sessions::MockDebugInfoGetter; 36 37 // A test fixture for tests exercising download updates functions. 38 class GetUpdatesProcessorTest : public ::testing::Test { 39 protected: 40 GetUpdatesProcessorTest() : 41 kTestStartTime(base::TimeTicks::Now()), 42 update_handler_deleter_(&update_handler_map_) {} 43 44 virtual void SetUp() { 45 AddUpdateHandler(AUTOFILL); 46 AddUpdateHandler(BOOKMARKS); 47 AddUpdateHandler(PREFERENCES); 48 } 49 50 ModelTypeSet enabled_types() { 51 return enabled_types_; 52 } 53 54 scoped_ptr<GetUpdatesProcessor> BuildGetUpdatesProcessor( 55 const GetUpdatesDelegate& delegate) { 56 return scoped_ptr<GetUpdatesProcessor>( 57 new GetUpdatesProcessor(&update_handler_map_, delegate)); 58 } 59 60 void InitFakeUpdateResponse(sync_pb::GetUpdatesResponse* response) { 61 ModelTypeSet types = enabled_types(); 62 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"); 72 } 73 74 response->set_changes_remaining(0); 75 } 76 77 const UpdateHandler* GetHandler(ModelType type) { 78 UpdateHandlerMap::iterator it = update_handler_map_.find(type); 79 if (it == update_handler_map_.end()) 80 return NULL; 81 return it->second; 82 } 83 84 const base::TimeTicks kTestStartTime; 85 86 protected: 87 MockUpdateHandler* AddUpdateHandler(ModelType type) { 88 enabled_types_.Put(type); 89 90 MockUpdateHandler* handler = new MockUpdateHandler(type); 91 update_handler_map_.insert(std::make_pair(type, handler)); 92 93 return handler; 94 } 95 96 private: 97 ModelTypeSet enabled_types_; 98 UpdateHandlerMap update_handler_map_; 99 STLValueDeleter<UpdateHandlerMap> update_handler_deleter_; 100 scoped_ptr<GetUpdatesProcessor> get_updates_processor_; 101 102 DISALLOW_COPY_AND_ASSIGN(GetUpdatesProcessorTest); 103 }; 104 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)); 109 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); 115 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()); 123 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(); 128 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()); 136 } else { 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()); 140 } 141 } 142 } 143 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); 157 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); 163 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()); 171 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(); 176 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()); 183 } else { 184 EXPECT_FALSE(progress_marker.has_notification_hint()); 185 EXPECT_EQ(0, gu_trigger.notification_hint_size()); 186 } 187 } 188 } 189 190 // Basic test to ensure initial sync requests are expressed in the request. 191 TEST_F(GetUpdatesProcessorTest, InitialSyncRequest) { 192 sessions::NudgeTracker nudge_tracker; 193 nudge_tracker.RecordInitialSyncRequired(AUTOFILL); 194 nudge_tracker.RecordInitialSyncRequired(PREFERENCES); 195 196 ModelTypeSet initial_sync_types = ModelTypeSet(AUTOFILL, PREFERENCES); 197 198 sync_pb::ClientToServerMessage message; 199 NormalGetUpdatesDelegate normal_delegate(nudge_tracker); 200 scoped_ptr<GetUpdatesProcessor> processor( 201 BuildGetUpdatesProcessor(normal_delegate)); 202 processor->PrepareGetUpdates(enabled_types(), &message); 203 204 const sync_pb::GetUpdatesMessage& gu_msg = message.get_updates(); 205 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH, 206 gu_msg.caller_info().source()); 207 EXPECT_EQ(sync_pb::SyncEnums::GU_TRIGGER, gu_msg.get_updates_origin()); 208 for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) { 209 syncer::ModelType type = GetModelTypeFromSpecificsFieldNumber( 210 gu_msg.from_progress_marker(i).data_type_id()); 211 212 const sync_pb::DataTypeProgressMarker& progress_marker = 213 gu_msg.from_progress_marker(i); 214 const sync_pb::GetUpdateTriggers& gu_trigger = 215 progress_marker.get_update_triggers(); 216 217 // We perform some basic tests of GU trigger and source fields here. The 218 // more complicated scenarios are tested by the NudgeTracker tests. 219 if (initial_sync_types.Has(type)) { 220 EXPECT_TRUE(gu_trigger.initial_sync_in_progress()); 221 } else { 222 EXPECT_TRUE(gu_trigger.has_initial_sync_in_progress()); 223 EXPECT_FALSE(gu_trigger.initial_sync_in_progress()); 224 } 225 } 226 } 227 228 TEST_F(GetUpdatesProcessorTest, ConfigureTest) { 229 sync_pb::ClientToServerMessage message; 230 ConfigureGetUpdatesDelegate configure_delegate( 231 sync_pb::GetUpdatesCallerInfo::RECONFIGURATION); 232 scoped_ptr<GetUpdatesProcessor> processor( 233 BuildGetUpdatesProcessor(configure_delegate)); 234 processor->PrepareGetUpdates(enabled_types(), &message); 235 236 const sync_pb::GetUpdatesMessage& gu_msg = message.get_updates(); 237 EXPECT_EQ(sync_pb::SyncEnums::RECONFIGURATION, gu_msg.get_updates_origin()); 238 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RECONFIGURATION, 239 gu_msg.caller_info().source()); 240 241 ModelTypeSet progress_types; 242 for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) { 243 syncer::ModelType type = GetModelTypeFromSpecificsFieldNumber( 244 gu_msg.from_progress_marker(i).data_type_id()); 245 progress_types.Put(type); 246 } 247 EXPECT_TRUE(enabled_types().Equals(progress_types)); 248 } 249 250 TEST_F(GetUpdatesProcessorTest, PollTest) { 251 sync_pb::ClientToServerMessage message; 252 PollGetUpdatesDelegate poll_delegate; 253 scoped_ptr<GetUpdatesProcessor> processor( 254 BuildGetUpdatesProcessor(poll_delegate)); 255 processor->PrepareGetUpdates(enabled_types(), &message); 256 257 const sync_pb::GetUpdatesMessage& gu_msg = message.get_updates(); 258 EXPECT_EQ(sync_pb::SyncEnums::PERIODIC, gu_msg.get_updates_origin()); 259 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::PERIODIC, 260 gu_msg.caller_info().source()); 261 262 ModelTypeSet progress_types; 263 for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) { 264 syncer::ModelType type = GetModelTypeFromSpecificsFieldNumber( 265 gu_msg.from_progress_marker(i).data_type_id()); 266 progress_types.Put(type); 267 } 268 EXPECT_TRUE(enabled_types().Equals(progress_types)); 269 } 270 271 TEST_F(GetUpdatesProcessorTest, RetryTest) { 272 sessions::NudgeTracker nudge_tracker; 273 274 // Schedule a retry. 275 base::TimeTicks t1 = kTestStartTime; 276 nudge_tracker.SetNextRetryTime(t1); 277 278 // Get the nudge tracker to think the retry is due. 279 nudge_tracker.SetSyncCycleStartTime(t1 + base::TimeDelta::FromSeconds(1)); 280 281 sync_pb::ClientToServerMessage message; 282 NormalGetUpdatesDelegate normal_delegate(nudge_tracker); 283 scoped_ptr<GetUpdatesProcessor> processor( 284 BuildGetUpdatesProcessor(normal_delegate)); 285 processor->PrepareGetUpdates(enabled_types(), &message); 286 287 const sync_pb::GetUpdatesMessage& gu_msg = message.get_updates(); 288 EXPECT_EQ(sync_pb::SyncEnums::RETRY, gu_msg.get_updates_origin()); 289 EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RETRY, 290 gu_msg.caller_info().source()); 291 EXPECT_TRUE(gu_msg.is_retry()); 292 293 ModelTypeSet progress_types; 294 for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) { 295 syncer::ModelType type = GetModelTypeFromSpecificsFieldNumber( 296 gu_msg.from_progress_marker(i).data_type_id()); 297 progress_types.Put(type); 298 } 299 EXPECT_TRUE(enabled_types().Equals(progress_types)); 300 } 301 302 TEST_F(GetUpdatesProcessorTest, NudgeWithRetryTest) { 303 sessions::NudgeTracker nudge_tracker; 304 305 // Schedule a retry. 306 base::TimeTicks t1 = kTestStartTime; 307 nudge_tracker.SetNextRetryTime(t1); 308 309 // Get the nudge tracker to think the retry is due. 310 nudge_tracker.SetSyncCycleStartTime(t1 + base::TimeDelta::FromSeconds(1)); 311 312 // Record a local change, too. 313 nudge_tracker.RecordLocalChange(ModelTypeSet(BOOKMARKS)); 314 315 sync_pb::ClientToServerMessage message; 316 NormalGetUpdatesDelegate normal_delegate(nudge_tracker); 317 scoped_ptr<GetUpdatesProcessor> processor( 318 BuildGetUpdatesProcessor(normal_delegate)); 319 processor->PrepareGetUpdates(enabled_types(), &message); 320 321 const sync_pb::GetUpdatesMessage& gu_msg = message.get_updates(); 322 EXPECT_NE(sync_pb::SyncEnums::RETRY, gu_msg.get_updates_origin()); 323 EXPECT_NE(sync_pb::GetUpdatesCallerInfo::RETRY, 324 gu_msg.caller_info().source()); 325 326 EXPECT_TRUE(gu_msg.is_retry()); 327 } 328 329 // Verify that a bogus response message is detected. 330 TEST_F(GetUpdatesProcessorTest, InvalidResponse) { 331 sync_pb::GetUpdatesResponse gu_response; 332 InitFakeUpdateResponse(&gu_response); 333 334 // This field is essential for making the client stop looping. If it's unset 335 // then something is very wrong. The client should detect this. 336 gu_response.clear_changes_remaining(); 337 338 sessions::NudgeTracker nudge_tracker; 339 NormalGetUpdatesDelegate normal_delegate(nudge_tracker); 340 sessions::StatusController status; 341 scoped_ptr<GetUpdatesProcessor> processor( 342 BuildGetUpdatesProcessor(normal_delegate)); 343 SyncerError error = processor->ProcessResponse(gu_response, 344 enabled_types(), 345 &status); 346 EXPECT_EQ(error, SERVER_RESPONSE_VALIDATION_FAILED); 347 } 348 349 // Verify that we correctly detect when there's more work to be done. 350 TEST_F(GetUpdatesProcessorTest, MoreToDownloadResponse) { 351 sync_pb::GetUpdatesResponse gu_response; 352 InitFakeUpdateResponse(&gu_response); 353 gu_response.set_changes_remaining(1); 354 355 sessions::NudgeTracker nudge_tracker; 356 NormalGetUpdatesDelegate normal_delegate(nudge_tracker); 357 sessions::StatusController status; 358 scoped_ptr<GetUpdatesProcessor> processor( 359 BuildGetUpdatesProcessor(normal_delegate)); 360 SyncerError error = processor->ProcessResponse(gu_response, 361 enabled_types(), 362 &status); 363 EXPECT_EQ(error, SERVER_MORE_TO_DOWNLOAD); 364 } 365 366 // A simple scenario: No updates returned and nothing more to download. 367 TEST_F(GetUpdatesProcessorTest, NormalResponseTest) { 368 sync_pb::GetUpdatesResponse gu_response; 369 InitFakeUpdateResponse(&gu_response); 370 gu_response.set_changes_remaining(0); 371 372 sessions::NudgeTracker nudge_tracker; 373 NormalGetUpdatesDelegate normal_delegate(nudge_tracker); 374 sessions::StatusController status; 375 scoped_ptr<GetUpdatesProcessor> processor( 376 BuildGetUpdatesProcessor(normal_delegate)); 377 SyncerError error = processor->ProcessResponse(gu_response, 378 enabled_types(), 379 &status); 380 EXPECT_EQ(error, SYNCER_OK); 381 } 382 383 // Variant of GetUpdatesProcessor test designed to test update application. 384 // 385 // Maintains two enabled types, but requests that updates be applied for only 386 // one of them. 387 class GetUpdatesProcessorApplyUpdatesTest : public GetUpdatesProcessorTest { 388 public: 389 GetUpdatesProcessorApplyUpdatesTest() {} 390 virtual ~GetUpdatesProcessorApplyUpdatesTest() {} 391 392 virtual void SetUp() OVERRIDE { 393 bookmarks_handler_ = AddUpdateHandler(BOOKMARKS); 394 autofill_handler_ = AddUpdateHandler(AUTOFILL); 395 } 396 397 ModelTypeSet GetGuTypes() { 398 return ModelTypeSet(AUTOFILL); 399 } 400 401 MockUpdateHandler* GetNonAppliedHandler() { 402 return bookmarks_handler_; 403 } 404 405 MockUpdateHandler* GetAppliedHandler() { 406 return autofill_handler_; 407 } 408 409 private: 410 MockUpdateHandler* bookmarks_handler_; 411 MockUpdateHandler* autofill_handler_; 412 }; 413 414 // Verify that a normal cycle applies updates non-passively to the specified 415 // types. 416 TEST_F(GetUpdatesProcessorApplyUpdatesTest, Normal) { 417 sessions::NudgeTracker nudge_tracker; 418 NormalGetUpdatesDelegate normal_delegate(nudge_tracker); 419 scoped_ptr<GetUpdatesProcessor> processor( 420 BuildGetUpdatesProcessor(normal_delegate)); 421 422 EXPECT_EQ(0, GetNonAppliedHandler()->GetApplyUpdatesCount()); 423 EXPECT_EQ(0, GetAppliedHandler()->GetApplyUpdatesCount()); 424 425 sessions::StatusController status; 426 processor->ApplyUpdates(GetGuTypes(), &status); 427 428 EXPECT_EQ(0, GetNonAppliedHandler()->GetApplyUpdatesCount()); 429 EXPECT_EQ(1, GetAppliedHandler()->GetApplyUpdatesCount()); 430 431 EXPECT_EQ(0, GetNonAppliedHandler()->GetPassiveApplyUpdatesCount()); 432 EXPECT_EQ(0, GetAppliedHandler()->GetPassiveApplyUpdatesCount()); 433 } 434 435 // Verify that a configure cycle applies updates passively to the specified 436 // types. 437 TEST_F(GetUpdatesProcessorApplyUpdatesTest, Configure) { 438 ConfigureGetUpdatesDelegate configure_delegate( 439 sync_pb::GetUpdatesCallerInfo::RECONFIGURATION); 440 scoped_ptr<GetUpdatesProcessor> processor( 441 BuildGetUpdatesProcessor(configure_delegate)); 442 443 EXPECT_EQ(0, GetNonAppliedHandler()->GetPassiveApplyUpdatesCount()); 444 EXPECT_EQ(0, GetAppliedHandler()->GetPassiveApplyUpdatesCount()); 445 446 sessions::StatusController status; 447 processor->ApplyUpdates(GetGuTypes(), &status); 448 449 EXPECT_EQ(0, GetNonAppliedHandler()->GetPassiveApplyUpdatesCount()); 450 EXPECT_EQ(1, GetAppliedHandler()->GetPassiveApplyUpdatesCount()); 451 452 EXPECT_EQ(0, GetNonAppliedHandler()->GetApplyUpdatesCount()); 453 EXPECT_EQ(0, GetAppliedHandler()->GetApplyUpdatesCount()); 454 } 455 456 // Verify that a poll cycle applies updates non-passively to the specified 457 // types. 458 TEST_F(GetUpdatesProcessorApplyUpdatesTest, Poll) { 459 PollGetUpdatesDelegate poll_delegate; 460 scoped_ptr<GetUpdatesProcessor> processor( 461 BuildGetUpdatesProcessor(poll_delegate)); 462 463 EXPECT_EQ(0, GetNonAppliedHandler()->GetApplyUpdatesCount()); 464 EXPECT_EQ(0, GetAppliedHandler()->GetApplyUpdatesCount()); 465 466 sessions::StatusController status; 467 processor->ApplyUpdates(GetGuTypes(), &status); 468 469 EXPECT_EQ(0, GetNonAppliedHandler()->GetApplyUpdatesCount()); 470 EXPECT_EQ(1, GetAppliedHandler()->GetApplyUpdatesCount()); 471 472 EXPECT_EQ(0, GetNonAppliedHandler()->GetPassiveApplyUpdatesCount()); 473 EXPECT_EQ(0, GetAppliedHandler()->GetPassiveApplyUpdatesCount()); 474 } 475 476 class DownloadUpdatesDebugInfoTest : public ::testing::Test { 477 public: 478 DownloadUpdatesDebugInfoTest() {} 479 virtual ~DownloadUpdatesDebugInfoTest() {} 480 481 sessions::StatusController* status() { 482 return &status_; 483 } 484 485 sessions::DebugInfoGetter* debug_info_getter() { 486 return &debug_info_getter_; 487 } 488 489 void AddDebugEvent() { 490 debug_info_getter_.AddDebugEvent(); 491 } 492 493 private: 494 sessions::StatusController status_; 495 MockDebugInfoGetter debug_info_getter_; 496 }; 497 498 // Verify CopyClientDebugInfo when there are no events to upload. 499 TEST_F(DownloadUpdatesDebugInfoTest, VerifyCopyClientDebugInfo_Empty) { 500 sync_pb::DebugInfo debug_info; 501 GetUpdatesProcessor::CopyClientDebugInfo(debug_info_getter(), &debug_info); 502 EXPECT_EQ(0, debug_info.events_size()); 503 } 504 505 TEST_F(DownloadUpdatesDebugInfoTest, VerifyCopyOverwrites) { 506 sync_pb::DebugInfo debug_info; 507 AddDebugEvent(); 508 GetUpdatesProcessor::CopyClientDebugInfo(debug_info_getter(), &debug_info); 509 EXPECT_EQ(1, debug_info.events_size()); 510 GetUpdatesProcessor::CopyClientDebugInfo(debug_info_getter(), &debug_info); 511 EXPECT_EQ(1, debug_info.events_size()); 512 } 513 514 } // namespace syncer 515