| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 <stddef.h> | |
| 6 #include <stdint.h> | |
| 7 | |
| 8 #include "base/bind.h" | |
| 9 #include "base/callback.h" | |
| 10 #include "base/compiler_specific.h" | |
| 11 #include "base/location.h" | |
| 12 #include "base/memory/weak_ptr.h" | |
| 13 #include "base/run_loop.h" | |
| 14 #include "base/single_thread_task_runner.h" | |
| 15 #include "base/test/test_timeouts.h" | |
| 16 #include "base/threading/thread_task_runner_handle.h" | |
| 17 #include "components/sync/base/cancelation_signal.h" | |
| 18 #include "components/sync/base/extensions_activity.h" | |
| 19 #include "components/sync/base/model_type_test_util.h" | |
| 20 #include "components/sync/engine_impl/backoff_delay_provider.h" | |
| 21 #include "components/sync/engine_impl/cycle/test_util.h" | |
| 22 #include "components/sync/engine_impl/sync_scheduler_impl.h" | |
| 23 #include "components/sync/engine_impl/syncer.h" | |
| 24 #include "components/sync/test/callback_counter.h" | |
| 25 #include "components/sync/test/engine/fake_model_worker.h" | |
| 26 #include "components/sync/test/engine/mock_connection_manager.h" | |
| 27 #include "components/sync/test/engine/mock_nudge_handler.h" | |
| 28 #include "components/sync/test/engine/test_directory_setter_upper.h" | |
| 29 #include "components/sync/test/mock_invalidation.h" | |
| 30 #include "testing/gmock/include/gmock/gmock.h" | |
| 31 #include "testing/gtest/include/gtest/gtest.h" | |
| 32 | |
| 33 using base::TimeDelta; | |
| 34 using base::TimeTicks; | |
| 35 using testing::_; | |
| 36 using testing::AtLeast; | |
| 37 using testing::DoAll; | |
| 38 using testing::Invoke; | |
| 39 using testing::Mock; | |
| 40 using testing::Return; | |
| 41 using testing::WithArg; | |
| 42 using testing::WithArgs; | |
| 43 using testing::WithoutArgs; | |
| 44 | |
| 45 namespace syncer { | |
| 46 | |
| 47 using sync_pb::GetUpdatesCallerInfo; | |
| 48 | |
| 49 class MockSyncer : public Syncer { | |
| 50 public: | |
| 51 MockSyncer(); | |
| 52 MOCK_METHOD3(NormalSyncShare, bool(ModelTypeSet, NudgeTracker*, SyncCycle*)); | |
| 53 MOCK_METHOD3(ConfigureSyncShare, | |
| 54 bool(ModelTypeSet, | |
| 55 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource, | |
| 56 SyncCycle*)); | |
| 57 MOCK_METHOD2(PollSyncShare, bool(ModelTypeSet, SyncCycle*)); | |
| 58 }; | |
| 59 | |
| 60 MockSyncer::MockSyncer() : Syncer(NULL) {} | |
| 61 | |
| 62 typedef std::vector<TimeTicks> SyncShareTimes; | |
| 63 | |
| 64 void QuitLoopNow() { | |
| 65 // We use QuitNow() instead of Quit() as the latter may get stalled | |
| 66 // indefinitely in the presence of repeated timers with low delays | |
| 67 // and a slow test (e.g., ThrottlingDoesThrottle [which has a poll | |
| 68 // delay of 5ms] run under TSAN on the trybots). | |
| 69 base::MessageLoop::current()->QuitNow(); | |
| 70 } | |
| 71 | |
| 72 void RunLoop() { | |
| 73 base::RunLoop().Run(); | |
| 74 } | |
| 75 | |
| 76 void PumpLoop() { | |
| 77 // Do it this way instead of RunAllPending to pump loop exactly once | |
| 78 // (necessary in the presence of timers; see comment in | |
| 79 // QuitLoopNow). | |
| 80 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, | |
| 81 base::Bind(&QuitLoopNow)); | |
| 82 RunLoop(); | |
| 83 } | |
| 84 | |
| 85 void PumpLoopFor(base::TimeDelta time) { | |
| 86 // Allow the loop to run for the specified amount of time. | |
| 87 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
| 88 FROM_HERE, base::Bind(&QuitLoopNow), time); | |
| 89 RunLoop(); | |
| 90 } | |
| 91 | |
| 92 ModelSafeRoutingInfo TypesToRoutingInfo(ModelTypeSet types) { | |
| 93 ModelSafeRoutingInfo routes; | |
| 94 for (ModelTypeSet::Iterator iter = types.First(); iter.Good(); iter.Inc()) { | |
| 95 routes[iter.Get()] = GROUP_PASSIVE; | |
| 96 } | |
| 97 return routes; | |
| 98 } | |
| 99 | |
| 100 static const size_t kMinNumSamples = 5; | |
| 101 | |
| 102 // Test harness for the SyncScheduler. Test the delays and backoff timers used | |
| 103 // in response to various events. | |
| 104 // | |
| 105 // These tests execute in real time with real timers. We try to keep the | |
| 106 // delays short, but there is a limit to how short we can make them. The | |
| 107 // timers on some platforms (ie. Windows) have a timer resolution greater than | |
| 108 // 1ms. Using 1ms delays may result in test flakiness. | |
| 109 // | |
| 110 // See crbug.com/402212 for more info. | |
| 111 class SyncSchedulerTest : public testing::Test { | |
| 112 public: | |
| 113 SyncSchedulerTest() : syncer_(NULL), delay_(NULL), weak_ptr_factory_(this) {} | |
| 114 | |
| 115 class MockDelayProvider : public BackoffDelayProvider { | |
| 116 public: | |
| 117 MockDelayProvider() | |
| 118 : BackoffDelayProvider( | |
| 119 TimeDelta::FromSeconds(kInitialBackoffRetrySeconds), | |
| 120 TimeDelta::FromSeconds(kInitialBackoffImmediateRetrySeconds)) {} | |
| 121 | |
| 122 MOCK_METHOD1(GetDelay, TimeDelta(const TimeDelta&)); | |
| 123 }; | |
| 124 | |
| 125 void SetUp() override { | |
| 126 dir_maker_.SetUp(); | |
| 127 syncer_ = new testing::StrictMock<MockSyncer>(); | |
| 128 delay_ = NULL; | |
| 129 extensions_activity_ = new ExtensionsActivity(); | |
| 130 | |
| 131 routing_info_[THEMES] = GROUP_UI; | |
| 132 routing_info_[TYPED_URLS] = GROUP_DB; | |
| 133 routing_info_[THEMES] = GROUP_UI; | |
| 134 routing_info_[NIGORI] = GROUP_PASSIVE; | |
| 135 | |
| 136 workers_.clear(); | |
| 137 workers_.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_UI))); | |
| 138 workers_.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_DB))); | |
| 139 workers_.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_PASSIVE))); | |
| 140 | |
| 141 connection_.reset( | |
| 142 new MockConnectionManager(directory(), &cancelation_signal_)); | |
| 143 connection_->SetServerReachable(); | |
| 144 | |
| 145 model_type_registry_.reset( | |
| 146 new ModelTypeRegistry(workers_, directory(), &mock_nudge_handler_)); | |
| 147 | |
| 148 context_.reset(new SyncCycleContext( | |
| 149 connection_.get(), directory(), extensions_activity_.get(), | |
| 150 std::vector<SyncEngineEventListener*>(), NULL, | |
| 151 model_type_registry_.get(), | |
| 152 true, // enable keystore encryption | |
| 153 false, // force enable pre-commit GU avoidance | |
| 154 "fake_invalidator_client_id")); | |
| 155 context_->SetRoutingInfo(routing_info_); | |
| 156 context_->set_notifications_enabled(true); | |
| 157 context_->set_account_name("Test"); | |
| 158 scheduler_.reset(new SyncSchedulerImpl("TestSyncScheduler", | |
| 159 BackoffDelayProvider::FromDefaults(), | |
| 160 context(), syncer_)); | |
| 161 scheduler_->SetDefaultNudgeDelay(default_delay()); | |
| 162 } | |
| 163 | |
| 164 SyncSchedulerImpl* scheduler() { return scheduler_.get(); } | |
| 165 const ModelSafeRoutingInfo& routing_info() { return routing_info_; } | |
| 166 MockSyncer* syncer() { return syncer_; } | |
| 167 MockDelayProvider* delay() { return delay_; } | |
| 168 MockConnectionManager* connection() { return connection_.get(); } | |
| 169 TimeDelta default_delay() { return TimeDelta::FromSeconds(0); } | |
| 170 TimeDelta timeout() { return TestTimeouts::action_timeout(); } | |
| 171 | |
| 172 void TearDown() override { | |
| 173 PumpLoop(); | |
| 174 scheduler_.reset(); | |
| 175 PumpLoop(); | |
| 176 dir_maker_.TearDown(); | |
| 177 } | |
| 178 | |
| 179 void AnalyzePollRun(const SyncShareTimes& times, | |
| 180 size_t min_num_samples, | |
| 181 const TimeTicks& optimal_start, | |
| 182 const TimeDelta& poll_interval) { | |
| 183 EXPECT_GE(times.size(), min_num_samples); | |
| 184 for (size_t i = 0; i < times.size(); i++) { | |
| 185 SCOPED_TRACE(testing::Message() << "SyncShare # (" << i << ")"); | |
| 186 TimeTicks optimal_next_sync = optimal_start + poll_interval * i; | |
| 187 EXPECT_GE(times[i], optimal_next_sync); | |
| 188 } | |
| 189 } | |
| 190 | |
| 191 void DoQuitLoopNow() { QuitLoopNow(); } | |
| 192 | |
| 193 void StartSyncConfiguration() { | |
| 194 scheduler()->Start(SyncScheduler::CONFIGURATION_MODE, base::Time()); | |
| 195 } | |
| 196 | |
| 197 void StartSyncScheduler(base::Time last_poll_time) { | |
| 198 scheduler()->Start(SyncScheduler::NORMAL_MODE, last_poll_time); | |
| 199 } | |
| 200 | |
| 201 // This stops the scheduler synchronously. | |
| 202 void StopSyncScheduler() { | |
| 203 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 204 FROM_HERE, base::Bind(&SyncSchedulerTest::DoQuitLoopNow, | |
| 205 weak_ptr_factory_.GetWeakPtr())); | |
| 206 RunLoop(); | |
| 207 } | |
| 208 | |
| 209 bool RunAndGetBackoff() { | |
| 210 ModelTypeSet nudge_types(THEMES); | |
| 211 StartSyncScheduler(base::Time()); | |
| 212 | |
| 213 scheduler()->ScheduleLocalNudge(nudge_types, FROM_HERE); | |
| 214 RunLoop(); | |
| 215 | |
| 216 return scheduler()->IsBackingOff(); | |
| 217 } | |
| 218 | |
| 219 void UseMockDelayProvider() { | |
| 220 delay_ = new MockDelayProvider(); | |
| 221 scheduler_->delay_provider_.reset(delay_); | |
| 222 } | |
| 223 | |
| 224 SyncCycleContext* context() { return context_.get(); } | |
| 225 | |
| 226 ModelTypeSet GetThrottledTypes() { | |
| 227 return scheduler_->nudge_tracker_.GetThrottledTypes(); | |
| 228 } | |
| 229 | |
| 230 base::TimeDelta GetRetryTimerDelay() { | |
| 231 EXPECT_TRUE(scheduler_->retry_timer_.IsRunning()); | |
| 232 return scheduler_->retry_timer_.GetCurrentDelay(); | |
| 233 } | |
| 234 | |
| 235 static std::unique_ptr<InvalidationInterface> BuildInvalidation( | |
| 236 int64_t version, | |
| 237 const std::string& payload) { | |
| 238 return MockInvalidation::Build(version, payload); | |
| 239 } | |
| 240 | |
| 241 private: | |
| 242 syncable::Directory* directory() { return dir_maker_.directory(); } | |
| 243 | |
| 244 base::MessageLoop loop_; | |
| 245 TestDirectorySetterUpper dir_maker_; | |
| 246 CancelationSignal cancelation_signal_; | |
| 247 std::unique_ptr<MockConnectionManager> connection_; | |
| 248 std::unique_ptr<ModelTypeRegistry> model_type_registry_; | |
| 249 std::unique_ptr<SyncCycleContext> context_; | |
| 250 std::unique_ptr<SyncSchedulerImpl> scheduler_; | |
| 251 MockNudgeHandler mock_nudge_handler_; | |
| 252 MockSyncer* syncer_; | |
| 253 MockDelayProvider* delay_; | |
| 254 std::vector<scoped_refptr<ModelSafeWorker>> workers_; | |
| 255 scoped_refptr<ExtensionsActivity> extensions_activity_; | |
| 256 ModelSafeRoutingInfo routing_info_; | |
| 257 base::WeakPtrFactory<SyncSchedulerTest> weak_ptr_factory_; | |
| 258 }; | |
| 259 | |
| 260 void RecordSyncShareImpl(SyncShareTimes* times) { | |
| 261 times->push_back(TimeTicks::Now()); | |
| 262 } | |
| 263 | |
| 264 ACTION_P2(RecordSyncShare, times, success) { | |
| 265 RecordSyncShareImpl(times); | |
| 266 if (base::MessageLoop::current()->is_running()) | |
| 267 QuitLoopNow(); | |
| 268 return success; | |
| 269 } | |
| 270 | |
| 271 ACTION_P3(RecordSyncShareMultiple, times, quit_after, success) { | |
| 272 RecordSyncShareImpl(times); | |
| 273 EXPECT_LE(times->size(), quit_after); | |
| 274 if (times->size() >= quit_after && | |
| 275 base::MessageLoop::current()->is_running()) { | |
| 276 QuitLoopNow(); | |
| 277 } | |
| 278 return success; | |
| 279 } | |
| 280 | |
| 281 ACTION_P(StopScheduler, scheduler) { | |
| 282 scheduler->Stop(); | |
| 283 } | |
| 284 | |
| 285 ACTION(AddFailureAndQuitLoopNow) { | |
| 286 ADD_FAILURE(); | |
| 287 QuitLoopNow(); | |
| 288 return true; | |
| 289 } | |
| 290 | |
| 291 ACTION_P(QuitLoopNowAction, success) { | |
| 292 QuitLoopNow(); | |
| 293 return success; | |
| 294 } | |
| 295 | |
| 296 // Test nudge scheduling. | |
| 297 TEST_F(SyncSchedulerTest, Nudge) { | |
| 298 SyncShareTimes times; | |
| 299 ModelTypeSet model_types(THEMES); | |
| 300 | |
| 301 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 302 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), | |
| 303 RecordSyncShare(×, true))) | |
| 304 .RetiresOnSaturation(); | |
| 305 | |
| 306 StartSyncScheduler(base::Time()); | |
| 307 | |
| 308 scheduler()->ScheduleLocalNudge(model_types, FROM_HERE); | |
| 309 RunLoop(); | |
| 310 | |
| 311 Mock::VerifyAndClearExpectations(syncer()); | |
| 312 | |
| 313 // Make sure a second, later, nudge is unaffected by first (no coalescing). | |
| 314 SyncShareTimes times2; | |
| 315 model_types.Remove(THEMES); | |
| 316 model_types.Put(TYPED_URLS); | |
| 317 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 318 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), | |
| 319 RecordSyncShare(×2, true))); | |
| 320 scheduler()->ScheduleLocalNudge(model_types, FROM_HERE); | |
| 321 RunLoop(); | |
| 322 } | |
| 323 | |
| 324 // Make sure a regular config command is scheduled fine in the absence of any | |
| 325 // errors. | |
| 326 TEST_F(SyncSchedulerTest, Config) { | |
| 327 SyncShareTimes times; | |
| 328 const ModelTypeSet model_types(THEMES); | |
| 329 | |
| 330 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _)) | |
| 331 .WillOnce(DoAll(Invoke(test_util::SimulateConfigureSuccess), | |
| 332 RecordSyncShare(×, true))); | |
| 333 | |
| 334 StartSyncConfiguration(); | |
| 335 | |
| 336 CallbackCounter ready_counter; | |
| 337 CallbackCounter retry_counter; | |
| 338 ConfigurationParams params( | |
| 339 GetUpdatesCallerInfo::RECONFIGURATION, model_types, | |
| 340 TypesToRoutingInfo(model_types), | |
| 341 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)), | |
| 342 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter))); | |
| 343 scheduler()->ScheduleConfiguration(params); | |
| 344 PumpLoop(); | |
| 345 ASSERT_EQ(1, ready_counter.times_called()); | |
| 346 ASSERT_EQ(0, retry_counter.times_called()); | |
| 347 } | |
| 348 | |
| 349 // Simulate a failure and make sure the config request is retried. | |
| 350 TEST_F(SyncSchedulerTest, ConfigWithBackingOff) { | |
| 351 UseMockDelayProvider(); | |
| 352 EXPECT_CALL(*delay(), GetDelay(_)) | |
| 353 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(20))); | |
| 354 SyncShareTimes times; | |
| 355 const ModelTypeSet model_types(THEMES); | |
| 356 | |
| 357 StartSyncConfiguration(); | |
| 358 | |
| 359 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _)) | |
| 360 .WillOnce(DoAll(Invoke(test_util::SimulateConfigureFailed), | |
| 361 RecordSyncShare(×, false))) | |
| 362 .WillOnce(DoAll(Invoke(test_util::SimulateConfigureFailed), | |
| 363 RecordSyncShare(×, false))); | |
| 364 | |
| 365 CallbackCounter ready_counter; | |
| 366 CallbackCounter retry_counter; | |
| 367 ConfigurationParams params( | |
| 368 GetUpdatesCallerInfo::RECONFIGURATION, model_types, | |
| 369 TypesToRoutingInfo(model_types), | |
| 370 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)), | |
| 371 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter))); | |
| 372 scheduler()->ScheduleConfiguration(params); | |
| 373 RunLoop(); | |
| 374 ASSERT_EQ(0, ready_counter.times_called()); | |
| 375 ASSERT_EQ(1, retry_counter.times_called()); | |
| 376 | |
| 377 // RunLoop() will trigger TryCanaryJob which will retry configuration. | |
| 378 // Since retry_task was already called it shouldn't be called again. | |
| 379 RunLoop(); | |
| 380 ASSERT_EQ(0, ready_counter.times_called()); | |
| 381 ASSERT_EQ(1, retry_counter.times_called()); | |
| 382 | |
| 383 Mock::VerifyAndClearExpectations(syncer()); | |
| 384 | |
| 385 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _)) | |
| 386 .WillOnce(DoAll(Invoke(test_util::SimulateConfigureSuccess), | |
| 387 RecordSyncShare(×, true))); | |
| 388 RunLoop(); | |
| 389 | |
| 390 ASSERT_EQ(1, ready_counter.times_called()); | |
| 391 } | |
| 392 | |
| 393 // Simuilate SyncSchedulerImpl::Stop being called in the middle of Configure. | |
| 394 // This can happen if server returns NOT_MY_BIRTHDAY. | |
| 395 TEST_F(SyncSchedulerTest, ConfigWithStop) { | |
| 396 UseMockDelayProvider(); | |
| 397 EXPECT_CALL(*delay(), GetDelay(_)) | |
| 398 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(20))); | |
| 399 SyncShareTimes times; | |
| 400 const ModelTypeSet model_types(THEMES); | |
| 401 | |
| 402 StartSyncConfiguration(); | |
| 403 | |
| 404 // Make ConfigureSyncShare call scheduler->Stop(). It is not supposed to call | |
| 405 // retry_task or dereference configuration params. | |
| 406 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _)) | |
| 407 .WillOnce(DoAll(Invoke(test_util::SimulateConfigureFailed), | |
| 408 StopScheduler(scheduler()), | |
| 409 RecordSyncShare(×, false))); | |
| 410 | |
| 411 CallbackCounter ready_counter; | |
| 412 CallbackCounter retry_counter; | |
| 413 ConfigurationParams params( | |
| 414 GetUpdatesCallerInfo::RECONFIGURATION, model_types, | |
| 415 TypesToRoutingInfo(model_types), | |
| 416 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)), | |
| 417 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter))); | |
| 418 scheduler()->ScheduleConfiguration(params); | |
| 419 PumpLoop(); | |
| 420 ASSERT_EQ(0, ready_counter.times_called()); | |
| 421 ASSERT_EQ(0, retry_counter.times_called()); | |
| 422 } | |
| 423 | |
| 424 // Issue a nudge when the config has failed. Make sure both the config and | |
| 425 // nudge are executed. | |
| 426 TEST_F(SyncSchedulerTest, NudgeWithConfigWithBackingOff) { | |
| 427 const ModelTypeSet model_types(THEMES); | |
| 428 UseMockDelayProvider(); | |
| 429 EXPECT_CALL(*delay(), GetDelay(_)) | |
| 430 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(50))); | |
| 431 SyncShareTimes times; | |
| 432 | |
| 433 StartSyncConfiguration(); | |
| 434 | |
| 435 // Request a configure and make sure it fails. | |
| 436 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _)) | |
| 437 .WillOnce(DoAll(Invoke(test_util::SimulateConfigureFailed), | |
| 438 RecordSyncShare(×, false))); | |
| 439 CallbackCounter ready_counter; | |
| 440 CallbackCounter retry_counter; | |
| 441 ConfigurationParams params( | |
| 442 GetUpdatesCallerInfo::RECONFIGURATION, model_types, | |
| 443 TypesToRoutingInfo(model_types), | |
| 444 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)), | |
| 445 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter))); | |
| 446 scheduler()->ScheduleConfiguration(params); | |
| 447 RunLoop(); | |
| 448 ASSERT_EQ(0, ready_counter.times_called()); | |
| 449 ASSERT_EQ(1, retry_counter.times_called()); | |
| 450 Mock::VerifyAndClearExpectations(syncer()); | |
| 451 | |
| 452 // Ask for a nudge while dealing with repeated configure failure. | |
| 453 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _)) | |
| 454 .WillOnce(DoAll(Invoke(test_util::SimulateConfigureFailed), | |
| 455 RecordSyncShare(×, false))); | |
| 456 scheduler()->ScheduleLocalNudge(model_types, FROM_HERE); | |
| 457 RunLoop(); | |
| 458 // Note that we're not RunLoop()ing for the NUDGE we just scheduled, but | |
| 459 // for the first retry attempt from the config job (after | |
| 460 // waiting ~+/- 50ms). | |
| 461 Mock::VerifyAndClearExpectations(syncer()); | |
| 462 ASSERT_EQ(0, ready_counter.times_called()); | |
| 463 | |
| 464 // Let the next configure retry succeed. | |
| 465 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _)) | |
| 466 .WillOnce(DoAll(Invoke(test_util::SimulateConfigureSuccess), | |
| 467 RecordSyncShare(×, true))); | |
| 468 RunLoop(); | |
| 469 | |
| 470 // Now change the mode so nudge can execute. | |
| 471 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 472 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), | |
| 473 RecordSyncShare(×, true))); | |
| 474 StartSyncScheduler(base::Time()); | |
| 475 PumpLoop(); | |
| 476 } | |
| 477 | |
| 478 // Test that nudges are coalesced. | |
| 479 TEST_F(SyncSchedulerTest, NudgeCoalescing) { | |
| 480 StartSyncScheduler(base::Time()); | |
| 481 | |
| 482 SyncShareTimes times; | |
| 483 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 484 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), | |
| 485 RecordSyncShare(×, true))); | |
| 486 const ModelTypeSet types1(THEMES), types2(TYPED_URLS), types3(THEMES); | |
| 487 TimeTicks optimal_time = TimeTicks::Now() + default_delay(); | |
| 488 scheduler()->ScheduleLocalNudge(types1, FROM_HERE); | |
| 489 scheduler()->ScheduleLocalNudge(types2, FROM_HERE); | |
| 490 RunLoop(); | |
| 491 | |
| 492 ASSERT_EQ(1U, times.size()); | |
| 493 EXPECT_GE(times[0], optimal_time); | |
| 494 | |
| 495 Mock::VerifyAndClearExpectations(syncer()); | |
| 496 | |
| 497 SyncShareTimes times2; | |
| 498 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 499 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), | |
| 500 RecordSyncShare(×2, true))); | |
| 501 scheduler()->ScheduleLocalNudge(types3, FROM_HERE); | |
| 502 RunLoop(); | |
| 503 } | |
| 504 | |
| 505 // Test that nudges are coalesced. | |
| 506 TEST_F(SyncSchedulerTest, NudgeCoalescingWithDifferentTimings) { | |
| 507 StartSyncScheduler(base::Time()); | |
| 508 | |
| 509 SyncShareTimes times; | |
| 510 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 511 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), | |
| 512 RecordSyncShare(×, true))); | |
| 513 ModelTypeSet types1(THEMES), types2(TYPED_URLS), types3; | |
| 514 | |
| 515 // Create a huge time delay. | |
| 516 TimeDelta delay = TimeDelta::FromDays(1); | |
| 517 | |
| 518 std::map<ModelType, TimeDelta> delay_map; | |
| 519 delay_map[types1.First().Get()] = delay; | |
| 520 scheduler()->OnReceivedCustomNudgeDelays(delay_map); | |
| 521 scheduler()->ScheduleLocalNudge(types1, FROM_HERE); | |
| 522 scheduler()->ScheduleLocalNudge(types2, FROM_HERE); | |
| 523 | |
| 524 TimeTicks min_time = TimeTicks::Now(); | |
| 525 TimeTicks max_time = TimeTicks::Now() + delay; | |
| 526 | |
| 527 RunLoop(); | |
| 528 Mock::VerifyAndClearExpectations(syncer()); | |
| 529 | |
| 530 // Make sure the sync happened at the right time. | |
| 531 ASSERT_EQ(1U, times.size()); | |
| 532 EXPECT_GE(times[0], min_time); | |
| 533 EXPECT_LE(times[0], max_time); | |
| 534 } | |
| 535 | |
| 536 // Test nudge scheduling. | |
| 537 TEST_F(SyncSchedulerTest, NudgeWithStates) { | |
| 538 StartSyncScheduler(base::Time()); | |
| 539 | |
| 540 SyncShareTimes times1; | |
| 541 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 542 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), | |
| 543 RecordSyncShare(×1, true))) | |
| 544 .RetiresOnSaturation(); | |
| 545 scheduler()->ScheduleInvalidationNudge(THEMES, BuildInvalidation(10, "test"), | |
| 546 FROM_HERE); | |
| 547 RunLoop(); | |
| 548 | |
| 549 Mock::VerifyAndClearExpectations(syncer()); | |
| 550 | |
| 551 // Make sure a second, later, nudge is unaffected by first (no coalescing). | |
| 552 SyncShareTimes times2; | |
| 553 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 554 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), | |
| 555 RecordSyncShare(×2, true))); | |
| 556 scheduler()->ScheduleInvalidationNudge( | |
| 557 TYPED_URLS, BuildInvalidation(10, "test2"), FROM_HERE); | |
| 558 RunLoop(); | |
| 559 } | |
| 560 | |
| 561 // Test that polling works as expected. | |
| 562 TEST_F(SyncSchedulerTest, Polling) { | |
| 563 SyncShareTimes times; | |
| 564 TimeDelta poll_interval(TimeDelta::FromMilliseconds(30)); | |
| 565 EXPECT_CALL(*syncer(), PollSyncShare(_, _)) | |
| 566 .Times(AtLeast(kMinNumSamples)) | |
| 567 .WillRepeatedly( | |
| 568 DoAll(Invoke(test_util::SimulatePollSuccess), | |
| 569 RecordSyncShareMultiple(×, kMinNumSamples, true))); | |
| 570 | |
| 571 scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval); | |
| 572 | |
| 573 TimeTicks optimal_start = TimeTicks::Now() + poll_interval; | |
| 574 StartSyncScheduler(base::Time()); | |
| 575 | |
| 576 // Run again to wait for polling. | |
| 577 RunLoop(); | |
| 578 | |
| 579 StopSyncScheduler(); | |
| 580 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll_interval); | |
| 581 } | |
| 582 | |
| 583 // Test that we reuse the previous poll time on startup, triggering the first | |
| 584 // poll based on when the last one happened. Subsequent polls should have the | |
| 585 // normal delay. | |
| 586 TEST_F(SyncSchedulerTest, PollingPersistence) { | |
| 587 SyncShareTimes times; | |
| 588 // Use a large poll interval that wouldn't normally get hit on its own for | |
| 589 // some time yet. | |
| 590 TimeDelta poll_interval(TimeDelta::FromMilliseconds(500)); | |
| 591 EXPECT_CALL(*syncer(), PollSyncShare(_, _)) | |
| 592 .Times(AtLeast(kMinNumSamples)) | |
| 593 .WillRepeatedly( | |
| 594 DoAll(Invoke(test_util::SimulatePollSuccess), | |
| 595 RecordSyncShareMultiple(×, kMinNumSamples, true))); | |
| 596 | |
| 597 scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval); | |
| 598 | |
| 599 // Set the start time to now, as the poll was overdue. | |
| 600 TimeTicks optimal_start = TimeTicks::Now(); | |
| 601 StartSyncScheduler(base::Time::Now() - poll_interval); | |
| 602 | |
| 603 // Run again to wait for polling. | |
| 604 RunLoop(); | |
| 605 | |
| 606 StopSyncScheduler(); | |
| 607 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll_interval); | |
| 608 } | |
| 609 | |
| 610 // Test that if the persisted poll is in the future, it's ignored (the case | |
| 611 // where the local time has been modified). | |
| 612 TEST_F(SyncSchedulerTest, PollingPersistenceBadClock) { | |
| 613 SyncShareTimes times; | |
| 614 TimeDelta poll_interval(TimeDelta::FromMilliseconds(30)); | |
| 615 EXPECT_CALL(*syncer(), PollSyncShare(_, _)) | |
| 616 .Times(AtLeast(kMinNumSamples)) | |
| 617 .WillRepeatedly( | |
| 618 DoAll(Invoke(test_util::SimulatePollSuccess), | |
| 619 RecordSyncShareMultiple(×, kMinNumSamples, true))); | |
| 620 | |
| 621 scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval); | |
| 622 | |
| 623 // Set the start time to |poll_interval| in the future. | |
| 624 TimeTicks optimal_start = TimeTicks::Now() + poll_interval; | |
| 625 StartSyncScheduler(base::Time::Now() + base::TimeDelta::FromMinutes(10)); | |
| 626 | |
| 627 // Run again to wait for polling. | |
| 628 RunLoop(); | |
| 629 | |
| 630 StopSyncScheduler(); | |
| 631 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll_interval); | |
| 632 } | |
| 633 | |
| 634 // Test that the short poll interval is used. | |
| 635 TEST_F(SyncSchedulerTest, PollNotificationsDisabled) { | |
| 636 SyncShareTimes times; | |
| 637 TimeDelta poll_interval(TimeDelta::FromMilliseconds(30)); | |
| 638 EXPECT_CALL(*syncer(), PollSyncShare(_, _)) | |
| 639 .Times(AtLeast(kMinNumSamples)) | |
| 640 .WillRepeatedly( | |
| 641 DoAll(Invoke(test_util::SimulatePollSuccess), | |
| 642 RecordSyncShareMultiple(×, kMinNumSamples, true))); | |
| 643 | |
| 644 scheduler()->OnReceivedShortPollIntervalUpdate(poll_interval); | |
| 645 scheduler()->SetNotificationsEnabled(false); | |
| 646 | |
| 647 TimeTicks optimal_start = TimeTicks::Now() + poll_interval; | |
| 648 StartSyncScheduler(base::Time()); | |
| 649 | |
| 650 // Run again to wait for polling. | |
| 651 RunLoop(); | |
| 652 | |
| 653 StopSyncScheduler(); | |
| 654 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll_interval); | |
| 655 } | |
| 656 | |
| 657 // Test that polling intervals are updated when needed. | |
| 658 TEST_F(SyncSchedulerTest, PollIntervalUpdate) { | |
| 659 SyncShareTimes times; | |
| 660 TimeDelta poll1(TimeDelta::FromMilliseconds(120)); | |
| 661 TimeDelta poll2(TimeDelta::FromMilliseconds(30)); | |
| 662 scheduler()->OnReceivedLongPollIntervalUpdate(poll1); | |
| 663 EXPECT_CALL(*syncer(), PollSyncShare(_, _)) | |
| 664 .Times(AtLeast(kMinNumSamples)) | |
| 665 .WillOnce( | |
| 666 DoAll(WithArgs<0, 1>(test_util::SimulatePollIntervalUpdate(poll2)), | |
| 667 Return(true))) | |
| 668 .WillRepeatedly(DoAll( | |
| 669 Invoke(test_util::SimulatePollSuccess), | |
| 670 WithArg<1>(RecordSyncShareMultiple(×, kMinNumSamples, true)))); | |
| 671 | |
| 672 TimeTicks optimal_start = TimeTicks::Now() + poll1 + poll2; | |
| 673 StartSyncScheduler(base::Time()); | |
| 674 | |
| 675 // Run again to wait for polling. | |
| 676 RunLoop(); | |
| 677 | |
| 678 StopSyncScheduler(); | |
| 679 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll2); | |
| 680 } | |
| 681 | |
| 682 // Test that no syncing occurs when throttled. | |
| 683 TEST_F(SyncSchedulerTest, ThrottlingDoesThrottle) { | |
| 684 const ModelTypeSet types(THEMES); | |
| 685 TimeDelta poll(TimeDelta::FromMilliseconds(20)); | |
| 686 TimeDelta throttle(TimeDelta::FromMinutes(10)); | |
| 687 scheduler()->OnReceivedLongPollIntervalUpdate(poll); | |
| 688 | |
| 689 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _)) | |
| 690 .WillOnce(DoAll(WithArg<2>(test_util::SimulateThrottled(throttle)), | |
| 691 Return(false))) | |
| 692 .WillRepeatedly(AddFailureAndQuitLoopNow()); | |
| 693 | |
| 694 StartSyncScheduler(base::Time()); | |
| 695 | |
| 696 scheduler()->ScheduleLocalNudge(types, FROM_HERE); | |
| 697 PumpLoop(); | |
| 698 | |
| 699 StartSyncConfiguration(); | |
| 700 | |
| 701 CallbackCounter ready_counter; | |
| 702 CallbackCounter retry_counter; | |
| 703 ConfigurationParams params( | |
| 704 GetUpdatesCallerInfo::RECONFIGURATION, types, TypesToRoutingInfo(types), | |
| 705 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)), | |
| 706 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter))); | |
| 707 scheduler()->ScheduleConfiguration(params); | |
| 708 PumpLoop(); | |
| 709 ASSERT_EQ(0, ready_counter.times_called()); | |
| 710 ASSERT_EQ(1, retry_counter.times_called()); | |
| 711 } | |
| 712 | |
| 713 TEST_F(SyncSchedulerTest, ThrottlingExpiresFromPoll) { | |
| 714 SyncShareTimes times; | |
| 715 TimeDelta poll(TimeDelta::FromMilliseconds(15)); | |
| 716 TimeDelta throttle1(TimeDelta::FromMilliseconds(150)); | |
| 717 scheduler()->OnReceivedLongPollIntervalUpdate(poll); | |
| 718 | |
| 719 ::testing::InSequence seq; | |
| 720 EXPECT_CALL(*syncer(), PollSyncShare(_, _)) | |
| 721 .WillOnce(DoAll(WithArg<1>(test_util::SimulateThrottled(throttle1)), | |
| 722 Return(false))) | |
| 723 .RetiresOnSaturation(); | |
| 724 EXPECT_CALL(*syncer(), PollSyncShare(_, _)) | |
| 725 .WillRepeatedly( | |
| 726 DoAll(Invoke(test_util::SimulatePollSuccess), | |
| 727 RecordSyncShareMultiple(×, kMinNumSamples, true))); | |
| 728 | |
| 729 TimeTicks optimal_start = TimeTicks::Now() + poll + throttle1; | |
| 730 StartSyncScheduler(base::Time()); | |
| 731 | |
| 732 // Run again to wait for polling. | |
| 733 RunLoop(); | |
| 734 | |
| 735 StopSyncScheduler(); | |
| 736 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll); | |
| 737 } | |
| 738 | |
| 739 TEST_F(SyncSchedulerTest, ThrottlingExpiresFromNudge) { | |
| 740 SyncShareTimes times; | |
| 741 TimeDelta poll(TimeDelta::FromDays(1)); | |
| 742 TimeDelta throttle1(TimeDelta::FromMilliseconds(150)); | |
| 743 scheduler()->OnReceivedLongPollIntervalUpdate(poll); | |
| 744 | |
| 745 ::testing::InSequence seq; | |
| 746 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 747 .WillOnce(DoAll(WithArg<2>(test_util::SimulateThrottled(throttle1)), | |
| 748 Return(false))) | |
| 749 .RetiresOnSaturation(); | |
| 750 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 751 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), | |
| 752 QuitLoopNowAction(true))); | |
| 753 | |
| 754 const ModelTypeSet types(THEMES); | |
| 755 StartSyncScheduler(base::Time()); | |
| 756 scheduler()->ScheduleLocalNudge(types, FROM_HERE); | |
| 757 | |
| 758 PumpLoop(); // To get PerformDelayedNudge called. | |
| 759 PumpLoop(); // To get TrySyncCycleJob called | |
| 760 EXPECT_TRUE(scheduler()->IsCurrentlyThrottled()); | |
| 761 RunLoop(); | |
| 762 EXPECT_FALSE(scheduler()->IsCurrentlyThrottled()); | |
| 763 | |
| 764 StopSyncScheduler(); | |
| 765 } | |
| 766 | |
| 767 TEST_F(SyncSchedulerTest, ThrottlingExpiresFromConfigure) { | |
| 768 SyncShareTimes times; | |
| 769 TimeDelta poll(TimeDelta::FromDays(1)); | |
| 770 TimeDelta throttle1(TimeDelta::FromMilliseconds(150)); | |
| 771 scheduler()->OnReceivedLongPollIntervalUpdate(poll); | |
| 772 | |
| 773 ::testing::InSequence seq; | |
| 774 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _)) | |
| 775 .WillOnce(DoAll(WithArg<2>(test_util::SimulateThrottled(throttle1)), | |
| 776 Return(false))) | |
| 777 .RetiresOnSaturation(); | |
| 778 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _)) | |
| 779 .WillOnce(DoAll(Invoke(test_util::SimulateConfigureSuccess), | |
| 780 QuitLoopNowAction(true))); | |
| 781 | |
| 782 const ModelTypeSet types(THEMES); | |
| 783 StartSyncConfiguration(); | |
| 784 | |
| 785 CallbackCounter ready_counter; | |
| 786 CallbackCounter retry_counter; | |
| 787 ConfigurationParams params( | |
| 788 GetUpdatesCallerInfo::RECONFIGURATION, types, TypesToRoutingInfo(types), | |
| 789 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)), | |
| 790 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter))); | |
| 791 scheduler()->ScheduleConfiguration(params); | |
| 792 PumpLoop(); | |
| 793 EXPECT_EQ(0, ready_counter.times_called()); | |
| 794 EXPECT_EQ(1, retry_counter.times_called()); | |
| 795 EXPECT_TRUE(scheduler()->IsCurrentlyThrottled()); | |
| 796 | |
| 797 RunLoop(); | |
| 798 EXPECT_FALSE(scheduler()->IsCurrentlyThrottled()); | |
| 799 | |
| 800 StopSyncScheduler(); | |
| 801 } | |
| 802 | |
| 803 TEST_F(SyncSchedulerTest, TypeThrottlingBlocksNudge) { | |
| 804 UseMockDelayProvider(); | |
| 805 EXPECT_CALL(*delay(), GetDelay(_)).WillRepeatedly(Return(default_delay())); | |
| 806 | |
| 807 TimeDelta poll(TimeDelta::FromDays(1)); | |
| 808 TimeDelta throttle1(TimeDelta::FromSeconds(60)); | |
| 809 scheduler()->OnReceivedLongPollIntervalUpdate(poll); | |
| 810 | |
| 811 const ModelTypeSet types(THEMES); | |
| 812 | |
| 813 ::testing::InSequence seq; | |
| 814 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 815 .WillOnce( | |
| 816 DoAll(WithArg<2>(test_util::SimulateTypesThrottled(types, throttle1)), | |
| 817 Return(false))) | |
| 818 .RetiresOnSaturation(); | |
| 819 | |
| 820 StartSyncScheduler(base::Time()); | |
| 821 scheduler()->ScheduleLocalNudge(types, FROM_HERE); | |
| 822 PumpLoop(); // To get PerformDelayedNudge called. | |
| 823 PumpLoop(); // To get TrySyncCycleJob called | |
| 824 EXPECT_TRUE(GetThrottledTypes().HasAll(types)); | |
| 825 | |
| 826 // This won't cause a sync cycle because the types are throttled. | |
| 827 scheduler()->ScheduleLocalNudge(types, FROM_HERE); | |
| 828 PumpLoop(); | |
| 829 | |
| 830 StopSyncScheduler(); | |
| 831 } | |
| 832 | |
| 833 TEST_F(SyncSchedulerTest, TypeThrottlingDoesBlockOtherSources) { | |
| 834 UseMockDelayProvider(); | |
| 835 EXPECT_CALL(*delay(), GetDelay(_)).WillRepeatedly(Return(default_delay())); | |
| 836 | |
| 837 SyncShareTimes times; | |
| 838 TimeDelta poll(TimeDelta::FromDays(1)); | |
| 839 TimeDelta throttle1(TimeDelta::FromSeconds(60)); | |
| 840 scheduler()->OnReceivedLongPollIntervalUpdate(poll); | |
| 841 | |
| 842 const ModelTypeSet throttled_types(THEMES); | |
| 843 const ModelTypeSet unthrottled_types(PREFERENCES); | |
| 844 | |
| 845 ::testing::InSequence seq; | |
| 846 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 847 .WillOnce(DoAll(WithArg<2>(test_util::SimulateTypesThrottled( | |
| 848 throttled_types, throttle1)), | |
| 849 Return(false))) | |
| 850 .RetiresOnSaturation(); | |
| 851 | |
| 852 StartSyncScheduler(base::Time()); | |
| 853 scheduler()->ScheduleLocalNudge(throttled_types, FROM_HERE); | |
| 854 PumpLoop(); // To get PerformDelayedNudge called. | |
| 855 PumpLoop(); // To get TrySyncCycleJob called | |
| 856 EXPECT_TRUE(GetThrottledTypes().HasAll(throttled_types)); | |
| 857 | |
| 858 // Ignore invalidations for throttled types. | |
| 859 scheduler()->ScheduleInvalidationNudge(THEMES, BuildInvalidation(10, "test"), | |
| 860 FROM_HERE); | |
| 861 PumpLoop(); | |
| 862 | |
| 863 // Ignore refresh requests for throttled types. | |
| 864 scheduler()->ScheduleLocalRefreshRequest(throttled_types, FROM_HERE); | |
| 865 PumpLoop(); | |
| 866 | |
| 867 Mock::VerifyAndClearExpectations(syncer()); | |
| 868 | |
| 869 // Local nudges for non-throttled types will trigger a sync. | |
| 870 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 871 .WillRepeatedly(DoAll(Invoke(test_util::SimulateNormalSuccess), | |
| 872 RecordSyncShare(×, true))); | |
| 873 scheduler()->ScheduleLocalNudge(unthrottled_types, FROM_HERE); | |
| 874 RunLoop(); | |
| 875 Mock::VerifyAndClearExpectations(syncer()); | |
| 876 | |
| 877 StopSyncScheduler(); | |
| 878 } | |
| 879 | |
| 880 // Test nudges / polls don't run in config mode and config tasks do. | |
| 881 TEST_F(SyncSchedulerTest, ConfigurationMode) { | |
| 882 TimeDelta poll(TimeDelta::FromMilliseconds(15)); | |
| 883 SyncShareTimes times; | |
| 884 scheduler()->OnReceivedLongPollIntervalUpdate(poll); | |
| 885 | |
| 886 StartSyncConfiguration(); | |
| 887 | |
| 888 const ModelTypeSet nudge_types(TYPED_URLS); | |
| 889 scheduler()->ScheduleLocalNudge(nudge_types, FROM_HERE); | |
| 890 scheduler()->ScheduleLocalNudge(nudge_types, FROM_HERE); | |
| 891 | |
| 892 const ModelTypeSet config_types(THEMES); | |
| 893 | |
| 894 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _)) | |
| 895 .WillOnce(DoAll(Invoke(test_util::SimulateConfigureSuccess), | |
| 896 RecordSyncShare(×, true))) | |
| 897 .RetiresOnSaturation(); | |
| 898 CallbackCounter ready_counter; | |
| 899 CallbackCounter retry_counter; | |
| 900 ConfigurationParams params( | |
| 901 GetUpdatesCallerInfo::RECONFIGURATION, config_types, | |
| 902 TypesToRoutingInfo(config_types), | |
| 903 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)), | |
| 904 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter))); | |
| 905 scheduler()->ScheduleConfiguration(params); | |
| 906 RunLoop(); | |
| 907 ASSERT_EQ(1, ready_counter.times_called()); | |
| 908 ASSERT_EQ(0, retry_counter.times_called()); | |
| 909 | |
| 910 Mock::VerifyAndClearExpectations(syncer()); | |
| 911 | |
| 912 // Switch to NORMAL_MODE to ensure NUDGES were properly saved and run. | |
| 913 scheduler()->OnReceivedLongPollIntervalUpdate(TimeDelta::FromDays(1)); | |
| 914 SyncShareTimes times2; | |
| 915 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 916 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), | |
| 917 RecordSyncShare(×2, true))); | |
| 918 | |
| 919 // TODO(tim): Figure out how to remove this dangerous need to reset | |
| 920 // routing info between mode switches. | |
| 921 context()->SetRoutingInfo(routing_info()); | |
| 922 StartSyncScheduler(base::Time()); | |
| 923 | |
| 924 RunLoop(); | |
| 925 Mock::VerifyAndClearExpectations(syncer()); | |
| 926 } | |
| 927 | |
| 928 class BackoffTriggersSyncSchedulerTest : public SyncSchedulerTest { | |
| 929 void SetUp() override { | |
| 930 SyncSchedulerTest::SetUp(); | |
| 931 UseMockDelayProvider(); | |
| 932 EXPECT_CALL(*delay(), GetDelay(_)) | |
| 933 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(10))); | |
| 934 } | |
| 935 | |
| 936 void TearDown() override { | |
| 937 StopSyncScheduler(); | |
| 938 SyncSchedulerTest::TearDown(); | |
| 939 } | |
| 940 }; | |
| 941 | |
| 942 // Have the syncer fail during commit. Expect that the scheduler enters | |
| 943 // backoff. | |
| 944 TEST_F(BackoffTriggersSyncSchedulerTest, FailCommitOnce) { | |
| 945 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 946 .WillOnce(DoAll(Invoke(test_util::SimulateCommitFailed), | |
| 947 QuitLoopNowAction(false))); | |
| 948 EXPECT_TRUE(RunAndGetBackoff()); | |
| 949 } | |
| 950 | |
| 951 // Have the syncer fail during download updates and succeed on the first | |
| 952 // retry. Expect that this clears the backoff state. | |
| 953 TEST_F(BackoffTriggersSyncSchedulerTest, FailDownloadOnceThenSucceed) { | |
| 954 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 955 .WillOnce(DoAll(Invoke(test_util::SimulateDownloadUpdatesFailed), | |
| 956 Return(false))) | |
| 957 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), | |
| 958 QuitLoopNowAction(true))); | |
| 959 EXPECT_FALSE(RunAndGetBackoff()); | |
| 960 } | |
| 961 | |
| 962 // Have the syncer fail during commit and succeed on the first retry. Expect | |
| 963 // that this clears the backoff state. | |
| 964 TEST_F(BackoffTriggersSyncSchedulerTest, FailCommitOnceThenSucceed) { | |
| 965 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 966 .WillOnce(DoAll(Invoke(test_util::SimulateCommitFailed), Return(false))) | |
| 967 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), | |
| 968 QuitLoopNowAction(true))); | |
| 969 EXPECT_FALSE(RunAndGetBackoff()); | |
| 970 } | |
| 971 | |
| 972 // Have the syncer fail to download updates and fail again on the retry. | |
| 973 // Expect this will leave the scheduler in backoff. | |
| 974 TEST_F(BackoffTriggersSyncSchedulerTest, FailDownloadTwice) { | |
| 975 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 976 .WillOnce(DoAll(Invoke(test_util::SimulateDownloadUpdatesFailed), | |
| 977 Return(false))) | |
| 978 .WillRepeatedly(DoAll(Invoke(test_util::SimulateDownloadUpdatesFailed), | |
| 979 QuitLoopNowAction(false))); | |
| 980 EXPECT_TRUE(RunAndGetBackoff()); | |
| 981 } | |
| 982 | |
| 983 // Have the syncer fail to get the encryption key yet succeed in downloading | |
| 984 // updates. Expect this will leave the scheduler in backoff. | |
| 985 TEST_F(BackoffTriggersSyncSchedulerTest, FailGetEncryptionKey) { | |
| 986 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _)) | |
| 987 .WillOnce(DoAll(Invoke(test_util::SimulateGetEncryptionKeyFailed), | |
| 988 Return(false))) | |
| 989 .WillRepeatedly(DoAll(Invoke(test_util::SimulateGetEncryptionKeyFailed), | |
| 990 QuitLoopNowAction(false))); | |
| 991 StartSyncConfiguration(); | |
| 992 | |
| 993 ModelTypeSet types(THEMES); | |
| 994 CallbackCounter ready_counter; | |
| 995 CallbackCounter retry_counter; | |
| 996 ConfigurationParams params( | |
| 997 GetUpdatesCallerInfo::RECONFIGURATION, types, TypesToRoutingInfo(types), | |
| 998 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)), | |
| 999 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter))); | |
| 1000 scheduler()->ScheduleConfiguration(params); | |
| 1001 RunLoop(); | |
| 1002 | |
| 1003 EXPECT_TRUE(scheduler()->IsBackingOff()); | |
| 1004 } | |
| 1005 | |
| 1006 // Test that no polls or extraneous nudges occur when in backoff. | |
| 1007 TEST_F(SyncSchedulerTest, BackoffDropsJobs) { | |
| 1008 SyncShareTimes times; | |
| 1009 TimeDelta poll(TimeDelta::FromMilliseconds(10)); | |
| 1010 const ModelTypeSet types(THEMES); | |
| 1011 scheduler()->OnReceivedLongPollIntervalUpdate(poll); | |
| 1012 UseMockDelayProvider(); | |
| 1013 | |
| 1014 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 1015 .WillOnce(DoAll(Invoke(test_util::SimulateCommitFailed), | |
| 1016 RecordSyncShareMultiple(×, 1U, false))); | |
| 1017 EXPECT_CALL(*delay(), GetDelay(_)) | |
| 1018 .WillRepeatedly(Return(TimeDelta::FromDays(1))); | |
| 1019 | |
| 1020 StartSyncScheduler(base::Time()); | |
| 1021 | |
| 1022 // This nudge should fail and put us into backoff. Thanks to our mock | |
| 1023 // GetDelay() setup above, this will be a long backoff. | |
| 1024 scheduler()->ScheduleLocalNudge(types, FROM_HERE); | |
| 1025 RunLoop(); | |
| 1026 | |
| 1027 // From this point forward, no SyncShare functions should be invoked. | |
| 1028 Mock::VerifyAndClearExpectations(syncer()); | |
| 1029 | |
| 1030 // Wait a while (10x poll interval) so a few poll jobs will be attempted. | |
| 1031 PumpLoopFor(poll * 10); | |
| 1032 | |
| 1033 // Try (and fail) to schedule a nudge. | |
| 1034 scheduler()->ScheduleLocalNudge(types, FROM_HERE); | |
| 1035 | |
| 1036 Mock::VerifyAndClearExpectations(syncer()); | |
| 1037 Mock::VerifyAndClearExpectations(delay()); | |
| 1038 | |
| 1039 EXPECT_CALL(*delay(), GetDelay(_)).Times(0); | |
| 1040 | |
| 1041 StartSyncConfiguration(); | |
| 1042 | |
| 1043 CallbackCounter ready_counter; | |
| 1044 CallbackCounter retry_counter; | |
| 1045 ConfigurationParams params( | |
| 1046 GetUpdatesCallerInfo::RECONFIGURATION, types, TypesToRoutingInfo(types), | |
| 1047 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)), | |
| 1048 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter))); | |
| 1049 scheduler()->ScheduleConfiguration(params); | |
| 1050 PumpLoop(); | |
| 1051 ASSERT_EQ(0, ready_counter.times_called()); | |
| 1052 ASSERT_EQ(1, retry_counter.times_called()); | |
| 1053 } | |
| 1054 | |
| 1055 // Test that backoff is shaping traffic properly with consecutive errors. | |
| 1056 TEST_F(SyncSchedulerTest, BackoffElevation) { | |
| 1057 SyncShareTimes times; | |
| 1058 UseMockDelayProvider(); | |
| 1059 | |
| 1060 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 1061 .Times(kMinNumSamples) | |
| 1062 .WillRepeatedly( | |
| 1063 DoAll(Invoke(test_util::SimulateCommitFailed), | |
| 1064 RecordSyncShareMultiple(×, kMinNumSamples, false))); | |
| 1065 | |
| 1066 const TimeDelta first = TimeDelta::FromSeconds(kInitialBackoffRetrySeconds); | |
| 1067 const TimeDelta second = TimeDelta::FromMilliseconds(20); | |
| 1068 const TimeDelta third = TimeDelta::FromMilliseconds(30); | |
| 1069 const TimeDelta fourth = TimeDelta::FromMilliseconds(40); | |
| 1070 const TimeDelta fifth = TimeDelta::FromMilliseconds(50); | |
| 1071 const TimeDelta sixth = TimeDelta::FromDays(1); | |
| 1072 | |
| 1073 EXPECT_CALL(*delay(), GetDelay(first)) | |
| 1074 .WillOnce(Return(second)) | |
| 1075 .RetiresOnSaturation(); | |
| 1076 EXPECT_CALL(*delay(), GetDelay(second)) | |
| 1077 .WillOnce(Return(third)) | |
| 1078 .RetiresOnSaturation(); | |
| 1079 EXPECT_CALL(*delay(), GetDelay(third)) | |
| 1080 .WillOnce(Return(fourth)) | |
| 1081 .RetiresOnSaturation(); | |
| 1082 EXPECT_CALL(*delay(), GetDelay(fourth)) | |
| 1083 .WillOnce(Return(fifth)) | |
| 1084 .RetiresOnSaturation(); | |
| 1085 EXPECT_CALL(*delay(), GetDelay(fifth)).WillOnce(Return(sixth)); | |
| 1086 | |
| 1087 StartSyncScheduler(base::Time()); | |
| 1088 | |
| 1089 // Run again with a nudge. | |
| 1090 scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE); | |
| 1091 RunLoop(); | |
| 1092 | |
| 1093 ASSERT_EQ(kMinNumSamples, times.size()); | |
| 1094 EXPECT_GE(times[1] - times[0], second); | |
| 1095 EXPECT_GE(times[2] - times[1], third); | |
| 1096 EXPECT_GE(times[3] - times[2], fourth); | |
| 1097 EXPECT_GE(times[4] - times[3], fifth); | |
| 1098 } | |
| 1099 | |
| 1100 // Test that things go back to normal once a retry makes forward progress. | |
| 1101 TEST_F(SyncSchedulerTest, BackoffRelief) { | |
| 1102 SyncShareTimes times; | |
| 1103 UseMockDelayProvider(); | |
| 1104 | |
| 1105 const TimeDelta backoff = TimeDelta::FromMilliseconds(10); | |
| 1106 EXPECT_CALL(*delay(), GetDelay(_)).WillOnce(Return(backoff)); | |
| 1107 | |
| 1108 // Optimal start for the post-backoff poll party. | |
| 1109 TimeTicks optimal_start = TimeTicks::Now(); | |
| 1110 StartSyncScheduler(base::Time()); | |
| 1111 | |
| 1112 // Kick off the test with a failed nudge. | |
| 1113 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 1114 .WillOnce(DoAll(Invoke(test_util::SimulateCommitFailed), | |
| 1115 RecordSyncShare(×, false))); | |
| 1116 scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE); | |
| 1117 RunLoop(); | |
| 1118 Mock::VerifyAndClearExpectations(syncer()); | |
| 1119 TimeTicks optimal_job_time = optimal_start; | |
| 1120 ASSERT_EQ(1U, times.size()); | |
| 1121 EXPECT_GE(times[0], optimal_job_time); | |
| 1122 | |
| 1123 // The retry succeeds. | |
| 1124 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 1125 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), | |
| 1126 RecordSyncShare(×, true))); | |
| 1127 RunLoop(); | |
| 1128 Mock::VerifyAndClearExpectations(syncer()); | |
| 1129 optimal_job_time = optimal_job_time + backoff; | |
| 1130 ASSERT_EQ(2U, times.size()); | |
| 1131 EXPECT_GE(times[1], optimal_job_time); | |
| 1132 | |
| 1133 // Now let the Poll timer do its thing. | |
| 1134 EXPECT_CALL(*syncer(), PollSyncShare(_, _)) | |
| 1135 .WillRepeatedly( | |
| 1136 DoAll(Invoke(test_util::SimulatePollSuccess), | |
| 1137 RecordSyncShareMultiple(×, kMinNumSamples, true))); | |
| 1138 const TimeDelta poll(TimeDelta::FromMilliseconds(10)); | |
| 1139 scheduler()->OnReceivedLongPollIntervalUpdate(poll); | |
| 1140 | |
| 1141 // The new optimal time is now, since the desired poll should have happened | |
| 1142 // in the past. | |
| 1143 optimal_job_time = base::TimeTicks::Now(); | |
| 1144 RunLoop(); | |
| 1145 Mock::VerifyAndClearExpectations(syncer()); | |
| 1146 ASSERT_EQ(kMinNumSamples, times.size()); | |
| 1147 for (size_t i = 2; i < times.size(); i++) { | |
| 1148 SCOPED_TRACE(testing::Message() << "SyncShare # (" << i << ")"); | |
| 1149 EXPECT_GE(times[i], optimal_job_time); | |
| 1150 optimal_job_time = optimal_job_time + poll; | |
| 1151 } | |
| 1152 | |
| 1153 StopSyncScheduler(); | |
| 1154 } | |
| 1155 | |
| 1156 // Test that poll failures are treated like any other failure. They should | |
| 1157 // result in retry with backoff. | |
| 1158 TEST_F(SyncSchedulerTest, TransientPollFailure) { | |
| 1159 SyncShareTimes times; | |
| 1160 const TimeDelta poll_interval(TimeDelta::FromMilliseconds(10)); | |
| 1161 scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval); | |
| 1162 UseMockDelayProvider(); // Will cause test failure if backoff is initiated. | |
| 1163 EXPECT_CALL(*delay(), GetDelay(_)) | |
| 1164 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(0))); | |
| 1165 | |
| 1166 EXPECT_CALL(*syncer(), PollSyncShare(_, _)) | |
| 1167 .WillOnce(DoAll(Invoke(test_util::SimulatePollFailed), | |
| 1168 RecordSyncShare(×, false))) | |
| 1169 .WillOnce(DoAll(Invoke(test_util::SimulatePollSuccess), | |
| 1170 RecordSyncShare(×, true))); | |
| 1171 | |
| 1172 StartSyncScheduler(base::Time()); | |
| 1173 | |
| 1174 // Run the unsuccessful poll. The failed poll should not trigger backoff. | |
| 1175 RunLoop(); | |
| 1176 EXPECT_TRUE(scheduler()->IsBackingOff()); | |
| 1177 | |
| 1178 // Run the successful poll. | |
| 1179 RunLoop(); | |
| 1180 EXPECT_FALSE(scheduler()->IsBackingOff()); | |
| 1181 } | |
| 1182 | |
| 1183 // Test that starting the syncer thread without a valid connection doesn't | |
| 1184 // break things when a connection is detected. | |
| 1185 TEST_F(SyncSchedulerTest, StartWhenNotConnected) { | |
| 1186 connection()->SetServerNotReachable(); | |
| 1187 connection()->UpdateConnectionStatus(); | |
| 1188 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 1189 .WillOnce( | |
| 1190 DoAll(Invoke(test_util::SimulateConnectionFailure), Return(false))) | |
| 1191 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), Return(true))); | |
| 1192 StartSyncScheduler(base::Time()); | |
| 1193 | |
| 1194 scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE); | |
| 1195 // Should save the nudge for until after the server is reachable. | |
| 1196 base::RunLoop().RunUntilIdle(); | |
| 1197 | |
| 1198 scheduler()->OnConnectionStatusChange(); | |
| 1199 connection()->SetServerReachable(); | |
| 1200 connection()->UpdateConnectionStatus(); | |
| 1201 base::RunLoop().RunUntilIdle(); | |
| 1202 } | |
| 1203 | |
| 1204 TEST_F(SyncSchedulerTest, ServerConnectionChangeDuringBackoff) { | |
| 1205 UseMockDelayProvider(); | |
| 1206 EXPECT_CALL(*delay(), GetDelay(_)) | |
| 1207 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(0))); | |
| 1208 | |
| 1209 StartSyncScheduler(base::Time()); | |
| 1210 connection()->SetServerNotReachable(); | |
| 1211 connection()->UpdateConnectionStatus(); | |
| 1212 | |
| 1213 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 1214 .WillOnce( | |
| 1215 DoAll(Invoke(test_util::SimulateConnectionFailure), Return(false))) | |
| 1216 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), Return(true))); | |
| 1217 | |
| 1218 scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE); | |
| 1219 PumpLoop(); // To get PerformDelayedNudge called. | |
| 1220 PumpLoop(); // Run the nudge, that will fail and schedule a quick retry. | |
| 1221 ASSERT_TRUE(scheduler()->IsBackingOff()); | |
| 1222 | |
| 1223 // Before we run the scheduled canary, trigger a server connection change. | |
| 1224 scheduler()->OnConnectionStatusChange(); | |
| 1225 connection()->SetServerReachable(); | |
| 1226 connection()->UpdateConnectionStatus(); | |
| 1227 base::RunLoop().RunUntilIdle(); | |
| 1228 } | |
| 1229 | |
| 1230 // This was supposed to test the scenario where we receive a nudge while a | |
| 1231 // connection change canary is scheduled, but has not run yet. Since we've made | |
| 1232 // the connection change canary synchronous, this is no longer possible. | |
| 1233 TEST_F(SyncSchedulerTest, ConnectionChangeCanaryPreemptedByNudge) { | |
| 1234 UseMockDelayProvider(); | |
| 1235 EXPECT_CALL(*delay(), GetDelay(_)) | |
| 1236 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(0))); | |
| 1237 | |
| 1238 StartSyncScheduler(base::Time()); | |
| 1239 connection()->SetServerNotReachable(); | |
| 1240 connection()->UpdateConnectionStatus(); | |
| 1241 | |
| 1242 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 1243 .WillOnce( | |
| 1244 DoAll(Invoke(test_util::SimulateConnectionFailure), Return(false))) | |
| 1245 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), Return(true))) | |
| 1246 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), | |
| 1247 QuitLoopNowAction(true))); | |
| 1248 | |
| 1249 scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE); | |
| 1250 | |
| 1251 PumpLoop(); // To get PerformDelayedNudge called. | |
| 1252 PumpLoop(); // Run the nudge, that will fail and schedule a quick retry. | |
| 1253 ASSERT_TRUE(scheduler()->IsBackingOff()); | |
| 1254 | |
| 1255 // Before we run the scheduled canary, trigger a server connection change. | |
| 1256 scheduler()->OnConnectionStatusChange(); | |
| 1257 PumpLoop(); | |
| 1258 connection()->SetServerReachable(); | |
| 1259 connection()->UpdateConnectionStatus(); | |
| 1260 scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE); | |
| 1261 base::RunLoop().RunUntilIdle(); | |
| 1262 } | |
| 1263 | |
| 1264 // Tests that we don't crash trying to run two canaries at once if we receive | |
| 1265 // extra connection status change notifications. See crbug.com/190085. | |
| 1266 TEST_F(SyncSchedulerTest, DoubleCanaryInConfigure) { | |
| 1267 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _)) | |
| 1268 .WillRepeatedly(DoAll( | |
| 1269 Invoke(test_util::SimulateConfigureConnectionFailure), Return(true))); | |
| 1270 StartSyncConfiguration(); | |
| 1271 connection()->SetServerNotReachable(); | |
| 1272 connection()->UpdateConnectionStatus(); | |
| 1273 | |
| 1274 ModelTypeSet model_types(THEMES); | |
| 1275 CallbackCounter ready_counter; | |
| 1276 CallbackCounter retry_counter; | |
| 1277 ConfigurationParams params( | |
| 1278 GetUpdatesCallerInfo::RECONFIGURATION, model_types, | |
| 1279 TypesToRoutingInfo(model_types), | |
| 1280 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)), | |
| 1281 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter))); | |
| 1282 scheduler()->ScheduleConfiguration(params); | |
| 1283 | |
| 1284 scheduler()->OnConnectionStatusChange(); | |
| 1285 scheduler()->OnConnectionStatusChange(); | |
| 1286 | |
| 1287 PumpLoop(); // Run the nudge, that will fail and schedule a quick retry. | |
| 1288 } | |
| 1289 | |
| 1290 TEST_F(SyncSchedulerTest, PollFromCanaryAfterAuthError) { | |
| 1291 SyncShareTimes times; | |
| 1292 TimeDelta poll(TimeDelta::FromMilliseconds(15)); | |
| 1293 scheduler()->OnReceivedLongPollIntervalUpdate(poll); | |
| 1294 | |
| 1295 ::testing::InSequence seq; | |
| 1296 EXPECT_CALL(*syncer(), PollSyncShare(_, _)) | |
| 1297 .WillRepeatedly( | |
| 1298 DoAll(Invoke(test_util::SimulatePollSuccess), | |
| 1299 RecordSyncShareMultiple(×, kMinNumSamples, true))); | |
| 1300 | |
| 1301 connection()->SetServerStatus(HttpResponse::SYNC_AUTH_ERROR); | |
| 1302 StartSyncScheduler(base::Time()); | |
| 1303 | |
| 1304 // Run to wait for polling. | |
| 1305 RunLoop(); | |
| 1306 | |
| 1307 // Normally OnCredentialsUpdated calls TryCanaryJob that doesn't run Poll, | |
| 1308 // but after poll finished with auth error from poll timer it should retry | |
| 1309 // poll once more | |
| 1310 EXPECT_CALL(*syncer(), PollSyncShare(_, _)) | |
| 1311 .WillOnce(DoAll(Invoke(test_util::SimulatePollSuccess), | |
| 1312 RecordSyncShare(×, true))); | |
| 1313 scheduler()->OnCredentialsUpdated(); | |
| 1314 connection()->SetServerStatus(HttpResponse::SERVER_CONNECTION_OK); | |
| 1315 RunLoop(); | |
| 1316 StopSyncScheduler(); | |
| 1317 } | |
| 1318 | |
| 1319 TEST_F(SyncSchedulerTest, SuccessfulRetry) { | |
| 1320 StartSyncScheduler(base::Time()); | |
| 1321 | |
| 1322 SyncShareTimes times; | |
| 1323 base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10); | |
| 1324 scheduler()->OnReceivedGuRetryDelay(delay); | |
| 1325 EXPECT_EQ(delay, GetRetryTimerDelay()); | |
| 1326 | |
| 1327 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 1328 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), | |
| 1329 RecordSyncShare(×, true))); | |
| 1330 | |
| 1331 // Run to wait for retrying. | |
| 1332 RunLoop(); | |
| 1333 | |
| 1334 StopSyncScheduler(); | |
| 1335 } | |
| 1336 | |
| 1337 TEST_F(SyncSchedulerTest, FailedRetry) { | |
| 1338 SyncShareTimes times; | |
| 1339 | |
| 1340 UseMockDelayProvider(); | |
| 1341 EXPECT_CALL(*delay(), GetDelay(_)) | |
| 1342 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(10))); | |
| 1343 | |
| 1344 StartSyncScheduler(base::Time()); | |
| 1345 | |
| 1346 base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10); | |
| 1347 scheduler()->OnReceivedGuRetryDelay(delay); | |
| 1348 | |
| 1349 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 1350 .WillOnce(DoAll(Invoke(test_util::SimulateDownloadUpdatesFailed), | |
| 1351 RecordSyncShare(×, false))); | |
| 1352 | |
| 1353 // Run to wait for retrying. | |
| 1354 RunLoop(); | |
| 1355 | |
| 1356 EXPECT_TRUE(scheduler()->IsBackingOff()); | |
| 1357 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 1358 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), | |
| 1359 RecordSyncShare(×, true))); | |
| 1360 | |
| 1361 // Run to wait for second retrying. | |
| 1362 RunLoop(); | |
| 1363 | |
| 1364 StopSyncScheduler(); | |
| 1365 } | |
| 1366 | |
| 1367 ACTION_P2(VerifyRetryTimerDelay, scheduler_test, expected_delay) { | |
| 1368 EXPECT_EQ(expected_delay, scheduler_test->GetRetryTimerDelay()); | |
| 1369 } | |
| 1370 | |
| 1371 TEST_F(SyncSchedulerTest, ReceiveNewRetryDelay) { | |
| 1372 StartSyncScheduler(base::Time()); | |
| 1373 | |
| 1374 SyncShareTimes times; | |
| 1375 base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(100); | |
| 1376 base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(200); | |
| 1377 | |
| 1378 scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE); | |
| 1379 scheduler()->OnReceivedGuRetryDelay(delay1); | |
| 1380 EXPECT_EQ(delay1, GetRetryTimerDelay()); | |
| 1381 | |
| 1382 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 1383 .WillOnce( | |
| 1384 DoAll(WithoutArgs(VerifyRetryTimerDelay(this, delay1)), | |
| 1385 WithArg<2>(test_util::SimulateGuRetryDelayCommand(delay2)), | |
| 1386 RecordSyncShare(×, true))); | |
| 1387 | |
| 1388 // Run nudge GU. | |
| 1389 RunLoop(); | |
| 1390 EXPECT_EQ(delay2, GetRetryTimerDelay()); | |
| 1391 | |
| 1392 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _)) | |
| 1393 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), | |
| 1394 RecordSyncShare(×, true))); | |
| 1395 | |
| 1396 // Run to wait for retrying. | |
| 1397 RunLoop(); | |
| 1398 | |
| 1399 StopSyncScheduler(); | |
| 1400 } | |
| 1401 | |
| 1402 TEST_F(SyncSchedulerTest, ScheduleClearServerData_Succeeds) { | |
| 1403 StartSyncConfiguration(); | |
| 1404 scheduler()->Start(SyncScheduler::CLEAR_SERVER_DATA_MODE, base::Time()); | |
| 1405 CallbackCounter success_counter; | |
| 1406 ClearParams params(base::Bind(&CallbackCounter::Callback, | |
| 1407 base::Unretained(&success_counter))); | |
| 1408 scheduler()->ScheduleClearServerData(params); | |
| 1409 PumpLoop(); | |
| 1410 ASSERT_EQ(1, success_counter.times_called()); | |
| 1411 } | |
| 1412 | |
| 1413 TEST_F(SyncSchedulerTest, ScheduleClearServerData_FailsRetriesSucceeds) { | |
| 1414 UseMockDelayProvider(); | |
| 1415 TimeDelta delta(TimeDelta::FromMilliseconds(20)); | |
| 1416 EXPECT_CALL(*delay(), GetDelay(_)).WillRepeatedly(Return(delta)); | |
| 1417 | |
| 1418 StartSyncConfiguration(); | |
| 1419 scheduler()->Start(SyncScheduler::CLEAR_SERVER_DATA_MODE, base::Time()); | |
| 1420 CallbackCounter success_counter; | |
| 1421 ClearParams params(base::Bind(&CallbackCounter::Callback, | |
| 1422 base::Unretained(&success_counter))); | |
| 1423 | |
| 1424 // Next request will fail. | |
| 1425 connection()->SetServerNotReachable(); | |
| 1426 scheduler()->ScheduleClearServerData(params); | |
| 1427 PumpLoop(); | |
| 1428 ASSERT_EQ(0, success_counter.times_called()); | |
| 1429 ASSERT_TRUE(scheduler()->IsBackingOff()); | |
| 1430 | |
| 1431 // Now succeed. | |
| 1432 connection()->SetServerReachable(); | |
| 1433 PumpLoopFor(2 * delta); | |
| 1434 ASSERT_EQ(1, success_counter.times_called()); | |
| 1435 ASSERT_FALSE(scheduler()->IsBackingOff()); | |
| 1436 } | |
| 1437 | |
| 1438 } // namespace syncer | |
| OLD | NEW |