Update .DEPS.git
[chromium-blink-merge.git] / sync / engine / sync_scheduler_unittest.cc
blob7b0a0d35c03720d0f8723e9b9b18354c21f54b1f
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.
5 #include "base/bind.h"
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/notifier/invalidation_util.h"
17 #include "sync/notifier/object_id_invalidation_map.h"
18 #include "sync/sessions/test_util.h"
19 #include "sync/test/callback_counter.h"
20 #include "sync/test/engine/fake_model_worker.h"
21 #include "sync/test/engine/mock_connection_manager.h"
22 #include "sync/test/engine/test_directory_setter_upper.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;
29 using testing::_;
30 using testing::AtLeast;
31 using testing::DoAll;
32 using testing::Invoke;
33 using testing::Mock;
34 using testing::Return;
35 using testing::WithArg;
36 using testing::WithArgs;
37 using testing::WithoutArgs;
39 namespace syncer {
40 using sessions::SyncSession;
41 using sessions::SyncSessionContext;
42 using sync_pb::GetUpdatesCallerInfo;
44 class MockSyncer : public Syncer {
45 public:
46 MockSyncer();
47 MOCK_METHOD3(NormalSyncShare, bool(ModelTypeSet,
48 const sessions::NudgeTracker&,
49 sessions::SyncSession*));
50 MOCK_METHOD3(ConfigureSyncShare,
51 bool(ModelTypeSet,
52 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource,
53 SyncSession*));
54 MOCK_METHOD2(PollSyncShare, bool(ModelTypeSet, sessions::SyncSession*));
55 MOCK_METHOD2(RetrySyncShare, bool(ModelTypeSet, sessions::SyncSession*));
58 MockSyncer::MockSyncer()
59 : Syncer(NULL) {}
61 typedef std::vector<TimeTicks> SyncShareTimes;
63 void QuitLoopNow() {
64 // We use QuitNow() instead of Quit() as the latter may get stalled
65 // indefinitely in the presence of repeated timers with low delays
66 // and a slow test (e.g., ThrottlingDoesThrottle [which has a poll
67 // delay of 5ms] run under TSAN on the trybots).
68 base::MessageLoop::current()->QuitNow();
71 void RunLoop() {
72 base::MessageLoop::current()->Run();
75 void PumpLoop() {
76 // Do it this way instead of RunAllPending to pump loop exactly once
77 // (necessary in the presence of timers; see comment in
78 // QuitLoopNow).
79 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&QuitLoopNow));
80 RunLoop();
83 void PumpLoopFor(base::TimeDelta time) {
84 // Allow the loop to run for the specified amount of time.
85 base::MessageLoop::current()->PostDelayedTask(
86 FROM_HERE, base::Bind(&QuitLoopNow), time);
87 RunLoop();
90 ModelSafeRoutingInfo TypesToRoutingInfo(ModelTypeSet types) {
91 ModelSafeRoutingInfo routes;
92 for (ModelTypeSet::Iterator iter = types.First(); iter.Good(); iter.Inc()) {
93 routes[iter.Get()] = GROUP_PASSIVE;
95 return routes;
98 // Convenient to use in tests wishing to analyze SyncShare calls over time.
99 static const size_t kMinNumSamples = 5;
100 class SyncSchedulerTest : public testing::Test {
101 public:
102 SyncSchedulerTest() : syncer_(NULL), delay_(NULL), weak_ptr_factory_(this) {}
104 class MockDelayProvider : public BackoffDelayProvider {
105 public:
106 MockDelayProvider() : BackoffDelayProvider(
107 TimeDelta::FromSeconds(kInitialBackoffRetrySeconds),
108 TimeDelta::FromSeconds(kInitialBackoffImmediateRetrySeconds)) {
111 MOCK_METHOD1(GetDelay, TimeDelta(const TimeDelta&));
114 virtual void SetUp() {
115 dir_maker_.SetUp();
116 syncer_ = new testing::StrictMock<MockSyncer>();
117 delay_ = NULL;
118 extensions_activity_ = new ExtensionsActivity();
120 routing_info_[BOOKMARKS] = GROUP_UI;
121 routing_info_[AUTOFILL] = GROUP_DB;
122 routing_info_[THEMES] = GROUP_UI;
123 routing_info_[NIGORI] = GROUP_PASSIVE;
125 workers_.clear();
126 workers_.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_UI)));
127 workers_.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_DB)));
128 workers_.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_PASSIVE)));
130 connection_.reset(new MockConnectionManager(directory(),
131 &cancelation_signal_));
132 connection_->SetServerReachable();
134 model_type_registry_.reset(new ModelTypeRegistry(workers_, directory()));
136 context_.reset(new SyncSessionContext(
137 connection_.get(), directory(),
138 extensions_activity_.get(),
139 std::vector<SyncEngineEventListener*>(), NULL, NULL,
140 model_type_registry_.get(),
141 true, // enable keystore encryption
142 false, // force enable pre-commit GU avoidance
143 "fake_invalidator_client_id"));
144 context_->SetRoutingInfo(routing_info_);
145 context_->set_notifications_enabled(true);
146 context_->set_account_name("Test");
147 scheduler_.reset(
148 new SyncSchedulerImpl("TestSyncScheduler",
149 BackoffDelayProvider::FromDefaults(),
150 context(),
151 syncer_));
154 SyncSchedulerImpl* scheduler() { return scheduler_.get(); }
155 const ModelSafeRoutingInfo& routing_info() { return routing_info_; }
156 MockSyncer* syncer() { return syncer_; }
157 MockDelayProvider* delay() { return delay_; }
158 MockConnectionManager* connection() { return connection_.get(); }
159 TimeDelta zero() { return TimeDelta::FromSeconds(0); }
160 TimeDelta timeout() {
161 return TestTimeouts::action_timeout();
164 virtual void TearDown() {
165 PumpLoop();
166 scheduler_.reset();
167 PumpLoop();
168 dir_maker_.TearDown();
171 void AnalyzePollRun(const SyncShareTimes& times, size_t min_num_samples,
172 const TimeTicks& optimal_start, const TimeDelta& poll_interval) {
173 EXPECT_GE(times.size(), min_num_samples);
174 for (size_t i = 0; i < times.size(); i++) {
175 SCOPED_TRACE(testing::Message() << "SyncShare # (" << i << ")");
176 TimeTicks optimal_next_sync = optimal_start + poll_interval * i;
177 EXPECT_GE(times[i], optimal_next_sync);
181 void DoQuitLoopNow() {
182 QuitLoopNow();
185 void StartSyncScheduler(SyncScheduler::Mode mode) {
186 scheduler()->Start(mode);
189 // This stops the scheduler synchronously.
190 void StopSyncScheduler() {
191 base::MessageLoop::current()->PostTask(
192 FROM_HERE,
193 base::Bind(&SyncSchedulerTest::DoQuitLoopNow,
194 weak_ptr_factory_.GetWeakPtr()));
195 RunLoop();
198 bool RunAndGetBackoff() {
199 ModelTypeSet nudge_types(BOOKMARKS);
200 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
202 scheduler()->ScheduleLocalNudge(zero(), nudge_types, FROM_HERE);
203 RunLoop();
205 return scheduler()->IsBackingOff();
208 void UseMockDelayProvider() {
209 delay_ = new MockDelayProvider();
210 scheduler_->delay_provider_.reset(delay_);
213 SyncSessionContext* context() { return context_.get(); }
215 ModelTypeSet GetThrottledTypes() {
216 return scheduler_->nudge_tracker_.GetThrottledTypes();
219 base::TimeDelta GetRetryTimerDelay() {
220 EXPECT_TRUE(scheduler_->retry_timer_.IsRunning());
221 return scheduler_->retry_timer_.GetCurrentDelay();
224 private:
225 syncable::Directory* directory() {
226 return dir_maker_.directory();
229 base::MessageLoop loop_;
230 TestDirectorySetterUpper dir_maker_;
231 CancelationSignal cancelation_signal_;
232 scoped_ptr<MockConnectionManager> connection_;
233 scoped_ptr<ModelTypeRegistry> model_type_registry_;
234 scoped_ptr<SyncSessionContext> context_;
235 scoped_ptr<SyncSchedulerImpl> scheduler_;
236 MockSyncer* syncer_;
237 MockDelayProvider* delay_;
238 std::vector<scoped_refptr<ModelSafeWorker> > workers_;
239 scoped_refptr<ExtensionsActivity> extensions_activity_;
240 ModelSafeRoutingInfo routing_info_;
241 base::WeakPtrFactory<SyncSchedulerTest> weak_ptr_factory_;
244 void RecordSyncShareImpl(SyncShareTimes* times) {
245 times->push_back(TimeTicks::Now());
248 ACTION_P(RecordSyncShare, times) {
249 RecordSyncShareImpl(times);
250 if (base::MessageLoop::current()->is_running())
251 QuitLoopNow();
252 return true;
255 ACTION_P2(RecordSyncShareMultiple, times, quit_after) {
256 RecordSyncShareImpl(times);
257 EXPECT_LE(times->size(), quit_after);
258 if (times->size() >= quit_after &&
259 base::MessageLoop::current()->is_running()) {
260 QuitLoopNow();
262 return true;
265 ACTION_P(StopScheduler, scheduler) {
266 scheduler->Stop();
269 ACTION(AddFailureAndQuitLoopNow) {
270 ADD_FAILURE();
271 QuitLoopNow();
272 return true;
275 ACTION(QuitLoopNowAction) {
276 QuitLoopNow();
277 return true;
280 // Test nudge scheduling.
281 TEST_F(SyncSchedulerTest, Nudge) {
282 SyncShareTimes times;
283 ModelTypeSet model_types(BOOKMARKS);
285 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
286 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
287 RecordSyncShare(&times)))
288 .RetiresOnSaturation();
290 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
292 scheduler()->ScheduleLocalNudge(zero(), model_types, FROM_HERE);
293 RunLoop();
295 Mock::VerifyAndClearExpectations(syncer());
297 // Make sure a second, later, nudge is unaffected by first (no coalescing).
298 SyncShareTimes times2;
299 model_types.Remove(BOOKMARKS);
300 model_types.Put(AUTOFILL);
301 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
302 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
303 RecordSyncShare(&times2)));
304 scheduler()->ScheduleLocalNudge(zero(), model_types, FROM_HERE);
305 RunLoop();
308 // Make sure a regular config command is scheduled fine in the absence of any
309 // errors.
310 TEST_F(SyncSchedulerTest, Config) {
311 SyncShareTimes times;
312 const ModelTypeSet model_types(BOOKMARKS);
314 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
315 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess),
316 RecordSyncShare(&times)));
318 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
320 CallbackCounter ready_counter;
321 CallbackCounter retry_counter;
322 ConfigurationParams params(
323 GetUpdatesCallerInfo::RECONFIGURATION,
324 model_types,
325 TypesToRoutingInfo(model_types),
326 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
327 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
328 scheduler()->ScheduleConfiguration(params);
329 PumpLoop();
330 ASSERT_EQ(1, ready_counter.times_called());
331 ASSERT_EQ(0, retry_counter.times_called());
334 // Simulate a failure and make sure the config request is retried.
335 TEST_F(SyncSchedulerTest, ConfigWithBackingOff) {
336 UseMockDelayProvider();
337 EXPECT_CALL(*delay(), GetDelay(_))
338 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(1)));
339 SyncShareTimes times;
340 const ModelTypeSet model_types(BOOKMARKS);
342 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
344 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
345 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed),
346 RecordSyncShare(&times)))
347 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed),
348 RecordSyncShare(&times)));
350 CallbackCounter ready_counter;
351 CallbackCounter retry_counter;
352 ConfigurationParams params(
353 GetUpdatesCallerInfo::RECONFIGURATION,
354 model_types,
355 TypesToRoutingInfo(model_types),
356 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
357 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
358 scheduler()->ScheduleConfiguration(params);
359 RunLoop();
360 ASSERT_EQ(0, ready_counter.times_called());
361 ASSERT_EQ(1, retry_counter.times_called());
363 // RunLoop() will trigger TryCanaryJob which will retry configuration.
364 // Since retry_task was already called it shouldn't be called again.
365 RunLoop();
366 ASSERT_EQ(0, ready_counter.times_called());
367 ASSERT_EQ(1, retry_counter.times_called());
369 Mock::VerifyAndClearExpectations(syncer());
371 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
372 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess),
373 RecordSyncShare(&times)));
374 RunLoop();
376 ASSERT_EQ(1, ready_counter.times_called());
379 // Simuilate SyncSchedulerImpl::Stop being called in the middle of Configure.
380 // This can happen if server returns NOT_MY_BIRTHDAY.
381 TEST_F(SyncSchedulerTest, ConfigWithStop) {
382 UseMockDelayProvider();
383 EXPECT_CALL(*delay(), GetDelay(_))
384 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(1)));
385 SyncShareTimes times;
386 const ModelTypeSet model_types(BOOKMARKS);
388 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
390 // Make ConfigureSyncShare call scheduler->Stop(). It is not supposed to call
391 // retry_task or dereference configuration params.
392 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
393 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed),
394 StopScheduler(scheduler()),
395 RecordSyncShare(&times)));
397 CallbackCounter ready_counter;
398 CallbackCounter retry_counter;
399 ConfigurationParams params(
400 GetUpdatesCallerInfo::RECONFIGURATION,
401 model_types,
402 TypesToRoutingInfo(model_types),
403 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
404 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
405 scheduler()->ScheduleConfiguration(params);
406 PumpLoop();
407 ASSERT_EQ(0, ready_counter.times_called());
408 ASSERT_EQ(0, retry_counter.times_called());
411 // Issue a nudge when the config has failed. Make sure both the config and
412 // nudge are executed.
413 TEST_F(SyncSchedulerTest, NudgeWithConfigWithBackingOff) {
414 const ModelTypeSet model_types(BOOKMARKS);
415 UseMockDelayProvider();
416 EXPECT_CALL(*delay(), GetDelay(_))
417 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(50)));
418 SyncShareTimes times;
420 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
422 // Request a configure and make sure it fails.
423 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
424 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed),
425 RecordSyncShare(&times)));
426 CallbackCounter ready_counter;
427 CallbackCounter retry_counter;
428 ConfigurationParams params(
429 GetUpdatesCallerInfo::RECONFIGURATION,
430 model_types,
431 TypesToRoutingInfo(model_types),
432 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
433 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
434 scheduler()->ScheduleConfiguration(params);
435 RunLoop();
436 ASSERT_EQ(0, ready_counter.times_called());
437 ASSERT_EQ(1, retry_counter.times_called());
438 Mock::VerifyAndClearExpectations(syncer());
440 // Ask for a nudge while dealing with repeated configure failure.
441 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
442 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed),
443 RecordSyncShare(&times)));
444 scheduler()->ScheduleLocalNudge(zero(), model_types, FROM_HERE);
445 RunLoop();
446 // Note that we're not RunLoop()ing for the NUDGE we just scheduled, but
447 // for the first retry attempt from the config job (after
448 // waiting ~+/- 50ms).
449 Mock::VerifyAndClearExpectations(syncer());
450 ASSERT_EQ(0, ready_counter.times_called());
452 // Let the next configure retry succeed.
453 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
454 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess),
455 RecordSyncShare(&times)));
456 RunLoop();
458 // Now change the mode so nudge can execute.
459 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
460 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
461 RecordSyncShare(&times)));
462 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
463 PumpLoop();
466 // Test that nudges are coalesced.
467 TEST_F(SyncSchedulerTest, NudgeCoalescing) {
468 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
470 SyncShareTimes times;
471 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
472 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
473 RecordSyncShare(&times)));
474 const ModelTypeSet types1(BOOKMARKS), types2(AUTOFILL), types3(THEMES);
475 TimeDelta delay = zero();
476 TimeTicks optimal_time = TimeTicks::Now() + delay;
477 scheduler()->ScheduleLocalNudge(delay, types1, FROM_HERE);
478 scheduler()->ScheduleLocalNudge(zero(), types2, FROM_HERE);
479 RunLoop();
481 ASSERT_EQ(1U, times.size());
482 EXPECT_GE(times[0], optimal_time);
484 Mock::VerifyAndClearExpectations(syncer());
486 SyncShareTimes times2;
487 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
488 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
489 RecordSyncShare(&times2)));
490 scheduler()->ScheduleLocalNudge(zero(), types3, FROM_HERE);
491 RunLoop();
494 // Test that nudges are coalesced.
495 TEST_F(SyncSchedulerTest, NudgeCoalescingWithDifferentTimings) {
496 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
498 SyncShareTimes times;
499 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
500 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
501 RecordSyncShare(&times)));
502 ModelTypeSet types1(BOOKMARKS), types2(AUTOFILL), types3;
504 // Create a huge time delay.
505 TimeDelta delay = TimeDelta::FromDays(1);
507 scheduler()->ScheduleLocalNudge(delay, types1, FROM_HERE);
508 scheduler()->ScheduleLocalNudge(zero(), types2, FROM_HERE);
510 TimeTicks min_time = TimeTicks::Now();
511 TimeTicks max_time = TimeTicks::Now() + delay;
513 RunLoop();
514 Mock::VerifyAndClearExpectations(syncer());
516 // Make sure the sync happened at the right time.
517 ASSERT_EQ(1U, times.size());
518 EXPECT_GE(times[0], min_time);
519 EXPECT_LE(times[0], max_time);
522 // Test nudge scheduling.
523 TEST_F(SyncSchedulerTest, NudgeWithStates) {
524 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
526 SyncShareTimes times1;
527 ObjectIdInvalidationMap invalidations1 =
528 BuildInvalidationMap(BOOKMARKS, 10, "test");
529 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
530 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
531 RecordSyncShare(&times1)))
532 .RetiresOnSaturation();
533 scheduler()->ScheduleInvalidationNudge(zero(), invalidations1, FROM_HERE);
534 RunLoop();
536 Mock::VerifyAndClearExpectations(syncer());
538 // Make sure a second, later, nudge is unaffected by first (no coalescing).
539 SyncShareTimes times2;
540 ObjectIdInvalidationMap invalidations2 =
541 BuildInvalidationMap(AUTOFILL, 10, "test2");
542 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
543 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
544 RecordSyncShare(&times2)));
545 scheduler()->ScheduleInvalidationNudge(zero(), invalidations2, FROM_HERE);
546 RunLoop();
549 // Test that polling works as expected.
550 TEST_F(SyncSchedulerTest, Polling) {
551 SyncShareTimes times;
552 TimeDelta poll_interval(TimeDelta::FromMilliseconds(30));
553 EXPECT_CALL(*syncer(), PollSyncShare(_,_)).Times(AtLeast(kMinNumSamples))
554 .WillRepeatedly(
555 DoAll(Invoke(sessions::test_util::SimulatePollRetrySuccess),
556 RecordSyncShareMultiple(&times, kMinNumSamples)));
558 scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval);
560 TimeTicks optimal_start = TimeTicks::Now() + poll_interval;
561 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
563 // Run again to wait for polling.
564 RunLoop();
566 StopSyncScheduler();
567 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll_interval);
570 // Test that the short poll interval is used.
571 TEST_F(SyncSchedulerTest, PollNotificationsDisabled) {
572 SyncShareTimes times;
573 TimeDelta poll_interval(TimeDelta::FromMilliseconds(30));
574 EXPECT_CALL(*syncer(), PollSyncShare(_,_)).Times(AtLeast(kMinNumSamples))
575 .WillRepeatedly(
576 DoAll(Invoke(sessions::test_util::SimulatePollRetrySuccess),
577 RecordSyncShareMultiple(&times, kMinNumSamples)));
579 scheduler()->OnReceivedShortPollIntervalUpdate(poll_interval);
580 scheduler()->SetNotificationsEnabled(false);
582 TimeTicks optimal_start = TimeTicks::Now() + poll_interval;
583 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
585 // Run again to wait for polling.
586 RunLoop();
588 StopSyncScheduler();
589 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll_interval);
592 // Test that polling intervals are updated when needed.
593 TEST_F(SyncSchedulerTest, PollIntervalUpdate) {
594 SyncShareTimes times;
595 TimeDelta poll1(TimeDelta::FromMilliseconds(120));
596 TimeDelta poll2(TimeDelta::FromMilliseconds(30));
597 scheduler()->OnReceivedLongPollIntervalUpdate(poll1);
598 EXPECT_CALL(*syncer(), PollSyncShare(_,_)).Times(AtLeast(kMinNumSamples))
599 .WillOnce(DoAll(
600 WithArgs<0,1>(
601 sessions::test_util::SimulatePollIntervalUpdate(poll2)),
602 Return(true)))
603 .WillRepeatedly(
604 DoAll(Invoke(sessions::test_util::SimulatePollRetrySuccess),
605 WithArg<1>(
606 RecordSyncShareMultiple(&times, kMinNumSamples))));
608 TimeTicks optimal_start = TimeTicks::Now() + poll1 + poll2;
609 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
611 // Run again to wait for polling.
612 RunLoop();
614 StopSyncScheduler();
615 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll2);
618 // Test that the sessions commit delay is updated when needed.
619 TEST_F(SyncSchedulerTest, SessionsCommitDelay) {
620 SyncShareTimes times;
621 TimeDelta delay1(TimeDelta::FromMilliseconds(120));
622 TimeDelta delay2(TimeDelta::FromMilliseconds(30));
623 scheduler()->OnReceivedSessionsCommitDelay(delay1);
625 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
626 .WillOnce(
627 DoAll(
628 WithArgs<0,1,2>(
629 sessions::test_util::SimulateSessionsCommitDelayUpdate(
630 delay2)),
631 Invoke(sessions::test_util::SimulateNormalSuccess),
632 QuitLoopNowAction()));
634 EXPECT_EQ(delay1, scheduler()->GetSessionsCommitDelay());
635 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
637 EXPECT_EQ(delay1, scheduler()->GetSessionsCommitDelay());
638 const ModelTypeSet model_types(BOOKMARKS);
639 scheduler()->ScheduleLocalNudge(zero(), model_types, FROM_HERE);
640 RunLoop();
642 EXPECT_EQ(delay2, scheduler()->GetSessionsCommitDelay());
643 StopSyncScheduler();
646 // Test that no syncing occurs when throttled.
647 TEST_F(SyncSchedulerTest, ThrottlingDoesThrottle) {
648 const ModelTypeSet types(BOOKMARKS);
649 TimeDelta poll(TimeDelta::FromMilliseconds(5));
650 TimeDelta throttle(TimeDelta::FromMinutes(10));
651 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
653 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
654 .WillOnce(DoAll(
655 WithArg<2>(sessions::test_util::SimulateThrottled(throttle)),
656 Return(true)))
657 .WillRepeatedly(AddFailureAndQuitLoopNow());
659 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
661 scheduler()->ScheduleLocalNudge(
662 TimeDelta::FromMicroseconds(1), types, FROM_HERE);
663 PumpLoop();
665 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
667 CallbackCounter ready_counter;
668 CallbackCounter retry_counter;
669 ConfigurationParams params(
670 GetUpdatesCallerInfo::RECONFIGURATION,
671 types,
672 TypesToRoutingInfo(types),
673 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
674 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
675 scheduler()->ScheduleConfiguration(params);
676 PumpLoop();
677 ASSERT_EQ(0, ready_counter.times_called());
678 ASSERT_EQ(1, retry_counter.times_called());
682 TEST_F(SyncSchedulerTest, ThrottlingExpiresFromPoll) {
683 SyncShareTimes times;
684 TimeDelta poll(TimeDelta::FromMilliseconds(15));
685 TimeDelta throttle1(TimeDelta::FromMilliseconds(150));
686 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
688 ::testing::InSequence seq;
689 EXPECT_CALL(*syncer(), PollSyncShare(_,_))
690 .WillOnce(DoAll(
691 WithArg<1>(sessions::test_util::SimulateThrottled(throttle1)),
692 Return(true)))
693 .RetiresOnSaturation();
694 EXPECT_CALL(*syncer(), PollSyncShare(_,_))
695 .WillRepeatedly(
696 DoAll(Invoke(sessions::test_util::SimulatePollRetrySuccess),
697 RecordSyncShareMultiple(&times, kMinNumSamples)));
699 TimeTicks optimal_start = TimeTicks::Now() + poll + throttle1;
700 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
702 // Run again to wait for polling.
703 RunLoop();
705 StopSyncScheduler();
706 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll);
709 TEST_F(SyncSchedulerTest, ThrottlingExpiresFromNudge) {
710 SyncShareTimes times;
711 TimeDelta poll(TimeDelta::FromDays(1));
712 TimeDelta throttle1(TimeDelta::FromMilliseconds(150));
713 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
715 ::testing::InSequence seq;
716 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
717 .WillOnce(DoAll(
718 WithArg<2>(sessions::test_util::SimulateThrottled(throttle1)),
719 Return(true)))
720 .RetiresOnSaturation();
721 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
722 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
723 QuitLoopNowAction()));
725 const ModelTypeSet types(BOOKMARKS);
726 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
727 scheduler()->ScheduleLocalNudge(zero(), types, FROM_HERE);
729 PumpLoop(); // To get PerformDelayedNudge called.
730 PumpLoop(); // To get TrySyncSessionJob called
731 EXPECT_TRUE(scheduler()->IsCurrentlyThrottled());
732 RunLoop();
733 EXPECT_FALSE(scheduler()->IsCurrentlyThrottled());
735 StopSyncScheduler();
738 TEST_F(SyncSchedulerTest, ThrottlingExpiresFromConfigure) {
739 SyncShareTimes times;
740 TimeDelta poll(TimeDelta::FromDays(1));
741 TimeDelta throttle1(TimeDelta::FromMilliseconds(150));
742 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
744 ::testing::InSequence seq;
745 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
746 .WillOnce(DoAll(
747 WithArg<2>(sessions::test_util::SimulateThrottled(throttle1)),
748 Return(true)))
749 .RetiresOnSaturation();
750 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
751 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess),
752 QuitLoopNowAction()));
754 const ModelTypeSet types(BOOKMARKS);
755 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
757 CallbackCounter ready_counter;
758 CallbackCounter retry_counter;
759 ConfigurationParams params(
760 GetUpdatesCallerInfo::RECONFIGURATION,
761 types,
762 TypesToRoutingInfo(types),
763 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
764 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
765 scheduler()->ScheduleConfiguration(params);
766 PumpLoop();
767 EXPECT_EQ(0, ready_counter.times_called());
768 EXPECT_EQ(1, retry_counter.times_called());
769 EXPECT_TRUE(scheduler()->IsCurrentlyThrottled());
771 RunLoop();
772 EXPECT_FALSE(scheduler()->IsCurrentlyThrottled());
774 StopSyncScheduler();
777 TEST_F(SyncSchedulerTest, TypeThrottlingBlocksNudge) {
778 UseMockDelayProvider();
779 EXPECT_CALL(*delay(), GetDelay(_))
780 .WillRepeatedly(Return(zero()));
782 TimeDelta poll(TimeDelta::FromDays(1));
783 TimeDelta throttle1(TimeDelta::FromSeconds(60));
784 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
786 const ModelTypeSet types(BOOKMARKS);
788 ::testing::InSequence seq;
789 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
790 .WillOnce(DoAll(
791 WithArg<2>(
792 sessions::test_util::SimulateTypesThrottled(types, throttle1)),
793 Return(true)))
794 .RetiresOnSaturation();
796 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
797 scheduler()->ScheduleLocalNudge(zero(), types, FROM_HERE);
798 PumpLoop(); // To get PerformDelayedNudge called.
799 PumpLoop(); // To get TrySyncSessionJob called
800 EXPECT_TRUE(GetThrottledTypes().HasAll(types));
802 // This won't cause a sync cycle because the types are throttled.
803 scheduler()->ScheduleLocalNudge(zero(), types, FROM_HERE);
804 PumpLoop();
806 StopSyncScheduler();
809 TEST_F(SyncSchedulerTest, TypeThrottlingDoesBlockOtherSources) {
810 UseMockDelayProvider();
811 EXPECT_CALL(*delay(), GetDelay(_))
812 .WillRepeatedly(Return(zero()));
814 SyncShareTimes times;
815 TimeDelta poll(TimeDelta::FromDays(1));
816 TimeDelta throttle1(TimeDelta::FromSeconds(60));
817 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
819 const ModelTypeSet throttled_types(BOOKMARKS);
820 const ModelTypeSet unthrottled_types(PREFERENCES);
822 ::testing::InSequence seq;
823 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
824 .WillOnce(DoAll(
825 WithArg<2>(
826 sessions::test_util::SimulateTypesThrottled(
827 throttled_types, throttle1)),
828 Return(true)))
829 .RetiresOnSaturation();
831 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
832 scheduler()->ScheduleLocalNudge(zero(), throttled_types, FROM_HERE);
833 PumpLoop(); // To get PerformDelayedNudge called.
834 PumpLoop(); // To get TrySyncSessionJob called
835 EXPECT_TRUE(GetThrottledTypes().HasAll(throttled_types));
837 // Ignore invalidations for throttled types.
838 ObjectIdInvalidationMap invalidations =
839 BuildInvalidationMap(BOOKMARKS, 10, "test");
840 scheduler()->ScheduleInvalidationNudge(zero(), invalidations, FROM_HERE);
841 PumpLoop();
843 // Ignore refresh requests for throttled types.
844 scheduler()->ScheduleLocalRefreshRequest(zero(), throttled_types, FROM_HERE);
845 PumpLoop();
847 Mock::VerifyAndClearExpectations(syncer());
849 // Local nudges for non-throttled types will trigger a sync.
850 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
851 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
852 RecordSyncShare(&times)));
853 scheduler()->ScheduleLocalNudge(zero(), unthrottled_types, FROM_HERE);
854 RunLoop();
855 Mock::VerifyAndClearExpectations(syncer());
857 StopSyncScheduler();
860 // Test nudges / polls don't run in config mode and config tasks do.
861 TEST_F(SyncSchedulerTest, ConfigurationMode) {
862 TimeDelta poll(TimeDelta::FromMilliseconds(15));
863 SyncShareTimes times;
864 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
866 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
868 const ModelTypeSet nudge_types(AUTOFILL);
869 scheduler()->ScheduleLocalNudge(zero(), nudge_types, FROM_HERE);
870 scheduler()->ScheduleLocalNudge(zero(), nudge_types, FROM_HERE);
872 const ModelTypeSet config_types(BOOKMARKS);
874 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
875 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess),
876 RecordSyncShare(&times)))
877 .RetiresOnSaturation();
878 CallbackCounter ready_counter;
879 CallbackCounter retry_counter;
880 ConfigurationParams params(
881 GetUpdatesCallerInfo::RECONFIGURATION,
882 config_types,
883 TypesToRoutingInfo(config_types),
884 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
885 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
886 scheduler()->ScheduleConfiguration(params);
887 RunLoop();
888 ASSERT_EQ(1, ready_counter.times_called());
889 ASSERT_EQ(0, retry_counter.times_called());
891 Mock::VerifyAndClearExpectations(syncer());
893 // Switch to NORMAL_MODE to ensure NUDGES were properly saved and run.
894 scheduler()->OnReceivedLongPollIntervalUpdate(TimeDelta::FromDays(1));
895 SyncShareTimes times2;
896 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
897 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
898 RecordSyncShare(&times2)));
900 // TODO(tim): Figure out how to remove this dangerous need to reset
901 // routing info between mode switches.
902 context()->SetRoutingInfo(routing_info());
903 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
905 RunLoop();
906 Mock::VerifyAndClearExpectations(syncer());
909 class BackoffTriggersSyncSchedulerTest : public SyncSchedulerTest {
910 virtual void SetUp() {
911 SyncSchedulerTest::SetUp();
912 UseMockDelayProvider();
913 EXPECT_CALL(*delay(), GetDelay(_))
914 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(1)));
917 virtual void TearDown() {
918 StopSyncScheduler();
919 SyncSchedulerTest::TearDown();
923 // Have the sycner fail during commit. Expect that the scheduler enters
924 // backoff.
925 TEST_F(BackoffTriggersSyncSchedulerTest, FailCommitOnce) {
926 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
927 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
928 QuitLoopNowAction()));
929 EXPECT_TRUE(RunAndGetBackoff());
932 // Have the syncer fail during download updates and succeed on the first
933 // retry. Expect that this clears the backoff state.
934 TEST_F(BackoffTriggersSyncSchedulerTest, FailDownloadOnceThenSucceed) {
935 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
936 .WillOnce(DoAll(
937 Invoke(sessions::test_util::SimulateDownloadUpdatesFailed),
938 Return(true)))
939 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
940 QuitLoopNowAction()));
941 EXPECT_FALSE(RunAndGetBackoff());
944 // Have the syncer fail during commit and succeed on the first retry. Expect
945 // that this clears the backoff state.
946 TEST_F(BackoffTriggersSyncSchedulerTest, FailCommitOnceThenSucceed) {
947 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
948 .WillOnce(DoAll(
949 Invoke(sessions::test_util::SimulateCommitFailed),
950 Return(true)))
951 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
952 QuitLoopNowAction()));
953 EXPECT_FALSE(RunAndGetBackoff());
956 // Have the syncer fail to download updates and fail again on the retry.
957 // Expect this will leave the scheduler in backoff.
958 TEST_F(BackoffTriggersSyncSchedulerTest, FailDownloadTwice) {
959 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
960 .WillOnce(DoAll(
961 Invoke(sessions::test_util::SimulateDownloadUpdatesFailed),
962 Return(true)))
963 .WillRepeatedly(DoAll(
964 Invoke(sessions::test_util::SimulateDownloadUpdatesFailed),
965 QuitLoopNowAction()));
966 EXPECT_TRUE(RunAndGetBackoff());
969 // Have the syncer fail to get the encryption key yet succeed in downloading
970 // updates. Expect this will leave the scheduler in backoff.
971 TEST_F(BackoffTriggersSyncSchedulerTest, FailGetEncryptionKey) {
972 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
973 .WillOnce(DoAll(
974 Invoke(sessions::test_util::SimulateGetEncryptionKeyFailed),
975 Return(true)))
976 .WillRepeatedly(DoAll(
977 Invoke(sessions::test_util::SimulateGetEncryptionKeyFailed),
978 QuitLoopNowAction()));
979 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
981 ModelTypeSet types(BOOKMARKS);
982 CallbackCounter ready_counter;
983 CallbackCounter retry_counter;
984 ConfigurationParams params(
985 GetUpdatesCallerInfo::RECONFIGURATION,
986 types,
987 TypesToRoutingInfo(types),
988 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
989 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
990 scheduler()->ScheduleConfiguration(params);
991 RunLoop();
993 EXPECT_TRUE(scheduler()->IsBackingOff());
996 // Test that no polls or extraneous nudges occur when in backoff.
997 TEST_F(SyncSchedulerTest, BackoffDropsJobs) {
998 SyncShareTimes times;
999 TimeDelta poll(TimeDelta::FromMilliseconds(5));
1000 const ModelTypeSet types(BOOKMARKS);
1001 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
1002 UseMockDelayProvider();
1004 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
1005 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
1006 RecordSyncShareMultiple(&times, 1U)));
1007 EXPECT_CALL(*delay(), GetDelay(_)).
1008 WillRepeatedly(Return(TimeDelta::FromDays(1)));
1010 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1012 // This nudge should fail and put us into backoff. Thanks to our mock
1013 // GetDelay() setup above, this will be a long backoff.
1014 scheduler()->ScheduleLocalNudge(zero(), types, FROM_HERE);
1015 RunLoop();
1017 // From this point forward, no SyncShare functions should be invoked.
1018 Mock::VerifyAndClearExpectations(syncer());
1020 // Wait a while (10x poll interval) so a few poll jobs will be attempted.
1021 PumpLoopFor(poll * 10);
1023 // Try (and fail) to schedule a nudge.
1024 scheduler()->ScheduleLocalNudge(
1025 base::TimeDelta::FromMilliseconds(1),
1026 types,
1027 FROM_HERE);
1029 Mock::VerifyAndClearExpectations(syncer());
1030 Mock::VerifyAndClearExpectations(delay());
1032 EXPECT_CALL(*delay(), GetDelay(_)).Times(0);
1034 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
1036 CallbackCounter ready_counter;
1037 CallbackCounter retry_counter;
1038 ConfigurationParams params(
1039 GetUpdatesCallerInfo::RECONFIGURATION,
1040 types,
1041 TypesToRoutingInfo(types),
1042 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
1043 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
1044 scheduler()->ScheduleConfiguration(params);
1045 PumpLoop();
1046 ASSERT_EQ(0, ready_counter.times_called());
1047 ASSERT_EQ(1, retry_counter.times_called());
1051 // Test that backoff is shaping traffic properly with consecutive errors.
1052 TEST_F(SyncSchedulerTest, BackoffElevation) {
1053 SyncShareTimes times;
1054 UseMockDelayProvider();
1056 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_)).Times(kMinNumSamples)
1057 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
1058 RecordSyncShareMultiple(&times, kMinNumSamples)));
1060 const TimeDelta first = TimeDelta::FromSeconds(kInitialBackoffRetrySeconds);
1061 const TimeDelta second = TimeDelta::FromMilliseconds(2);
1062 const TimeDelta third = TimeDelta::FromMilliseconds(3);
1063 const TimeDelta fourth = TimeDelta::FromMilliseconds(4);
1064 const TimeDelta fifth = TimeDelta::FromMilliseconds(5);
1065 const TimeDelta sixth = TimeDelta::FromDays(1);
1067 EXPECT_CALL(*delay(), GetDelay(first)).WillOnce(Return(second))
1068 .RetiresOnSaturation();
1069 EXPECT_CALL(*delay(), GetDelay(second)).WillOnce(Return(third))
1070 .RetiresOnSaturation();
1071 EXPECT_CALL(*delay(), GetDelay(third)).WillOnce(Return(fourth))
1072 .RetiresOnSaturation();
1073 EXPECT_CALL(*delay(), GetDelay(fourth)).WillOnce(Return(fifth))
1074 .RetiresOnSaturation();
1075 EXPECT_CALL(*delay(), GetDelay(fifth)).WillOnce(Return(sixth));
1077 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1079 // Run again with a nudge.
1080 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS), FROM_HERE);
1081 RunLoop();
1083 ASSERT_EQ(kMinNumSamples, times.size());
1084 EXPECT_GE(times[1] - times[0], second);
1085 EXPECT_GE(times[2] - times[1], third);
1086 EXPECT_GE(times[3] - times[2], fourth);
1087 EXPECT_GE(times[4] - times[3], fifth);
1090 // Test that things go back to normal once a retry makes forward progress.
1091 TEST_F(SyncSchedulerTest, BackoffRelief) {
1092 SyncShareTimes times;
1093 const TimeDelta poll(TimeDelta::FromMilliseconds(10));
1094 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
1095 UseMockDelayProvider();
1097 const TimeDelta backoff = TimeDelta::FromMilliseconds(5);
1098 EXPECT_CALL(*delay(), GetDelay(_)).WillOnce(Return(backoff));
1100 // Optimal start for the post-backoff poll party.
1101 TimeTicks optimal_start = TimeTicks::Now();
1102 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1104 // Kick off the test with a failed nudge.
1105 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
1106 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
1107 RecordSyncShare(&times)));
1108 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS), FROM_HERE);
1109 RunLoop();
1110 Mock::VerifyAndClearExpectations(syncer());
1111 TimeTicks optimal_job_time = optimal_start;
1112 ASSERT_EQ(1U, times.size());
1113 EXPECT_GE(times[0], optimal_job_time);
1115 // The retry succeeds.
1116 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
1117 .WillOnce(DoAll(
1118 Invoke(sessions::test_util::SimulateNormalSuccess),
1119 RecordSyncShare(&times)));
1120 RunLoop();
1121 Mock::VerifyAndClearExpectations(syncer());
1122 optimal_job_time = optimal_job_time + backoff;
1123 ASSERT_EQ(2U, times.size());
1124 EXPECT_GE(times[1], optimal_job_time);
1126 // Now let the Poll timer do its thing.
1127 EXPECT_CALL(*syncer(), PollSyncShare(_,_))
1128 .WillRepeatedly(DoAll(
1129 Invoke(sessions::test_util::SimulatePollRetrySuccess),
1130 RecordSyncShareMultiple(&times, kMinNumSamples)));
1131 RunLoop();
1132 Mock::VerifyAndClearExpectations(syncer());
1133 ASSERT_EQ(kMinNumSamples, times.size());
1134 for (size_t i = 2; i < times.size(); i++) {
1135 optimal_job_time = optimal_job_time + poll;
1136 SCOPED_TRACE(testing::Message() << "SyncShare # (" << i << ")");
1137 EXPECT_GE(times[i], optimal_job_time);
1140 StopSyncScheduler();
1143 // Test that poll failures are ignored. They should have no effect on
1144 // subsequent poll attempts, nor should they trigger a backoff/retry.
1145 TEST_F(SyncSchedulerTest, TransientPollFailure) {
1146 SyncShareTimes times;
1147 const TimeDelta poll_interval(TimeDelta::FromMilliseconds(1));
1148 scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval);
1149 UseMockDelayProvider(); // Will cause test failure if backoff is initiated.
1151 EXPECT_CALL(*syncer(), PollSyncShare(_,_))
1152 .WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollRetryFailed),
1153 RecordSyncShare(&times)))
1154 .WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollRetrySuccess),
1155 RecordSyncShare(&times)));
1157 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1159 // Run the unsucessful poll. The failed poll should not trigger backoff.
1160 RunLoop();
1161 EXPECT_FALSE(scheduler()->IsBackingOff());
1163 // Run the successful poll.
1164 RunLoop();
1165 EXPECT_FALSE(scheduler()->IsBackingOff());
1168 // Test that starting the syncer thread without a valid connection doesn't
1169 // break things when a connection is detected.
1170 TEST_F(SyncSchedulerTest, StartWhenNotConnected) {
1171 connection()->SetServerNotReachable();
1172 connection()->UpdateConnectionStatus();
1173 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
1174 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConnectionFailure),
1175 Return(true)))
1176 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
1177 Return(true)));
1178 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1180 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS), FROM_HERE);
1181 // Should save the nudge for until after the server is reachable.
1182 base::MessageLoop::current()->RunUntilIdle();
1184 scheduler()->OnConnectionStatusChange();
1185 connection()->SetServerReachable();
1186 connection()->UpdateConnectionStatus();
1187 base::MessageLoop::current()->RunUntilIdle();
1190 TEST_F(SyncSchedulerTest, ServerConnectionChangeDuringBackoff) {
1191 UseMockDelayProvider();
1192 EXPECT_CALL(*delay(), GetDelay(_))
1193 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(0)));
1195 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1196 connection()->SetServerNotReachable();
1197 connection()->UpdateConnectionStatus();
1199 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
1200 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConnectionFailure),
1201 Return(true)))
1202 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
1203 Return(true)));
1205 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS), FROM_HERE);
1206 PumpLoop(); // To get PerformDelayedNudge called.
1207 PumpLoop(); // Run the nudge, that will fail and schedule a quick retry.
1208 ASSERT_TRUE(scheduler()->IsBackingOff());
1210 // Before we run the scheduled canary, trigger a server connection change.
1211 scheduler()->OnConnectionStatusChange();
1212 connection()->SetServerReachable();
1213 connection()->UpdateConnectionStatus();
1214 base::MessageLoop::current()->RunUntilIdle();
1217 // This was supposed to test the scenario where we receive a nudge while a
1218 // connection change canary is scheduled, but has not run yet. Since we've made
1219 // the connection change canary synchronous, this is no longer possible.
1220 TEST_F(SyncSchedulerTest, ConnectionChangeCanaryPreemptedByNudge) {
1221 UseMockDelayProvider();
1222 EXPECT_CALL(*delay(), GetDelay(_))
1223 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(0)));
1225 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1226 connection()->SetServerNotReachable();
1227 connection()->UpdateConnectionStatus();
1229 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
1230 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConnectionFailure),
1231 Return(true)))
1232 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
1233 Return(true)))
1234 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
1235 QuitLoopNowAction()));
1237 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS), FROM_HERE);
1239 PumpLoop(); // To get PerformDelayedNudge called.
1240 PumpLoop(); // Run the nudge, that will fail and schedule a quick retry.
1241 ASSERT_TRUE(scheduler()->IsBackingOff());
1243 // Before we run the scheduled canary, trigger a server connection change.
1244 scheduler()->OnConnectionStatusChange();
1245 PumpLoop();
1246 connection()->SetServerReachable();
1247 connection()->UpdateConnectionStatus();
1248 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS), FROM_HERE);
1249 base::MessageLoop::current()->RunUntilIdle();
1252 // Tests that we don't crash trying to run two canaries at once if we receive
1253 // extra connection status change notifications. See crbug.com/190085.
1254 TEST_F(SyncSchedulerTest, DoubleCanaryInConfigure) {
1255 EXPECT_CALL(*syncer(), ConfigureSyncShare(_,_,_))
1256 .WillRepeatedly(DoAll(
1257 Invoke(sessions::test_util::SimulateConfigureConnectionFailure),
1258 Return(true)));
1259 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
1260 connection()->SetServerNotReachable();
1261 connection()->UpdateConnectionStatus();
1263 ModelTypeSet model_types(BOOKMARKS);
1264 CallbackCounter ready_counter;
1265 CallbackCounter retry_counter;
1266 ConfigurationParams params(
1267 GetUpdatesCallerInfo::RECONFIGURATION,
1268 model_types,
1269 TypesToRoutingInfo(model_types),
1270 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
1271 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
1272 scheduler()->ScheduleConfiguration(params);
1274 scheduler()->OnConnectionStatusChange();
1275 scheduler()->OnConnectionStatusChange();
1277 PumpLoop(); // Run the nudge, that will fail and schedule a quick retry.
1280 TEST_F(SyncSchedulerTest, PollFromCanaryAfterAuthError) {
1281 SyncShareTimes times;
1282 TimeDelta poll(TimeDelta::FromMilliseconds(15));
1283 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
1285 ::testing::InSequence seq;
1286 EXPECT_CALL(*syncer(), PollSyncShare(_,_))
1287 .WillRepeatedly(
1288 DoAll(Invoke(sessions::test_util::SimulatePollRetrySuccess),
1289 RecordSyncShareMultiple(&times, kMinNumSamples)));
1291 connection()->SetServerStatus(HttpResponse::SYNC_AUTH_ERROR);
1292 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1294 // Run to wait for polling.
1295 RunLoop();
1297 // Normally OnCredentialsUpdated calls TryCanaryJob that doesn't run Poll,
1298 // but after poll finished with auth error from poll timer it should retry
1299 // poll once more
1300 EXPECT_CALL(*syncer(), PollSyncShare(_,_))
1301 .WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollRetrySuccess),
1302 RecordSyncShare(&times)));
1303 scheduler()->OnCredentialsUpdated();
1304 connection()->SetServerStatus(HttpResponse::SERVER_CONNECTION_OK);
1305 RunLoop();
1306 StopSyncScheduler();
1309 TEST_F(SyncSchedulerTest, SuccessfulRetry) {
1310 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1312 SyncShareTimes times;
1313 base::TimeDelta delay = base::TimeDelta::FromMilliseconds(1);
1314 scheduler()->OnReceivedGuRetryDelay(delay);
1315 EXPECT_EQ(delay, GetRetryTimerDelay());
1317 EXPECT_CALL(*syncer(), RetrySyncShare(_,_))
1318 .WillOnce(
1319 DoAll(Invoke(sessions::test_util::SimulatePollRetrySuccess),
1320 RecordSyncShare(&times)));
1322 // Run to wait for retrying.
1323 RunLoop();
1325 StopSyncScheduler();
1328 TEST_F(SyncSchedulerTest, FailedRetry) {
1329 UseMockDelayProvider();
1330 EXPECT_CALL(*delay(), GetDelay(_))
1331 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(1)));
1333 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1335 base::TimeDelta delay = base::TimeDelta::FromMilliseconds(1);
1336 scheduler()->OnReceivedGuRetryDelay(delay);
1338 EXPECT_CALL(*syncer(), RetrySyncShare(_,_))
1339 .WillOnce(
1340 DoAll(Invoke(sessions::test_util::SimulatePollRetryFailed),
1341 QuitLoopNowAction()));
1343 // Run to wait for retrying.
1344 RunLoop();
1346 EXPECT_TRUE(scheduler()->IsBackingOff());
1347 EXPECT_CALL(*syncer(), RetrySyncShare(_,_))
1348 .WillOnce(
1349 DoAll(Invoke(sessions::test_util::SimulatePollRetrySuccess),
1350 QuitLoopNowAction()));
1352 // Run to wait for second retrying.
1353 RunLoop();
1355 StopSyncScheduler();
1358 ACTION_P2(VerifyRetryTimerDelay, scheduler_test, expected_delay) {
1359 EXPECT_EQ(expected_delay, scheduler_test->GetRetryTimerDelay());
1362 TEST_F(SyncSchedulerTest, ReceiveNewRetryDelay) {
1363 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1365 SyncShareTimes times;
1366 base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(100);
1367 base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(200);
1369 scheduler()->ScheduleLocalRefreshRequest(zero(), ModelTypeSet(BOOKMARKS),
1370 FROM_HERE);
1371 scheduler()->OnReceivedGuRetryDelay(delay1);
1373 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
1374 .WillOnce(DoAll(
1375 WithoutArgs(VerifyRetryTimerDelay(this, delay1)),
1376 WithArg<2>(sessions::test_util::SimulateGuRetryDelayCommand(delay2)),
1377 WithoutArgs(VerifyRetryTimerDelay(this, delay2)),
1378 RecordSyncShare(&times)));
1380 // Run nudge GU.
1381 RunLoop();
1383 EXPECT_CALL(*syncer(), RetrySyncShare(_,_))
1384 .WillOnce(
1385 DoAll(Invoke(sessions::test_util::SimulatePollRetrySuccess),
1386 RecordSyncShare(&times)));
1388 // Run to wait for retrying.
1389 RunLoop();
1391 StopSyncScheduler();
1394 } // namespace syncer