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.
6 #include "base/callback.h"
7 #include "base/compiler_specific.h"
8 #include "base/memory/weak_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/test/test_timeouts.h"
11 #include "sync/engine/backoff_delay_provider.h"
12 #include "sync/engine/sync_scheduler_impl.h"
13 #include "sync/engine/syncer.h"
14 #include "sync/internal_api/public/base/cancelation_signal.h"
15 #include "sync/internal_api/public/base/model_type_test_util.h"
16 #include "sync/sessions/test_util.h"
17 #include "sync/test/callback_counter.h"
18 #include "sync/test/engine/fake_model_worker.h"
19 #include "sync/test/engine/mock_connection_manager.h"
20 #include "sync/test/engine/mock_nudge_handler.h"
21 #include "sync/test/engine/test_directory_setter_upper.h"
22 #include "sync/test/mock_invalidation.h"
23 #include "sync/util/extensions_activity.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest.h"
27 using base::TimeDelta;
28 using base::TimeTicks;
30 using testing::AtLeast;
32 using testing::Invoke;
34 using testing::Return;
35 using testing::WithArg;
36 using testing::WithArgs;
37 using testing::WithoutArgs;
40 using sessions::SyncSession;
41 using sessions::SyncSessionContext;
42 using sync_pb::GetUpdatesCallerInfo;
44 class MockSyncer : public Syncer {
47 MOCK_METHOD3(NormalSyncShare, bool(ModelTypeSet,
48 const sessions::NudgeTracker&,
49 sessions::SyncSession*));
50 MOCK_METHOD3(ConfigureSyncShare,
52 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource,
54 MOCK_METHOD2(PollSyncShare, bool(ModelTypeSet, sessions::SyncSession*));
57 MockSyncer::MockSyncer()
60 typedef std::vector<TimeTicks> SyncShareTimes;
63 // We use QuitNow() instead of Quit() as the latter may get stalled
64 // indefinitely in the presence of repeated timers with low delays
65 // and a slow test (e.g., ThrottlingDoesThrottle [which has a poll
66 // delay of 5ms] run under TSAN on the trybots).
67 base::MessageLoop::current()->QuitNow();
71 base::MessageLoop::current()->Run();
75 // Do it this way instead of RunAllPending to pump loop exactly once
76 // (necessary in the presence of timers; see comment in
78 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&QuitLoopNow));
82 void PumpLoopFor(base::TimeDelta time) {
83 // Allow the loop to run for the specified amount of time.
84 base::MessageLoop::current()->PostDelayedTask(
85 FROM_HERE, base::Bind(&QuitLoopNow), time);
89 ModelSafeRoutingInfo TypesToRoutingInfo(ModelTypeSet types) {
90 ModelSafeRoutingInfo routes;
91 for (ModelTypeSet::Iterator iter = types.First(); iter.Good(); iter.Inc()) {
92 routes[iter.Get()] = GROUP_PASSIVE;
98 static const size_t kMinNumSamples = 5;
100 // Test harness for the SyncScheduler. Test the delays and backoff timers used
101 // in response to various events.
103 // These tests execute in real time with real timers. We try to keep the
104 // delays short, but there is a limit to how short we can make them. The
105 // timers on some platforms (ie. Windows) have a timer resolution greater than
106 // 1ms. Using 1ms delays may result in test flakiness.
108 // See crbug.com/402212 for more info.
109 class SyncSchedulerTest : public testing::Test {
111 SyncSchedulerTest() : syncer_(NULL), delay_(NULL), weak_ptr_factory_(this) {}
113 class MockDelayProvider : public BackoffDelayProvider {
115 MockDelayProvider() : BackoffDelayProvider(
116 TimeDelta::FromSeconds(kInitialBackoffRetrySeconds),
117 TimeDelta::FromSeconds(kInitialBackoffImmediateRetrySeconds)) {
120 MOCK_METHOD1(GetDelay, TimeDelta(const TimeDelta&));
123 virtual void SetUp() {
125 syncer_ = new testing::StrictMock<MockSyncer>();
127 extensions_activity_ = new ExtensionsActivity();
129 routing_info_[BOOKMARKS] = GROUP_UI;
130 routing_info_[AUTOFILL] = GROUP_DB;
131 routing_info_[THEMES] = GROUP_UI;
132 routing_info_[NIGORI] = GROUP_PASSIVE;
135 workers_.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_UI)));
136 workers_.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_DB)));
137 workers_.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_PASSIVE)));
139 connection_.reset(new MockConnectionManager(directory(),
140 &cancelation_signal_));
141 connection_->SetServerReachable();
143 model_type_registry_.reset(
144 new ModelTypeRegistry(workers_, directory(), &mock_nudge_handler_));
146 context_.reset(new SyncSessionContext(
147 connection_.get(), directory(),
148 extensions_activity_.get(),
149 std::vector<SyncEngineEventListener*>(), NULL,
150 model_type_registry_.get(),
151 true, // enable keystore encryption
152 false, // force enable pre-commit GU avoidance
153 "fake_invalidator_client_id"));
154 context_->SetRoutingInfo(routing_info_);
155 context_->set_notifications_enabled(true);
156 context_->set_account_name("Test");
158 new SyncSchedulerImpl("TestSyncScheduler",
159 BackoffDelayProvider::FromDefaults(),
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 zero() { return TimeDelta::FromSeconds(0); }
170 TimeDelta timeout() {
171 return TestTimeouts::action_timeout();
174 virtual void TearDown() {
178 dir_maker_.TearDown();
181 void AnalyzePollRun(const SyncShareTimes& times, size_t min_num_samples,
182 const TimeTicks& optimal_start, 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);
191 void DoQuitLoopNow() {
195 void StartSyncScheduler(SyncScheduler::Mode mode) {
196 scheduler()->Start(mode);
199 // This stops the scheduler synchronously.
200 void StopSyncScheduler() {
201 base::MessageLoop::current()->PostTask(
203 base::Bind(&SyncSchedulerTest::DoQuitLoopNow,
204 weak_ptr_factory_.GetWeakPtr()));
208 bool RunAndGetBackoff() {
209 ModelTypeSet nudge_types(BOOKMARKS);
210 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
212 scheduler()->ScheduleLocalNudge(zero(), nudge_types, FROM_HERE);
215 return scheduler()->IsBackingOff();
218 void UseMockDelayProvider() {
219 delay_ = new MockDelayProvider();
220 scheduler_->delay_provider_.reset(delay_);
223 SyncSessionContext* context() { return context_.get(); }
225 ModelTypeSet GetThrottledTypes() {
226 return scheduler_->nudge_tracker_.GetThrottledTypes();
229 base::TimeDelta GetRetryTimerDelay() {
230 EXPECT_TRUE(scheduler_->retry_timer_.IsRunning());
231 return scheduler_->retry_timer_.GetCurrentDelay();
234 static scoped_ptr<InvalidationInterface> BuildInvalidation(
236 const std::string& payload) {
237 return MockInvalidation::Build(version, payload)
238 .PassAs<InvalidationInterface>();
242 syncable::Directory* directory() {
243 return dir_maker_.directory();
246 base::MessageLoop loop_;
247 TestDirectorySetterUpper dir_maker_;
248 CancelationSignal cancelation_signal_;
249 scoped_ptr<MockConnectionManager> connection_;
250 scoped_ptr<ModelTypeRegistry> model_type_registry_;
251 scoped_ptr<SyncSessionContext> context_;
252 scoped_ptr<SyncSchedulerImpl> scheduler_;
253 MockNudgeHandler mock_nudge_handler_;
255 MockDelayProvider* delay_;
256 std::vector<scoped_refptr<ModelSafeWorker> > workers_;
257 scoped_refptr<ExtensionsActivity> extensions_activity_;
258 ModelSafeRoutingInfo routing_info_;
259 base::WeakPtrFactory<SyncSchedulerTest> weak_ptr_factory_;
262 void RecordSyncShareImpl(SyncShareTimes* times) {
263 times->push_back(TimeTicks::Now());
266 ACTION_P(RecordSyncShare, times) {
267 RecordSyncShareImpl(times);
268 if (base::MessageLoop::current()->is_running())
273 ACTION_P2(RecordSyncShareMultiple, times, quit_after) {
274 RecordSyncShareImpl(times);
275 EXPECT_LE(times->size(), quit_after);
276 if (times->size() >= quit_after &&
277 base::MessageLoop::current()->is_running()) {
283 ACTION_P(StopScheduler, scheduler) {
287 ACTION(AddFailureAndQuitLoopNow) {
293 ACTION(QuitLoopNowAction) {
298 // Test nudge scheduling.
299 TEST_F(SyncSchedulerTest, Nudge) {
300 SyncShareTimes times;
301 ModelTypeSet model_types(BOOKMARKS);
303 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
304 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
305 RecordSyncShare(×)))
306 .RetiresOnSaturation();
308 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
310 scheduler()->ScheduleLocalNudge(zero(), model_types, FROM_HERE);
313 Mock::VerifyAndClearExpectations(syncer());
315 // Make sure a second, later, nudge is unaffected by first (no coalescing).
316 SyncShareTimes times2;
317 model_types.Remove(BOOKMARKS);
318 model_types.Put(AUTOFILL);
319 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
320 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
321 RecordSyncShare(×2)));
322 scheduler()->ScheduleLocalNudge(zero(), model_types, FROM_HERE);
326 // Make sure a regular config command is scheduled fine in the absence of any
328 TEST_F(SyncSchedulerTest, Config) {
329 SyncShareTimes times;
330 const ModelTypeSet model_types(BOOKMARKS);
332 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
333 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess),
334 RecordSyncShare(×)));
336 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
338 CallbackCounter ready_counter;
339 CallbackCounter retry_counter;
340 ConfigurationParams params(
341 GetUpdatesCallerInfo::RECONFIGURATION,
343 TypesToRoutingInfo(model_types),
344 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
345 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
346 scheduler()->ScheduleConfiguration(params);
348 ASSERT_EQ(1, ready_counter.times_called());
349 ASSERT_EQ(0, retry_counter.times_called());
352 // Simulate a failure and make sure the config request is retried.
353 TEST_F(SyncSchedulerTest, ConfigWithBackingOff) {
354 UseMockDelayProvider();
355 EXPECT_CALL(*delay(), GetDelay(_))
356 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(20)));
357 SyncShareTimes times;
358 const ModelTypeSet model_types(BOOKMARKS);
360 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
362 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
363 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed),
364 RecordSyncShare(×)))
365 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed),
366 RecordSyncShare(×)));
368 CallbackCounter ready_counter;
369 CallbackCounter retry_counter;
370 ConfigurationParams params(
371 GetUpdatesCallerInfo::RECONFIGURATION,
373 TypesToRoutingInfo(model_types),
374 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
375 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
376 scheduler()->ScheduleConfiguration(params);
378 ASSERT_EQ(0, ready_counter.times_called());
379 ASSERT_EQ(1, retry_counter.times_called());
381 // RunLoop() will trigger TryCanaryJob which will retry configuration.
382 // Since retry_task was already called it shouldn't be called again.
384 ASSERT_EQ(0, ready_counter.times_called());
385 ASSERT_EQ(1, retry_counter.times_called());
387 Mock::VerifyAndClearExpectations(syncer());
389 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
390 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess),
391 RecordSyncShare(×)));
394 ASSERT_EQ(1, ready_counter.times_called());
397 // Simuilate SyncSchedulerImpl::Stop being called in the middle of Configure.
398 // This can happen if server returns NOT_MY_BIRTHDAY.
399 TEST_F(SyncSchedulerTest, ConfigWithStop) {
400 UseMockDelayProvider();
401 EXPECT_CALL(*delay(), GetDelay(_))
402 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(20)));
403 SyncShareTimes times;
404 const ModelTypeSet model_types(BOOKMARKS);
406 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
408 // Make ConfigureSyncShare call scheduler->Stop(). It is not supposed to call
409 // retry_task or dereference configuration params.
410 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
411 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed),
412 StopScheduler(scheduler()),
413 RecordSyncShare(×)));
415 CallbackCounter ready_counter;
416 CallbackCounter retry_counter;
417 ConfigurationParams params(
418 GetUpdatesCallerInfo::RECONFIGURATION,
420 TypesToRoutingInfo(model_types),
421 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
422 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
423 scheduler()->ScheduleConfiguration(params);
425 ASSERT_EQ(0, ready_counter.times_called());
426 ASSERT_EQ(0, retry_counter.times_called());
429 // Issue a nudge when the config has failed. Make sure both the config and
430 // nudge are executed.
431 TEST_F(SyncSchedulerTest, NudgeWithConfigWithBackingOff) {
432 const ModelTypeSet model_types(BOOKMARKS);
433 UseMockDelayProvider();
434 EXPECT_CALL(*delay(), GetDelay(_))
435 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(50)));
436 SyncShareTimes times;
438 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
440 // Request a configure and make sure it fails.
441 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
442 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed),
443 RecordSyncShare(×)));
444 CallbackCounter ready_counter;
445 CallbackCounter retry_counter;
446 ConfigurationParams params(
447 GetUpdatesCallerInfo::RECONFIGURATION,
449 TypesToRoutingInfo(model_types),
450 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
451 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
452 scheduler()->ScheduleConfiguration(params);
454 ASSERT_EQ(0, ready_counter.times_called());
455 ASSERT_EQ(1, retry_counter.times_called());
456 Mock::VerifyAndClearExpectations(syncer());
458 // Ask for a nudge while dealing with repeated configure failure.
459 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
460 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed),
461 RecordSyncShare(×)));
462 scheduler()->ScheduleLocalNudge(zero(), model_types, FROM_HERE);
464 // Note that we're not RunLoop()ing for the NUDGE we just scheduled, but
465 // for the first retry attempt from the config job (after
466 // waiting ~+/- 50ms).
467 Mock::VerifyAndClearExpectations(syncer());
468 ASSERT_EQ(0, ready_counter.times_called());
470 // Let the next configure retry succeed.
471 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
472 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess),
473 RecordSyncShare(×)));
476 // Now change the mode so nudge can execute.
477 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
478 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
479 RecordSyncShare(×)));
480 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
484 // Test that nudges are coalesced.
485 TEST_F(SyncSchedulerTest, NudgeCoalescing) {
486 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
488 SyncShareTimes times;
489 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
490 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
491 RecordSyncShare(×)));
492 const ModelTypeSet types1(BOOKMARKS), types2(AUTOFILL), types3(THEMES);
493 TimeDelta delay = zero();
494 TimeTicks optimal_time = TimeTicks::Now() + delay;
495 scheduler()->ScheduleLocalNudge(delay, types1, FROM_HERE);
496 scheduler()->ScheduleLocalNudge(zero(), types2, FROM_HERE);
499 ASSERT_EQ(1U, times.size());
500 EXPECT_GE(times[0], optimal_time);
502 Mock::VerifyAndClearExpectations(syncer());
504 SyncShareTimes times2;
505 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
506 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
507 RecordSyncShare(×2)));
508 scheduler()->ScheduleLocalNudge(zero(), types3, FROM_HERE);
512 // Test that nudges are coalesced.
513 TEST_F(SyncSchedulerTest, NudgeCoalescingWithDifferentTimings) {
514 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
516 SyncShareTimes times;
517 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
518 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
519 RecordSyncShare(×)));
520 ModelTypeSet types1(BOOKMARKS), types2(AUTOFILL), types3;
522 // Create a huge time delay.
523 TimeDelta delay = TimeDelta::FromDays(1);
525 scheduler()->ScheduleLocalNudge(delay, types1, FROM_HERE);
526 scheduler()->ScheduleLocalNudge(zero(), types2, FROM_HERE);
528 TimeTicks min_time = TimeTicks::Now();
529 TimeTicks max_time = TimeTicks::Now() + delay;
532 Mock::VerifyAndClearExpectations(syncer());
534 // Make sure the sync happened at the right time.
535 ASSERT_EQ(1U, times.size());
536 EXPECT_GE(times[0], min_time);
537 EXPECT_LE(times[0], max_time);
540 // Test nudge scheduling.
541 TEST_F(SyncSchedulerTest, NudgeWithStates) {
542 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
544 SyncShareTimes times1;
545 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
546 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
547 RecordSyncShare(×1)))
548 .RetiresOnSaturation();
549 scheduler()->ScheduleInvalidationNudge(
550 zero(), BOOKMARKS, BuildInvalidation(10, "test"), FROM_HERE);
553 Mock::VerifyAndClearExpectations(syncer());
555 // Make sure a second, later, nudge is unaffected by first (no coalescing).
556 SyncShareTimes times2;
557 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
558 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
559 RecordSyncShare(×2)));
560 scheduler()->ScheduleInvalidationNudge(
561 zero(), AUTOFILL, BuildInvalidation(10, "test2"), FROM_HERE);
565 // Test that polling works as expected.
566 TEST_F(SyncSchedulerTest, Polling) {
567 SyncShareTimes times;
568 TimeDelta poll_interval(TimeDelta::FromMilliseconds(30));
569 EXPECT_CALL(*syncer(), PollSyncShare(_,_)).Times(AtLeast(kMinNumSamples))
571 DoAll(Invoke(sessions::test_util::SimulatePollSuccess),
572 RecordSyncShareMultiple(×, kMinNumSamples)));
574 scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval);
576 TimeTicks optimal_start = TimeTicks::Now() + poll_interval;
577 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
579 // Run again to wait for polling.
583 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll_interval);
586 // Test that the short poll interval is used.
587 TEST_F(SyncSchedulerTest, PollNotificationsDisabled) {
588 SyncShareTimes times;
589 TimeDelta poll_interval(TimeDelta::FromMilliseconds(30));
590 EXPECT_CALL(*syncer(), PollSyncShare(_,_)).Times(AtLeast(kMinNumSamples))
592 DoAll(Invoke(sessions::test_util::SimulatePollSuccess),
593 RecordSyncShareMultiple(×, kMinNumSamples)));
595 scheduler()->OnReceivedShortPollIntervalUpdate(poll_interval);
596 scheduler()->SetNotificationsEnabled(false);
598 TimeTicks optimal_start = TimeTicks::Now() + poll_interval;
599 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
601 // Run again to wait for polling.
605 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll_interval);
608 // Test that polling intervals are updated when needed.
609 TEST_F(SyncSchedulerTest, PollIntervalUpdate) {
610 SyncShareTimes times;
611 TimeDelta poll1(TimeDelta::FromMilliseconds(120));
612 TimeDelta poll2(TimeDelta::FromMilliseconds(30));
613 scheduler()->OnReceivedLongPollIntervalUpdate(poll1);
614 EXPECT_CALL(*syncer(), PollSyncShare(_,_)).Times(AtLeast(kMinNumSamples))
617 sessions::test_util::SimulatePollIntervalUpdate(poll2)),
620 DoAll(Invoke(sessions::test_util::SimulatePollSuccess),
622 RecordSyncShareMultiple(×, kMinNumSamples))));
624 TimeTicks optimal_start = TimeTicks::Now() + poll1 + poll2;
625 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
627 // Run again to wait for polling.
631 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll2);
634 // Test that the sessions commit delay is updated when needed.
635 TEST_F(SyncSchedulerTest, SessionsCommitDelay) {
636 SyncShareTimes times;
637 TimeDelta delay1(TimeDelta::FromMilliseconds(120));
638 TimeDelta delay2(TimeDelta::FromMilliseconds(30));
639 scheduler()->OnReceivedSessionsCommitDelay(delay1);
641 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
645 sessions::test_util::SimulateSessionsCommitDelayUpdate(
647 Invoke(sessions::test_util::SimulateNormalSuccess),
648 QuitLoopNowAction()));
650 EXPECT_EQ(delay1, scheduler()->GetSessionsCommitDelay());
651 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
653 EXPECT_EQ(delay1, scheduler()->GetSessionsCommitDelay());
654 const ModelTypeSet model_types(BOOKMARKS);
655 scheduler()->ScheduleLocalNudge(zero(), model_types, FROM_HERE);
658 EXPECT_EQ(delay2, scheduler()->GetSessionsCommitDelay());
662 // Test that no syncing occurs when throttled.
663 TEST_F(SyncSchedulerTest, ThrottlingDoesThrottle) {
664 const ModelTypeSet types(BOOKMARKS);
665 TimeDelta poll(TimeDelta::FromMilliseconds(20));
666 TimeDelta throttle(TimeDelta::FromMinutes(10));
667 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
669 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
671 WithArg<2>(sessions::test_util::SimulateThrottled(throttle)),
673 .WillRepeatedly(AddFailureAndQuitLoopNow());
675 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
677 scheduler()->ScheduleLocalNudge(
678 TimeDelta::FromMicroseconds(1), types, FROM_HERE);
681 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
683 CallbackCounter ready_counter;
684 CallbackCounter retry_counter;
685 ConfigurationParams params(
686 GetUpdatesCallerInfo::RECONFIGURATION,
688 TypesToRoutingInfo(types),
689 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
690 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
691 scheduler()->ScheduleConfiguration(params);
693 ASSERT_EQ(0, ready_counter.times_called());
694 ASSERT_EQ(1, retry_counter.times_called());
698 TEST_F(SyncSchedulerTest, ThrottlingExpiresFromPoll) {
699 SyncShareTimes times;
700 TimeDelta poll(TimeDelta::FromMilliseconds(15));
701 TimeDelta throttle1(TimeDelta::FromMilliseconds(150));
702 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
704 ::testing::InSequence seq;
705 EXPECT_CALL(*syncer(), PollSyncShare(_,_))
707 WithArg<1>(sessions::test_util::SimulateThrottled(throttle1)),
709 .RetiresOnSaturation();
710 EXPECT_CALL(*syncer(), PollSyncShare(_,_))
712 DoAll(Invoke(sessions::test_util::SimulatePollSuccess),
713 RecordSyncShareMultiple(×, kMinNumSamples)));
715 TimeTicks optimal_start = TimeTicks::Now() + poll + throttle1;
716 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
718 // Run again to wait for polling.
722 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll);
725 TEST_F(SyncSchedulerTest, ThrottlingExpiresFromNudge) {
726 SyncShareTimes times;
727 TimeDelta poll(TimeDelta::FromDays(1));
728 TimeDelta throttle1(TimeDelta::FromMilliseconds(150));
729 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
731 ::testing::InSequence seq;
732 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
734 WithArg<2>(sessions::test_util::SimulateThrottled(throttle1)),
736 .RetiresOnSaturation();
737 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
738 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
739 QuitLoopNowAction()));
741 const ModelTypeSet types(BOOKMARKS);
742 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
743 scheduler()->ScheduleLocalNudge(zero(), types, FROM_HERE);
745 PumpLoop(); // To get PerformDelayedNudge called.
746 PumpLoop(); // To get TrySyncSessionJob called
747 EXPECT_TRUE(scheduler()->IsCurrentlyThrottled());
749 EXPECT_FALSE(scheduler()->IsCurrentlyThrottled());
754 TEST_F(SyncSchedulerTest, ThrottlingExpiresFromConfigure) {
755 SyncShareTimes times;
756 TimeDelta poll(TimeDelta::FromDays(1));
757 TimeDelta throttle1(TimeDelta::FromMilliseconds(150));
758 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
760 ::testing::InSequence seq;
761 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
763 WithArg<2>(sessions::test_util::SimulateThrottled(throttle1)),
765 .RetiresOnSaturation();
766 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
767 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess),
768 QuitLoopNowAction()));
770 const ModelTypeSet types(BOOKMARKS);
771 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
773 CallbackCounter ready_counter;
774 CallbackCounter retry_counter;
775 ConfigurationParams params(
776 GetUpdatesCallerInfo::RECONFIGURATION,
778 TypesToRoutingInfo(types),
779 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
780 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
781 scheduler()->ScheduleConfiguration(params);
783 EXPECT_EQ(0, ready_counter.times_called());
784 EXPECT_EQ(1, retry_counter.times_called());
785 EXPECT_TRUE(scheduler()->IsCurrentlyThrottled());
788 EXPECT_FALSE(scheduler()->IsCurrentlyThrottled());
793 TEST_F(SyncSchedulerTest, TypeThrottlingBlocksNudge) {
794 UseMockDelayProvider();
795 EXPECT_CALL(*delay(), GetDelay(_))
796 .WillRepeatedly(Return(zero()));
798 TimeDelta poll(TimeDelta::FromDays(1));
799 TimeDelta throttle1(TimeDelta::FromSeconds(60));
800 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
802 const ModelTypeSet types(BOOKMARKS);
804 ::testing::InSequence seq;
805 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
808 sessions::test_util::SimulateTypesThrottled(types, throttle1)),
810 .RetiresOnSaturation();
812 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
813 scheduler()->ScheduleLocalNudge(zero(), types, FROM_HERE);
814 PumpLoop(); // To get PerformDelayedNudge called.
815 PumpLoop(); // To get TrySyncSessionJob called
816 EXPECT_TRUE(GetThrottledTypes().HasAll(types));
818 // This won't cause a sync cycle because the types are throttled.
819 scheduler()->ScheduleLocalNudge(zero(), types, FROM_HERE);
825 TEST_F(SyncSchedulerTest, TypeThrottlingDoesBlockOtherSources) {
826 UseMockDelayProvider();
827 EXPECT_CALL(*delay(), GetDelay(_))
828 .WillRepeatedly(Return(zero()));
830 SyncShareTimes times;
831 TimeDelta poll(TimeDelta::FromDays(1));
832 TimeDelta throttle1(TimeDelta::FromSeconds(60));
833 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
835 const ModelTypeSet throttled_types(BOOKMARKS);
836 const ModelTypeSet unthrottled_types(PREFERENCES);
838 ::testing::InSequence seq;
839 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
842 sessions::test_util::SimulateTypesThrottled(
843 throttled_types, throttle1)),
845 .RetiresOnSaturation();
847 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
848 scheduler()->ScheduleLocalNudge(zero(), throttled_types, FROM_HERE);
849 PumpLoop(); // To get PerformDelayedNudge called.
850 PumpLoop(); // To get TrySyncSessionJob called
851 EXPECT_TRUE(GetThrottledTypes().HasAll(throttled_types));
853 // Ignore invalidations for throttled types.
854 scheduler()->ScheduleInvalidationNudge(
855 zero(), BOOKMARKS, BuildInvalidation(10, "test"), FROM_HERE);
858 // Ignore refresh requests for throttled types.
859 scheduler()->ScheduleLocalRefreshRequest(zero(), throttled_types, FROM_HERE);
862 Mock::VerifyAndClearExpectations(syncer());
864 // Local nudges for non-throttled types will trigger a sync.
865 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
866 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
867 RecordSyncShare(×)));
868 scheduler()->ScheduleLocalNudge(zero(), unthrottled_types, FROM_HERE);
870 Mock::VerifyAndClearExpectations(syncer());
875 // Test nudges / polls don't run in config mode and config tasks do.
876 TEST_F(SyncSchedulerTest, ConfigurationMode) {
877 TimeDelta poll(TimeDelta::FromMilliseconds(15));
878 SyncShareTimes times;
879 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
881 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
883 const ModelTypeSet nudge_types(AUTOFILL);
884 scheduler()->ScheduleLocalNudge(zero(), nudge_types, FROM_HERE);
885 scheduler()->ScheduleLocalNudge(zero(), nudge_types, FROM_HERE);
887 const ModelTypeSet config_types(BOOKMARKS);
889 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
890 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess),
891 RecordSyncShare(×)))
892 .RetiresOnSaturation();
893 CallbackCounter ready_counter;
894 CallbackCounter retry_counter;
895 ConfigurationParams params(
896 GetUpdatesCallerInfo::RECONFIGURATION,
898 TypesToRoutingInfo(config_types),
899 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
900 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
901 scheduler()->ScheduleConfiguration(params);
903 ASSERT_EQ(1, ready_counter.times_called());
904 ASSERT_EQ(0, retry_counter.times_called());
906 Mock::VerifyAndClearExpectations(syncer());
908 // Switch to NORMAL_MODE to ensure NUDGES were properly saved and run.
909 scheduler()->OnReceivedLongPollIntervalUpdate(TimeDelta::FromDays(1));
910 SyncShareTimes times2;
911 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
912 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
913 RecordSyncShare(×2)));
915 // TODO(tim): Figure out how to remove this dangerous need to reset
916 // routing info between mode switches.
917 context()->SetRoutingInfo(routing_info());
918 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
921 Mock::VerifyAndClearExpectations(syncer());
924 class BackoffTriggersSyncSchedulerTest : public SyncSchedulerTest {
925 virtual void SetUp() {
926 SyncSchedulerTest::SetUp();
927 UseMockDelayProvider();
928 EXPECT_CALL(*delay(), GetDelay(_))
929 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(10)));
932 virtual void TearDown() {
934 SyncSchedulerTest::TearDown();
938 // Have the sycner fail during commit. Expect that the scheduler enters
940 TEST_F(BackoffTriggersSyncSchedulerTest, FailCommitOnce) {
941 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
942 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
943 QuitLoopNowAction()));
944 EXPECT_TRUE(RunAndGetBackoff());
947 // Have the syncer fail during download updates and succeed on the first
948 // retry. Expect that this clears the backoff state.
949 TEST_F(BackoffTriggersSyncSchedulerTest, FailDownloadOnceThenSucceed) {
950 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
952 Invoke(sessions::test_util::SimulateDownloadUpdatesFailed),
954 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
955 QuitLoopNowAction()));
956 EXPECT_FALSE(RunAndGetBackoff());
959 // Have the syncer fail during commit and succeed on the first retry. Expect
960 // that this clears the backoff state.
961 TEST_F(BackoffTriggersSyncSchedulerTest, FailCommitOnceThenSucceed) {
962 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
964 Invoke(sessions::test_util::SimulateCommitFailed),
966 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
967 QuitLoopNowAction()));
968 EXPECT_FALSE(RunAndGetBackoff());
971 // Have the syncer fail to download updates and fail again on the retry.
972 // Expect this will leave the scheduler in backoff.
973 TEST_F(BackoffTriggersSyncSchedulerTest, FailDownloadTwice) {
974 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
976 Invoke(sessions::test_util::SimulateDownloadUpdatesFailed),
978 .WillRepeatedly(DoAll(
979 Invoke(sessions::test_util::SimulateDownloadUpdatesFailed),
980 QuitLoopNowAction()));
981 EXPECT_TRUE(RunAndGetBackoff());
984 // Have the syncer fail to get the encryption key yet succeed in downloading
985 // updates. Expect this will leave the scheduler in backoff.
986 TEST_F(BackoffTriggersSyncSchedulerTest, FailGetEncryptionKey) {
987 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
989 Invoke(sessions::test_util::SimulateGetEncryptionKeyFailed),
991 .WillRepeatedly(DoAll(
992 Invoke(sessions::test_util::SimulateGetEncryptionKeyFailed),
993 QuitLoopNowAction()));
994 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
996 ModelTypeSet types(BOOKMARKS);
997 CallbackCounter ready_counter;
998 CallbackCounter retry_counter;
999 ConfigurationParams params(
1000 GetUpdatesCallerInfo::RECONFIGURATION,
1002 TypesToRoutingInfo(types),
1003 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
1004 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
1005 scheduler()->ScheduleConfiguration(params);
1008 EXPECT_TRUE(scheduler()->IsBackingOff());
1011 // Test that no polls or extraneous nudges occur when in backoff.
1012 TEST_F(SyncSchedulerTest, BackoffDropsJobs) {
1013 SyncShareTimes times;
1014 TimeDelta poll(TimeDelta::FromMilliseconds(10));
1015 const ModelTypeSet types(BOOKMARKS);
1016 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
1017 UseMockDelayProvider();
1019 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
1020 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
1021 RecordSyncShareMultiple(×, 1U)));
1022 EXPECT_CALL(*delay(), GetDelay(_)).
1023 WillRepeatedly(Return(TimeDelta::FromDays(1)));
1025 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1027 // This nudge should fail and put us into backoff. Thanks to our mock
1028 // GetDelay() setup above, this will be a long backoff.
1029 scheduler()->ScheduleLocalNudge(zero(), types, FROM_HERE);
1032 // From this point forward, no SyncShare functions should be invoked.
1033 Mock::VerifyAndClearExpectations(syncer());
1035 // Wait a while (10x poll interval) so a few poll jobs will be attempted.
1036 PumpLoopFor(poll * 10);
1038 // Try (and fail) to schedule a nudge.
1039 scheduler()->ScheduleLocalNudge(
1040 base::TimeDelta::FromMilliseconds(10),
1044 Mock::VerifyAndClearExpectations(syncer());
1045 Mock::VerifyAndClearExpectations(delay());
1047 EXPECT_CALL(*delay(), GetDelay(_)).Times(0);
1049 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
1051 CallbackCounter ready_counter;
1052 CallbackCounter retry_counter;
1053 ConfigurationParams params(
1054 GetUpdatesCallerInfo::RECONFIGURATION,
1056 TypesToRoutingInfo(types),
1057 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
1058 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
1059 scheduler()->ScheduleConfiguration(params);
1061 ASSERT_EQ(0, ready_counter.times_called());
1062 ASSERT_EQ(1, retry_counter.times_called());
1066 // Test that backoff is shaping traffic properly with consecutive errors.
1067 TEST_F(SyncSchedulerTest, BackoffElevation) {
1068 SyncShareTimes times;
1069 UseMockDelayProvider();
1071 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_)).Times(kMinNumSamples)
1072 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
1073 RecordSyncShareMultiple(×, kMinNumSamples)));
1075 const TimeDelta first = TimeDelta::FromSeconds(kInitialBackoffRetrySeconds);
1076 const TimeDelta second = TimeDelta::FromMilliseconds(20);
1077 const TimeDelta third = TimeDelta::FromMilliseconds(30);
1078 const TimeDelta fourth = TimeDelta::FromMilliseconds(40);
1079 const TimeDelta fifth = TimeDelta::FromMilliseconds(50);
1080 const TimeDelta sixth = TimeDelta::FromDays(1);
1082 EXPECT_CALL(*delay(), GetDelay(first)).WillOnce(Return(second))
1083 .RetiresOnSaturation();
1084 EXPECT_CALL(*delay(), GetDelay(second)).WillOnce(Return(third))
1085 .RetiresOnSaturation();
1086 EXPECT_CALL(*delay(), GetDelay(third)).WillOnce(Return(fourth))
1087 .RetiresOnSaturation();
1088 EXPECT_CALL(*delay(), GetDelay(fourth)).WillOnce(Return(fifth))
1089 .RetiresOnSaturation();
1090 EXPECT_CALL(*delay(), GetDelay(fifth)).WillOnce(Return(sixth));
1092 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1094 // Run again with a nudge.
1095 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS), FROM_HERE);
1098 ASSERT_EQ(kMinNumSamples, times.size());
1099 EXPECT_GE(times[1] - times[0], second);
1100 EXPECT_GE(times[2] - times[1], third);
1101 EXPECT_GE(times[3] - times[2], fourth);
1102 EXPECT_GE(times[4] - times[3], fifth);
1105 // Test that things go back to normal once a retry makes forward progress.
1106 TEST_F(SyncSchedulerTest, BackoffRelief) {
1107 SyncShareTimes times;
1108 const TimeDelta poll(TimeDelta::FromMilliseconds(10));
1109 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
1110 UseMockDelayProvider();
1112 const TimeDelta backoff = TimeDelta::FromMilliseconds(10);
1113 EXPECT_CALL(*delay(), GetDelay(_)).WillOnce(Return(backoff));
1115 // Optimal start for the post-backoff poll party.
1116 TimeTicks optimal_start = TimeTicks::Now();
1117 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1119 // Kick off the test with a failed nudge.
1120 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
1121 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
1122 RecordSyncShare(×)));
1123 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS), FROM_HERE);
1125 Mock::VerifyAndClearExpectations(syncer());
1126 TimeTicks optimal_job_time = optimal_start;
1127 ASSERT_EQ(1U, times.size());
1128 EXPECT_GE(times[0], optimal_job_time);
1130 // The retry succeeds.
1131 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
1133 Invoke(sessions::test_util::SimulateNormalSuccess),
1134 RecordSyncShare(×)));
1136 Mock::VerifyAndClearExpectations(syncer());
1137 optimal_job_time = optimal_job_time + backoff;
1138 ASSERT_EQ(2U, times.size());
1139 EXPECT_GE(times[1], optimal_job_time);
1141 // Now let the Poll timer do its thing.
1142 EXPECT_CALL(*syncer(), PollSyncShare(_,_))
1143 .WillRepeatedly(DoAll(
1144 Invoke(sessions::test_util::SimulatePollSuccess),
1145 RecordSyncShareMultiple(×, kMinNumSamples)));
1147 Mock::VerifyAndClearExpectations(syncer());
1148 ASSERT_EQ(kMinNumSamples, times.size());
1149 for (size_t i = 2; i < times.size(); i++) {
1150 optimal_job_time = optimal_job_time + poll;
1151 SCOPED_TRACE(testing::Message() << "SyncShare # (" << i << ")");
1152 EXPECT_GE(times[i], optimal_job_time);
1155 StopSyncScheduler();
1158 // Test that poll failures are ignored. They should have no effect on
1159 // subsequent poll attempts, nor should they trigger a backoff/retry.
1160 TEST_F(SyncSchedulerTest, TransientPollFailure) {
1161 SyncShareTimes times;
1162 const TimeDelta poll_interval(TimeDelta::FromMilliseconds(10));
1163 scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval);
1164 UseMockDelayProvider(); // Will cause test failure if backoff is initiated.
1166 EXPECT_CALL(*syncer(), PollSyncShare(_,_))
1167 .WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollFailed),
1168 RecordSyncShare(×)))
1169 .WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollSuccess),
1170 RecordSyncShare(×)));
1172 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1174 // Run the unsucessful poll. The failed poll should not trigger backoff.
1176 EXPECT_FALSE(scheduler()->IsBackingOff());
1178 // Run the successful poll.
1180 EXPECT_FALSE(scheduler()->IsBackingOff());
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(DoAll(Invoke(sessions::test_util::SimulateConnectionFailure),
1191 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
1193 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1195 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS), FROM_HERE);
1196 // Should save the nudge for until after the server is reachable.
1197 base::MessageLoop::current()->RunUntilIdle();
1199 scheduler()->OnConnectionStatusChange();
1200 connection()->SetServerReachable();
1201 connection()->UpdateConnectionStatus();
1202 base::MessageLoop::current()->RunUntilIdle();
1205 TEST_F(SyncSchedulerTest, ServerConnectionChangeDuringBackoff) {
1206 UseMockDelayProvider();
1207 EXPECT_CALL(*delay(), GetDelay(_))
1208 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(0)));
1210 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1211 connection()->SetServerNotReachable();
1212 connection()->UpdateConnectionStatus();
1214 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
1215 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConnectionFailure),
1217 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
1220 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS), FROM_HERE);
1221 PumpLoop(); // To get PerformDelayedNudge called.
1222 PumpLoop(); // Run the nudge, that will fail and schedule a quick retry.
1223 ASSERT_TRUE(scheduler()->IsBackingOff());
1225 // Before we run the scheduled canary, trigger a server connection change.
1226 scheduler()->OnConnectionStatusChange();
1227 connection()->SetServerReachable();
1228 connection()->UpdateConnectionStatus();
1229 base::MessageLoop::current()->RunUntilIdle();
1232 // This was supposed to test the scenario where we receive a nudge while a
1233 // connection change canary is scheduled, but has not run yet. Since we've made
1234 // the connection change canary synchronous, this is no longer possible.
1235 TEST_F(SyncSchedulerTest, ConnectionChangeCanaryPreemptedByNudge) {
1236 UseMockDelayProvider();
1237 EXPECT_CALL(*delay(), GetDelay(_))
1238 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(0)));
1240 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1241 connection()->SetServerNotReachable();
1242 connection()->UpdateConnectionStatus();
1244 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
1245 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConnectionFailure),
1247 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
1249 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
1250 QuitLoopNowAction()));
1252 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS), FROM_HERE);
1254 PumpLoop(); // To get PerformDelayedNudge called.
1255 PumpLoop(); // Run the nudge, that will fail and schedule a quick retry.
1256 ASSERT_TRUE(scheduler()->IsBackingOff());
1258 // Before we run the scheduled canary, trigger a server connection change.
1259 scheduler()->OnConnectionStatusChange();
1261 connection()->SetServerReachable();
1262 connection()->UpdateConnectionStatus();
1263 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS), FROM_HERE);
1264 base::MessageLoop::current()->RunUntilIdle();
1267 // Tests that we don't crash trying to run two canaries at once if we receive
1268 // extra connection status change notifications. See crbug.com/190085.
1269 TEST_F(SyncSchedulerTest, DoubleCanaryInConfigure) {
1270 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
1271 .WillRepeatedly(DoAll(
1272 Invoke(sessions::test_util::SimulateConfigureConnectionFailure),
1274 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
1275 connection()->SetServerNotReachable();
1276 connection()->UpdateConnectionStatus();
1278 ModelTypeSet model_types(BOOKMARKS);
1279 CallbackCounter ready_counter;
1280 CallbackCounter retry_counter;
1281 ConfigurationParams params(
1282 GetUpdatesCallerInfo::RECONFIGURATION,
1284 TypesToRoutingInfo(model_types),
1285 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
1286 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
1287 scheduler()->ScheduleConfiguration(params);
1289 scheduler()->OnConnectionStatusChange();
1290 scheduler()->OnConnectionStatusChange();
1292 PumpLoop(); // Run the nudge, that will fail and schedule a quick retry.
1295 TEST_F(SyncSchedulerTest, PollFromCanaryAfterAuthError) {
1296 SyncShareTimes times;
1297 TimeDelta poll(TimeDelta::FromMilliseconds(15));
1298 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
1300 ::testing::InSequence seq;
1301 EXPECT_CALL(*syncer(), PollSyncShare(_,_))
1303 DoAll(Invoke(sessions::test_util::SimulatePollSuccess),
1304 RecordSyncShareMultiple(×, kMinNumSamples)));
1306 connection()->SetServerStatus(HttpResponse::SYNC_AUTH_ERROR);
1307 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1309 // Run to wait for polling.
1312 // Normally OnCredentialsUpdated calls TryCanaryJob that doesn't run Poll,
1313 // but after poll finished with auth error from poll timer it should retry
1315 EXPECT_CALL(*syncer(), PollSyncShare(_,_))
1316 .WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollSuccess),
1317 RecordSyncShare(×)));
1318 scheduler()->OnCredentialsUpdated();
1319 connection()->SetServerStatus(HttpResponse::SERVER_CONNECTION_OK);
1321 StopSyncScheduler();
1324 TEST_F(SyncSchedulerTest, SuccessfulRetry) {
1325 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1327 SyncShareTimes times;
1328 base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10);
1329 scheduler()->OnReceivedGuRetryDelay(delay);
1330 EXPECT_EQ(delay, GetRetryTimerDelay());
1332 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
1334 DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
1335 RecordSyncShare(×)));
1337 // Run to wait for retrying.
1340 StopSyncScheduler();
1343 TEST_F(SyncSchedulerTest, FailedRetry) {
1344 UseMockDelayProvider();
1345 EXPECT_CALL(*delay(), GetDelay(_))
1346 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(10)));
1348 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1350 base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10);
1351 scheduler()->OnReceivedGuRetryDelay(delay);
1353 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
1355 DoAll(Invoke(sessions::test_util::SimulateDownloadUpdatesFailed),
1356 QuitLoopNowAction()));
1358 // Run to wait for retrying.
1361 EXPECT_TRUE(scheduler()->IsBackingOff());
1362 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
1364 DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
1365 QuitLoopNowAction()));
1367 // Run to wait for second retrying.
1370 StopSyncScheduler();
1373 ACTION_P2(VerifyRetryTimerDelay, scheduler_test, expected_delay) {
1374 EXPECT_EQ(expected_delay, scheduler_test->GetRetryTimerDelay());
1377 TEST_F(SyncSchedulerTest, ReceiveNewRetryDelay) {
1378 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1380 SyncShareTimes times;
1381 base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(100);
1382 base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(200);
1384 scheduler()->ScheduleLocalRefreshRequest(zero(), ModelTypeSet(BOOKMARKS),
1386 scheduler()->OnReceivedGuRetryDelay(delay1);
1387 EXPECT_EQ(delay1, GetRetryTimerDelay());
1389 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
1391 WithoutArgs(VerifyRetryTimerDelay(this, delay1)),
1392 WithArg<2>(sessions::test_util::SimulateGuRetryDelayCommand(delay2)),
1393 RecordSyncShare(×)));
1397 EXPECT_EQ(delay2, GetRetryTimerDelay());
1399 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
1400 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
1401 RecordSyncShare(×)));
1403 // Run to wait for retrying.
1406 StopSyncScheduler();
1409 } // namespace syncer