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/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
;
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
;
97 // Convenient to use in tests wishing to analyze SyncShare calls over time.
98 static const size_t kMinNumSamples
= 5;
99 class SyncSchedulerTest
: public testing::Test
{
101 SyncSchedulerTest() : syncer_(NULL
), delay_(NULL
), weak_ptr_factory_(this) {}
103 class MockDelayProvider
: public BackoffDelayProvider
{
105 MockDelayProvider() : BackoffDelayProvider(
106 TimeDelta::FromSeconds(kInitialBackoffRetrySeconds
),
107 TimeDelta::FromSeconds(kInitialBackoffImmediateRetrySeconds
)) {
110 MOCK_METHOD1(GetDelay
, TimeDelta(const TimeDelta
&));
113 virtual void SetUp() {
115 syncer_
= new testing::StrictMock
<MockSyncer
>();
117 extensions_activity_
= new ExtensionsActivity();
119 routing_info_
[BOOKMARKS
] = GROUP_UI
;
120 routing_info_
[AUTOFILL
] = GROUP_DB
;
121 routing_info_
[THEMES
] = GROUP_UI
;
122 routing_info_
[NIGORI
] = GROUP_PASSIVE
;
125 workers_
.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_UI
)));
126 workers_
.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_DB
)));
127 workers_
.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_PASSIVE
)));
129 connection_
.reset(new MockConnectionManager(directory(),
130 &cancelation_signal_
));
131 connection_
->SetServerReachable();
133 model_type_registry_
.reset(new ModelTypeRegistry(workers_
, directory()));
135 context_
.reset(new SyncSessionContext(
136 connection_
.get(), directory(),
137 extensions_activity_
.get(),
138 std::vector
<SyncEngineEventListener
*>(), NULL
,
139 model_type_registry_
.get(),
140 true, // enable keystore encryption
141 false, // force enable pre-commit GU avoidance
142 "fake_invalidator_client_id"));
143 context_
->SetRoutingInfo(routing_info_
);
144 context_
->set_notifications_enabled(true);
145 context_
->set_account_name("Test");
147 new SyncSchedulerImpl("TestSyncScheduler",
148 BackoffDelayProvider::FromDefaults(),
153 SyncSchedulerImpl
* scheduler() { return scheduler_
.get(); }
154 const ModelSafeRoutingInfo
& routing_info() { return routing_info_
; }
155 MockSyncer
* syncer() { return syncer_
; }
156 MockDelayProvider
* delay() { return delay_
; }
157 MockConnectionManager
* connection() { return connection_
.get(); }
158 TimeDelta
zero() { return TimeDelta::FromSeconds(0); }
159 TimeDelta
timeout() {
160 return TestTimeouts::action_timeout();
163 virtual void TearDown() {
167 dir_maker_
.TearDown();
170 void AnalyzePollRun(const SyncShareTimes
& times
, size_t min_num_samples
,
171 const TimeTicks
& optimal_start
, const TimeDelta
& poll_interval
) {
172 EXPECT_GE(times
.size(), min_num_samples
);
173 for (size_t i
= 0; i
< times
.size(); i
++) {
174 SCOPED_TRACE(testing::Message() << "SyncShare # (" << i
<< ")");
175 TimeTicks optimal_next_sync
= optimal_start
+ poll_interval
* i
;
176 EXPECT_GE(times
[i
], optimal_next_sync
);
180 void DoQuitLoopNow() {
184 void StartSyncScheduler(SyncScheduler::Mode mode
) {
185 scheduler()->Start(mode
);
188 // This stops the scheduler synchronously.
189 void StopSyncScheduler() {
190 base::MessageLoop::current()->PostTask(
192 base::Bind(&SyncSchedulerTest::DoQuitLoopNow
,
193 weak_ptr_factory_
.GetWeakPtr()));
197 bool RunAndGetBackoff() {
198 ModelTypeSet
nudge_types(BOOKMARKS
);
199 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
201 scheduler()->ScheduleLocalNudge(zero(), nudge_types
, FROM_HERE
);
204 return scheduler()->IsBackingOff();
207 void UseMockDelayProvider() {
208 delay_
= new MockDelayProvider();
209 scheduler_
->delay_provider_
.reset(delay_
);
212 SyncSessionContext
* context() { return context_
.get(); }
214 ModelTypeSet
GetThrottledTypes() {
215 return scheduler_
->nudge_tracker_
.GetThrottledTypes();
218 base::TimeDelta
GetRetryTimerDelay() {
219 EXPECT_TRUE(scheduler_
->retry_timer_
.IsRunning());
220 return scheduler_
->retry_timer_
.GetCurrentDelay();
224 syncable::Directory
* directory() {
225 return dir_maker_
.directory();
228 base::MessageLoop loop_
;
229 TestDirectorySetterUpper dir_maker_
;
230 CancelationSignal cancelation_signal_
;
231 scoped_ptr
<MockConnectionManager
> connection_
;
232 scoped_ptr
<ModelTypeRegistry
> model_type_registry_
;
233 scoped_ptr
<SyncSessionContext
> context_
;
234 scoped_ptr
<SyncSchedulerImpl
> scheduler_
;
236 MockDelayProvider
* delay_
;
237 std::vector
<scoped_refptr
<ModelSafeWorker
> > workers_
;
238 scoped_refptr
<ExtensionsActivity
> extensions_activity_
;
239 ModelSafeRoutingInfo routing_info_
;
240 base::WeakPtrFactory
<SyncSchedulerTest
> weak_ptr_factory_
;
243 void RecordSyncShareImpl(SyncShareTimes
* times
) {
244 times
->push_back(TimeTicks::Now());
247 ACTION_P(RecordSyncShare
, times
) {
248 RecordSyncShareImpl(times
);
249 if (base::MessageLoop::current()->is_running())
254 ACTION_P2(RecordSyncShareMultiple
, times
, quit_after
) {
255 RecordSyncShareImpl(times
);
256 EXPECT_LE(times
->size(), quit_after
);
257 if (times
->size() >= quit_after
&&
258 base::MessageLoop::current()->is_running()) {
264 ACTION_P(StopScheduler
, scheduler
) {
268 ACTION(AddFailureAndQuitLoopNow
) {
274 ACTION(QuitLoopNowAction
) {
279 // Test nudge scheduling.
280 TEST_F(SyncSchedulerTest
, Nudge
) {
281 SyncShareTimes times
;
282 ModelTypeSet
model_types(BOOKMARKS
);
284 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
285 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
286 RecordSyncShare(×
)))
287 .RetiresOnSaturation();
289 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
291 scheduler()->ScheduleLocalNudge(zero(), model_types
, FROM_HERE
);
294 Mock::VerifyAndClearExpectations(syncer());
296 // Make sure a second, later, nudge is unaffected by first (no coalescing).
297 SyncShareTimes times2
;
298 model_types
.Remove(BOOKMARKS
);
299 model_types
.Put(AUTOFILL
);
300 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
301 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
302 RecordSyncShare(×2
)));
303 scheduler()->ScheduleLocalNudge(zero(), model_types
, FROM_HERE
);
307 // Make sure a regular config command is scheduled fine in the absence of any
309 TEST_F(SyncSchedulerTest
, Config
) {
310 SyncShareTimes times
;
311 const ModelTypeSet
model_types(BOOKMARKS
);
313 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
314 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess
),
315 RecordSyncShare(×
)));
317 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
319 CallbackCounter ready_counter
;
320 CallbackCounter retry_counter
;
321 ConfigurationParams
params(
322 GetUpdatesCallerInfo::RECONFIGURATION
,
324 TypesToRoutingInfo(model_types
),
325 base::Bind(&CallbackCounter::Callback
, base::Unretained(&ready_counter
)),
326 base::Bind(&CallbackCounter::Callback
, base::Unretained(&retry_counter
)));
327 scheduler()->ScheduleConfiguration(params
);
329 ASSERT_EQ(1, ready_counter
.times_called());
330 ASSERT_EQ(0, retry_counter
.times_called());
333 // Simulate a failure and make sure the config request is retried.
334 TEST_F(SyncSchedulerTest
, ConfigWithBackingOff
) {
335 UseMockDelayProvider();
336 EXPECT_CALL(*delay(), GetDelay(_
))
337 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(1)));
338 SyncShareTimes times
;
339 const ModelTypeSet
model_types(BOOKMARKS
);
341 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
343 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
344 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed
),
345 RecordSyncShare(×
)))
346 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed
),
347 RecordSyncShare(×
)));
349 CallbackCounter ready_counter
;
350 CallbackCounter retry_counter
;
351 ConfigurationParams
params(
352 GetUpdatesCallerInfo::RECONFIGURATION
,
354 TypesToRoutingInfo(model_types
),
355 base::Bind(&CallbackCounter::Callback
, base::Unretained(&ready_counter
)),
356 base::Bind(&CallbackCounter::Callback
, base::Unretained(&retry_counter
)));
357 scheduler()->ScheduleConfiguration(params
);
359 ASSERT_EQ(0, ready_counter
.times_called());
360 ASSERT_EQ(1, retry_counter
.times_called());
362 // RunLoop() will trigger TryCanaryJob which will retry configuration.
363 // Since retry_task was already called it shouldn't be called again.
365 ASSERT_EQ(0, ready_counter
.times_called());
366 ASSERT_EQ(1, retry_counter
.times_called());
368 Mock::VerifyAndClearExpectations(syncer());
370 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
371 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess
),
372 RecordSyncShare(×
)));
375 ASSERT_EQ(1, ready_counter
.times_called());
378 // Simuilate SyncSchedulerImpl::Stop being called in the middle of Configure.
379 // This can happen if server returns NOT_MY_BIRTHDAY.
380 TEST_F(SyncSchedulerTest
, ConfigWithStop
) {
381 UseMockDelayProvider();
382 EXPECT_CALL(*delay(), GetDelay(_
))
383 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(1)));
384 SyncShareTimes times
;
385 const ModelTypeSet
model_types(BOOKMARKS
);
387 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
389 // Make ConfigureSyncShare call scheduler->Stop(). It is not supposed to call
390 // retry_task or dereference configuration params.
391 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
392 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed
),
393 StopScheduler(scheduler()),
394 RecordSyncShare(×
)));
396 CallbackCounter ready_counter
;
397 CallbackCounter retry_counter
;
398 ConfigurationParams
params(
399 GetUpdatesCallerInfo::RECONFIGURATION
,
401 TypesToRoutingInfo(model_types
),
402 base::Bind(&CallbackCounter::Callback
, base::Unretained(&ready_counter
)),
403 base::Bind(&CallbackCounter::Callback
, base::Unretained(&retry_counter
)));
404 scheduler()->ScheduleConfiguration(params
);
406 ASSERT_EQ(0, ready_counter
.times_called());
407 ASSERT_EQ(0, retry_counter
.times_called());
410 // Issue a nudge when the config has failed. Make sure both the config and
411 // nudge are executed.
412 TEST_F(SyncSchedulerTest
, NudgeWithConfigWithBackingOff
) {
413 const ModelTypeSet
model_types(BOOKMARKS
);
414 UseMockDelayProvider();
415 EXPECT_CALL(*delay(), GetDelay(_
))
416 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(50)));
417 SyncShareTimes times
;
419 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
421 // Request a configure and make sure it fails.
422 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
423 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed
),
424 RecordSyncShare(×
)));
425 CallbackCounter ready_counter
;
426 CallbackCounter retry_counter
;
427 ConfigurationParams
params(
428 GetUpdatesCallerInfo::RECONFIGURATION
,
430 TypesToRoutingInfo(model_types
),
431 base::Bind(&CallbackCounter::Callback
, base::Unretained(&ready_counter
)),
432 base::Bind(&CallbackCounter::Callback
, base::Unretained(&retry_counter
)));
433 scheduler()->ScheduleConfiguration(params
);
435 ASSERT_EQ(0, ready_counter
.times_called());
436 ASSERT_EQ(1, retry_counter
.times_called());
437 Mock::VerifyAndClearExpectations(syncer());
439 // Ask for a nudge while dealing with repeated configure failure.
440 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
441 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed
),
442 RecordSyncShare(×
)));
443 scheduler()->ScheduleLocalNudge(zero(), model_types
, FROM_HERE
);
445 // Note that we're not RunLoop()ing for the NUDGE we just scheduled, but
446 // for the first retry attempt from the config job (after
447 // waiting ~+/- 50ms).
448 Mock::VerifyAndClearExpectations(syncer());
449 ASSERT_EQ(0, ready_counter
.times_called());
451 // Let the next configure retry succeed.
452 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
453 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess
),
454 RecordSyncShare(×
)));
457 // Now change the mode so nudge can execute.
458 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
459 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
460 RecordSyncShare(×
)));
461 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
465 // Test that nudges are coalesced.
466 TEST_F(SyncSchedulerTest
, NudgeCoalescing
) {
467 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
469 SyncShareTimes times
;
470 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
471 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
472 RecordSyncShare(×
)));
473 const ModelTypeSet
types1(BOOKMARKS
), types2(AUTOFILL
), types3(THEMES
);
474 TimeDelta delay
= zero();
475 TimeTicks optimal_time
= TimeTicks::Now() + delay
;
476 scheduler()->ScheduleLocalNudge(delay
, types1
, FROM_HERE
);
477 scheduler()->ScheduleLocalNudge(zero(), types2
, FROM_HERE
);
480 ASSERT_EQ(1U, times
.size());
481 EXPECT_GE(times
[0], optimal_time
);
483 Mock::VerifyAndClearExpectations(syncer());
485 SyncShareTimes times2
;
486 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
487 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
488 RecordSyncShare(×2
)));
489 scheduler()->ScheduleLocalNudge(zero(), types3
, FROM_HERE
);
493 // Test that nudges are coalesced.
494 TEST_F(SyncSchedulerTest
, NudgeCoalescingWithDifferentTimings
) {
495 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
497 SyncShareTimes times
;
498 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
499 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
500 RecordSyncShare(×
)));
501 ModelTypeSet
types1(BOOKMARKS
), types2(AUTOFILL
), types3
;
503 // Create a huge time delay.
504 TimeDelta delay
= TimeDelta::FromDays(1);
506 scheduler()->ScheduleLocalNudge(delay
, types1
, FROM_HERE
);
507 scheduler()->ScheduleLocalNudge(zero(), types2
, FROM_HERE
);
509 TimeTicks min_time
= TimeTicks::Now();
510 TimeTicks max_time
= TimeTicks::Now() + delay
;
513 Mock::VerifyAndClearExpectations(syncer());
515 // Make sure the sync happened at the right time.
516 ASSERT_EQ(1U, times
.size());
517 EXPECT_GE(times
[0], min_time
);
518 EXPECT_LE(times
[0], max_time
);
521 // Test nudge scheduling.
522 TEST_F(SyncSchedulerTest
, NudgeWithStates
) {
523 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
525 SyncShareTimes times1
;
526 ObjectIdInvalidationMap invalidations1
=
527 BuildInvalidationMap(BOOKMARKS
, 10, "test");
528 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
529 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
530 RecordSyncShare(×1
)))
531 .RetiresOnSaturation();
532 scheduler()->ScheduleInvalidationNudge(zero(), invalidations1
, FROM_HERE
);
535 Mock::VerifyAndClearExpectations(syncer());
537 // Make sure a second, later, nudge is unaffected by first (no coalescing).
538 SyncShareTimes times2
;
539 ObjectIdInvalidationMap invalidations2
=
540 BuildInvalidationMap(AUTOFILL
, 10, "test2");
541 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
542 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
543 RecordSyncShare(×2
)));
544 scheduler()->ScheduleInvalidationNudge(zero(), invalidations2
, FROM_HERE
);
548 // Test that polling works as expected.
549 TEST_F(SyncSchedulerTest
, Polling
) {
550 SyncShareTimes times
;
551 TimeDelta
poll_interval(TimeDelta::FromMilliseconds(30));
552 EXPECT_CALL(*syncer(), PollSyncShare(_
,_
)).Times(AtLeast(kMinNumSamples
))
554 DoAll(Invoke(sessions::test_util::SimulatePollSuccess
),
555 RecordSyncShareMultiple(×
, kMinNumSamples
)));
557 scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval
);
559 TimeTicks optimal_start
= TimeTicks::Now() + poll_interval
;
560 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
562 // Run again to wait for polling.
566 AnalyzePollRun(times
, kMinNumSamples
, optimal_start
, poll_interval
);
569 // Test that the short poll interval is used.
570 TEST_F(SyncSchedulerTest
, PollNotificationsDisabled
) {
571 SyncShareTimes times
;
572 TimeDelta
poll_interval(TimeDelta::FromMilliseconds(30));
573 EXPECT_CALL(*syncer(), PollSyncShare(_
,_
)).Times(AtLeast(kMinNumSamples
))
575 DoAll(Invoke(sessions::test_util::SimulatePollSuccess
),
576 RecordSyncShareMultiple(×
, kMinNumSamples
)));
578 scheduler()->OnReceivedShortPollIntervalUpdate(poll_interval
);
579 scheduler()->SetNotificationsEnabled(false);
581 TimeTicks optimal_start
= TimeTicks::Now() + poll_interval
;
582 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
584 // Run again to wait for polling.
588 AnalyzePollRun(times
, kMinNumSamples
, optimal_start
, poll_interval
);
591 // Test that polling intervals are updated when needed.
592 TEST_F(SyncSchedulerTest
, PollIntervalUpdate
) {
593 SyncShareTimes times
;
594 TimeDelta
poll1(TimeDelta::FromMilliseconds(120));
595 TimeDelta
poll2(TimeDelta::FromMilliseconds(30));
596 scheduler()->OnReceivedLongPollIntervalUpdate(poll1
);
597 EXPECT_CALL(*syncer(), PollSyncShare(_
,_
)).Times(AtLeast(kMinNumSamples
))
600 sessions::test_util::SimulatePollIntervalUpdate(poll2
)),
603 DoAll(Invoke(sessions::test_util::SimulatePollSuccess
),
605 RecordSyncShareMultiple(×
, kMinNumSamples
))));
607 TimeTicks optimal_start
= TimeTicks::Now() + poll1
+ poll2
;
608 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
610 // Run again to wait for polling.
614 AnalyzePollRun(times
, kMinNumSamples
, optimal_start
, poll2
);
617 // Test that the sessions commit delay is updated when needed.
618 TEST_F(SyncSchedulerTest
, SessionsCommitDelay
) {
619 SyncShareTimes times
;
620 TimeDelta
delay1(TimeDelta::FromMilliseconds(120));
621 TimeDelta
delay2(TimeDelta::FromMilliseconds(30));
622 scheduler()->OnReceivedSessionsCommitDelay(delay1
);
624 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
628 sessions::test_util::SimulateSessionsCommitDelayUpdate(
630 Invoke(sessions::test_util::SimulateNormalSuccess
),
631 QuitLoopNowAction()));
633 EXPECT_EQ(delay1
, scheduler()->GetSessionsCommitDelay());
634 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
636 EXPECT_EQ(delay1
, scheduler()->GetSessionsCommitDelay());
637 const ModelTypeSet
model_types(BOOKMARKS
);
638 scheduler()->ScheduleLocalNudge(zero(), model_types
, FROM_HERE
);
641 EXPECT_EQ(delay2
, scheduler()->GetSessionsCommitDelay());
645 // Test that no syncing occurs when throttled.
646 TEST_F(SyncSchedulerTest
, ThrottlingDoesThrottle
) {
647 const ModelTypeSet
types(BOOKMARKS
);
648 TimeDelta
poll(TimeDelta::FromMilliseconds(5));
649 TimeDelta
throttle(TimeDelta::FromMinutes(10));
650 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
652 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
654 WithArg
<2>(sessions::test_util::SimulateThrottled(throttle
)),
656 .WillRepeatedly(AddFailureAndQuitLoopNow());
658 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
660 scheduler()->ScheduleLocalNudge(
661 TimeDelta::FromMicroseconds(1), types
, FROM_HERE
);
664 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
666 CallbackCounter ready_counter
;
667 CallbackCounter retry_counter
;
668 ConfigurationParams
params(
669 GetUpdatesCallerInfo::RECONFIGURATION
,
671 TypesToRoutingInfo(types
),
672 base::Bind(&CallbackCounter::Callback
, base::Unretained(&ready_counter
)),
673 base::Bind(&CallbackCounter::Callback
, base::Unretained(&retry_counter
)));
674 scheduler()->ScheduleConfiguration(params
);
676 ASSERT_EQ(0, ready_counter
.times_called());
677 ASSERT_EQ(1, retry_counter
.times_called());
681 TEST_F(SyncSchedulerTest
, ThrottlingExpiresFromPoll
) {
682 SyncShareTimes times
;
683 TimeDelta
poll(TimeDelta::FromMilliseconds(15));
684 TimeDelta
throttle1(TimeDelta::FromMilliseconds(150));
685 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
687 ::testing::InSequence seq
;
688 EXPECT_CALL(*syncer(), PollSyncShare(_
,_
))
690 WithArg
<1>(sessions::test_util::SimulateThrottled(throttle1
)),
692 .RetiresOnSaturation();
693 EXPECT_CALL(*syncer(), PollSyncShare(_
,_
))
695 DoAll(Invoke(sessions::test_util::SimulatePollSuccess
),
696 RecordSyncShareMultiple(×
, kMinNumSamples
)));
698 TimeTicks optimal_start
= TimeTicks::Now() + poll
+ throttle1
;
699 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
701 // Run again to wait for polling.
705 AnalyzePollRun(times
, kMinNumSamples
, optimal_start
, poll
);
708 TEST_F(SyncSchedulerTest
, ThrottlingExpiresFromNudge
) {
709 SyncShareTimes times
;
710 TimeDelta
poll(TimeDelta::FromDays(1));
711 TimeDelta
throttle1(TimeDelta::FromMilliseconds(150));
712 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
714 ::testing::InSequence seq
;
715 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
717 WithArg
<2>(sessions::test_util::SimulateThrottled(throttle1
)),
719 .RetiresOnSaturation();
720 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
721 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
722 QuitLoopNowAction()));
724 const ModelTypeSet
types(BOOKMARKS
);
725 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
726 scheduler()->ScheduleLocalNudge(zero(), types
, FROM_HERE
);
728 PumpLoop(); // To get PerformDelayedNudge called.
729 PumpLoop(); // To get TrySyncSessionJob called
730 EXPECT_TRUE(scheduler()->IsCurrentlyThrottled());
732 EXPECT_FALSE(scheduler()->IsCurrentlyThrottled());
737 TEST_F(SyncSchedulerTest
, ThrottlingExpiresFromConfigure
) {
738 SyncShareTimes times
;
739 TimeDelta
poll(TimeDelta::FromDays(1));
740 TimeDelta
throttle1(TimeDelta::FromMilliseconds(150));
741 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
743 ::testing::InSequence seq
;
744 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
746 WithArg
<2>(sessions::test_util::SimulateThrottled(throttle1
)),
748 .RetiresOnSaturation();
749 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
750 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess
),
751 QuitLoopNowAction()));
753 const ModelTypeSet
types(BOOKMARKS
);
754 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
756 CallbackCounter ready_counter
;
757 CallbackCounter retry_counter
;
758 ConfigurationParams
params(
759 GetUpdatesCallerInfo::RECONFIGURATION
,
761 TypesToRoutingInfo(types
),
762 base::Bind(&CallbackCounter::Callback
, base::Unretained(&ready_counter
)),
763 base::Bind(&CallbackCounter::Callback
, base::Unretained(&retry_counter
)));
764 scheduler()->ScheduleConfiguration(params
);
766 EXPECT_EQ(0, ready_counter
.times_called());
767 EXPECT_EQ(1, retry_counter
.times_called());
768 EXPECT_TRUE(scheduler()->IsCurrentlyThrottled());
771 EXPECT_FALSE(scheduler()->IsCurrentlyThrottled());
776 TEST_F(SyncSchedulerTest
, TypeThrottlingBlocksNudge
) {
777 UseMockDelayProvider();
778 EXPECT_CALL(*delay(), GetDelay(_
))
779 .WillRepeatedly(Return(zero()));
781 TimeDelta
poll(TimeDelta::FromDays(1));
782 TimeDelta
throttle1(TimeDelta::FromSeconds(60));
783 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
785 const ModelTypeSet
types(BOOKMARKS
);
787 ::testing::InSequence seq
;
788 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
791 sessions::test_util::SimulateTypesThrottled(types
, throttle1
)),
793 .RetiresOnSaturation();
795 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
796 scheduler()->ScheduleLocalNudge(zero(), types
, FROM_HERE
);
797 PumpLoop(); // To get PerformDelayedNudge called.
798 PumpLoop(); // To get TrySyncSessionJob called
799 EXPECT_TRUE(GetThrottledTypes().HasAll(types
));
801 // This won't cause a sync cycle because the types are throttled.
802 scheduler()->ScheduleLocalNudge(zero(), types
, FROM_HERE
);
808 TEST_F(SyncSchedulerTest
, TypeThrottlingDoesBlockOtherSources
) {
809 UseMockDelayProvider();
810 EXPECT_CALL(*delay(), GetDelay(_
))
811 .WillRepeatedly(Return(zero()));
813 SyncShareTimes times
;
814 TimeDelta
poll(TimeDelta::FromDays(1));
815 TimeDelta
throttle1(TimeDelta::FromSeconds(60));
816 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
818 const ModelTypeSet
throttled_types(BOOKMARKS
);
819 const ModelTypeSet
unthrottled_types(PREFERENCES
);
821 ::testing::InSequence seq
;
822 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
825 sessions::test_util::SimulateTypesThrottled(
826 throttled_types
, throttle1
)),
828 .RetiresOnSaturation();
830 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
831 scheduler()->ScheduleLocalNudge(zero(), throttled_types
, FROM_HERE
);
832 PumpLoop(); // To get PerformDelayedNudge called.
833 PumpLoop(); // To get TrySyncSessionJob called
834 EXPECT_TRUE(GetThrottledTypes().HasAll(throttled_types
));
836 // Ignore invalidations for throttled types.
837 ObjectIdInvalidationMap invalidations
=
838 BuildInvalidationMap(BOOKMARKS
, 10, "test");
839 scheduler()->ScheduleInvalidationNudge(zero(), invalidations
, FROM_HERE
);
842 // Ignore refresh requests for throttled types.
843 scheduler()->ScheduleLocalRefreshRequest(zero(), throttled_types
, FROM_HERE
);
846 Mock::VerifyAndClearExpectations(syncer());
848 // Local nudges for non-throttled types will trigger a sync.
849 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
850 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
851 RecordSyncShare(×
)));
852 scheduler()->ScheduleLocalNudge(zero(), unthrottled_types
, FROM_HERE
);
854 Mock::VerifyAndClearExpectations(syncer());
859 // Test nudges / polls don't run in config mode and config tasks do.
860 TEST_F(SyncSchedulerTest
, ConfigurationMode
) {
861 TimeDelta
poll(TimeDelta::FromMilliseconds(15));
862 SyncShareTimes times
;
863 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
865 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
867 const ModelTypeSet
nudge_types(AUTOFILL
);
868 scheduler()->ScheduleLocalNudge(zero(), nudge_types
, FROM_HERE
);
869 scheduler()->ScheduleLocalNudge(zero(), nudge_types
, FROM_HERE
);
871 const ModelTypeSet
config_types(BOOKMARKS
);
873 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
874 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess
),
875 RecordSyncShare(×
)))
876 .RetiresOnSaturation();
877 CallbackCounter ready_counter
;
878 CallbackCounter retry_counter
;
879 ConfigurationParams
params(
880 GetUpdatesCallerInfo::RECONFIGURATION
,
882 TypesToRoutingInfo(config_types
),
883 base::Bind(&CallbackCounter::Callback
, base::Unretained(&ready_counter
)),
884 base::Bind(&CallbackCounter::Callback
, base::Unretained(&retry_counter
)));
885 scheduler()->ScheduleConfiguration(params
);
887 ASSERT_EQ(1, ready_counter
.times_called());
888 ASSERT_EQ(0, retry_counter
.times_called());
890 Mock::VerifyAndClearExpectations(syncer());
892 // Switch to NORMAL_MODE to ensure NUDGES were properly saved and run.
893 scheduler()->OnReceivedLongPollIntervalUpdate(TimeDelta::FromDays(1));
894 SyncShareTimes times2
;
895 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
896 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
897 RecordSyncShare(×2
)));
899 // TODO(tim): Figure out how to remove this dangerous need to reset
900 // routing info between mode switches.
901 context()->SetRoutingInfo(routing_info());
902 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
905 Mock::VerifyAndClearExpectations(syncer());
908 class BackoffTriggersSyncSchedulerTest
: public SyncSchedulerTest
{
909 virtual void SetUp() {
910 SyncSchedulerTest::SetUp();
911 UseMockDelayProvider();
912 EXPECT_CALL(*delay(), GetDelay(_
))
913 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(1)));
916 virtual void TearDown() {
918 SyncSchedulerTest::TearDown();
922 // Have the sycner fail during commit. Expect that the scheduler enters
924 TEST_F(BackoffTriggersSyncSchedulerTest
, FailCommitOnce
) {
925 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
926 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed
),
927 QuitLoopNowAction()));
928 EXPECT_TRUE(RunAndGetBackoff());
931 // Have the syncer fail during download updates and succeed on the first
932 // retry. Expect that this clears the backoff state.
933 TEST_F(BackoffTriggersSyncSchedulerTest
, FailDownloadOnceThenSucceed
) {
934 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
936 Invoke(sessions::test_util::SimulateDownloadUpdatesFailed
),
938 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
939 QuitLoopNowAction()));
940 EXPECT_FALSE(RunAndGetBackoff());
943 // Have the syncer fail during commit and succeed on the first retry. Expect
944 // that this clears the backoff state.
945 TEST_F(BackoffTriggersSyncSchedulerTest
, FailCommitOnceThenSucceed
) {
946 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
948 Invoke(sessions::test_util::SimulateCommitFailed
),
950 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
951 QuitLoopNowAction()));
952 EXPECT_FALSE(RunAndGetBackoff());
955 // Have the syncer fail to download updates and fail again on the retry.
956 // Expect this will leave the scheduler in backoff.
957 TEST_F(BackoffTriggersSyncSchedulerTest
, FailDownloadTwice
) {
958 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
960 Invoke(sessions::test_util::SimulateDownloadUpdatesFailed
),
962 .WillRepeatedly(DoAll(
963 Invoke(sessions::test_util::SimulateDownloadUpdatesFailed
),
964 QuitLoopNowAction()));
965 EXPECT_TRUE(RunAndGetBackoff());
968 // Have the syncer fail to get the encryption key yet succeed in downloading
969 // updates. Expect this will leave the scheduler in backoff.
970 TEST_F(BackoffTriggersSyncSchedulerTest
, FailGetEncryptionKey
) {
971 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
973 Invoke(sessions::test_util::SimulateGetEncryptionKeyFailed
),
975 .WillRepeatedly(DoAll(
976 Invoke(sessions::test_util::SimulateGetEncryptionKeyFailed
),
977 QuitLoopNowAction()));
978 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
980 ModelTypeSet
types(BOOKMARKS
);
981 CallbackCounter ready_counter
;
982 CallbackCounter retry_counter
;
983 ConfigurationParams
params(
984 GetUpdatesCallerInfo::RECONFIGURATION
,
986 TypesToRoutingInfo(types
),
987 base::Bind(&CallbackCounter::Callback
, base::Unretained(&ready_counter
)),
988 base::Bind(&CallbackCounter::Callback
, base::Unretained(&retry_counter
)));
989 scheduler()->ScheduleConfiguration(params
);
992 EXPECT_TRUE(scheduler()->IsBackingOff());
995 // Test that no polls or extraneous nudges occur when in backoff.
996 TEST_F(SyncSchedulerTest
, BackoffDropsJobs
) {
997 SyncShareTimes times
;
998 TimeDelta
poll(TimeDelta::FromMilliseconds(5));
999 const ModelTypeSet
types(BOOKMARKS
);
1000 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
1001 UseMockDelayProvider();
1003 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
1004 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed
),
1005 RecordSyncShareMultiple(×
, 1U)));
1006 EXPECT_CALL(*delay(), GetDelay(_
)).
1007 WillRepeatedly(Return(TimeDelta::FromDays(1)));
1009 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
1011 // This nudge should fail and put us into backoff. Thanks to our mock
1012 // GetDelay() setup above, this will be a long backoff.
1013 scheduler()->ScheduleLocalNudge(zero(), types
, FROM_HERE
);
1016 // From this point forward, no SyncShare functions should be invoked.
1017 Mock::VerifyAndClearExpectations(syncer());
1019 // Wait a while (10x poll interval) so a few poll jobs will be attempted.
1020 PumpLoopFor(poll
* 10);
1022 // Try (and fail) to schedule a nudge.
1023 scheduler()->ScheduleLocalNudge(
1024 base::TimeDelta::FromMilliseconds(1),
1028 Mock::VerifyAndClearExpectations(syncer());
1029 Mock::VerifyAndClearExpectations(delay());
1031 EXPECT_CALL(*delay(), GetDelay(_
)).Times(0);
1033 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
1035 CallbackCounter ready_counter
;
1036 CallbackCounter retry_counter
;
1037 ConfigurationParams
params(
1038 GetUpdatesCallerInfo::RECONFIGURATION
,
1040 TypesToRoutingInfo(types
),
1041 base::Bind(&CallbackCounter::Callback
, base::Unretained(&ready_counter
)),
1042 base::Bind(&CallbackCounter::Callback
, base::Unretained(&retry_counter
)));
1043 scheduler()->ScheduleConfiguration(params
);
1045 ASSERT_EQ(0, ready_counter
.times_called());
1046 ASSERT_EQ(1, retry_counter
.times_called());
1050 // Test that backoff is shaping traffic properly with consecutive errors.
1051 TEST_F(SyncSchedulerTest
, BackoffElevation
) {
1052 SyncShareTimes times
;
1053 UseMockDelayProvider();
1055 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
)).Times(kMinNumSamples
)
1056 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateCommitFailed
),
1057 RecordSyncShareMultiple(×
, kMinNumSamples
)));
1059 const TimeDelta first
= TimeDelta::FromSeconds(kInitialBackoffRetrySeconds
);
1060 const TimeDelta second
= TimeDelta::FromMilliseconds(2);
1061 const TimeDelta third
= TimeDelta::FromMilliseconds(3);
1062 const TimeDelta fourth
= TimeDelta::FromMilliseconds(4);
1063 const TimeDelta fifth
= TimeDelta::FromMilliseconds(5);
1064 const TimeDelta sixth
= TimeDelta::FromDays(1);
1066 EXPECT_CALL(*delay(), GetDelay(first
)).WillOnce(Return(second
))
1067 .RetiresOnSaturation();
1068 EXPECT_CALL(*delay(), GetDelay(second
)).WillOnce(Return(third
))
1069 .RetiresOnSaturation();
1070 EXPECT_CALL(*delay(), GetDelay(third
)).WillOnce(Return(fourth
))
1071 .RetiresOnSaturation();
1072 EXPECT_CALL(*delay(), GetDelay(fourth
)).WillOnce(Return(fifth
))
1073 .RetiresOnSaturation();
1074 EXPECT_CALL(*delay(), GetDelay(fifth
)).WillOnce(Return(sixth
));
1076 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
1078 // Run again with a nudge.
1079 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS
), FROM_HERE
);
1082 ASSERT_EQ(kMinNumSamples
, times
.size());
1083 EXPECT_GE(times
[1] - times
[0], second
);
1084 EXPECT_GE(times
[2] - times
[1], third
);
1085 EXPECT_GE(times
[3] - times
[2], fourth
);
1086 EXPECT_GE(times
[4] - times
[3], fifth
);
1089 // Test that things go back to normal once a retry makes forward progress.
1090 TEST_F(SyncSchedulerTest
, BackoffRelief
) {
1091 SyncShareTimes times
;
1092 const TimeDelta
poll(TimeDelta::FromMilliseconds(10));
1093 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
1094 UseMockDelayProvider();
1096 const TimeDelta backoff
= TimeDelta::FromMilliseconds(5);
1097 EXPECT_CALL(*delay(), GetDelay(_
)).WillOnce(Return(backoff
));
1099 // Optimal start for the post-backoff poll party.
1100 TimeTicks optimal_start
= TimeTicks::Now();
1101 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
1103 // Kick off the test with a failed nudge.
1104 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
1105 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed
),
1106 RecordSyncShare(×
)));
1107 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS
), FROM_HERE
);
1109 Mock::VerifyAndClearExpectations(syncer());
1110 TimeTicks optimal_job_time
= optimal_start
;
1111 ASSERT_EQ(1U, times
.size());
1112 EXPECT_GE(times
[0], optimal_job_time
);
1114 // The retry succeeds.
1115 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
1117 Invoke(sessions::test_util::SimulateNormalSuccess
),
1118 RecordSyncShare(×
)));
1120 Mock::VerifyAndClearExpectations(syncer());
1121 optimal_job_time
= optimal_job_time
+ backoff
;
1122 ASSERT_EQ(2U, times
.size());
1123 EXPECT_GE(times
[1], optimal_job_time
);
1125 // Now let the Poll timer do its thing.
1126 EXPECT_CALL(*syncer(), PollSyncShare(_
,_
))
1127 .WillRepeatedly(DoAll(
1128 Invoke(sessions::test_util::SimulatePollSuccess
),
1129 RecordSyncShareMultiple(×
, kMinNumSamples
)));
1131 Mock::VerifyAndClearExpectations(syncer());
1132 ASSERT_EQ(kMinNumSamples
, times
.size());
1133 for (size_t i
= 2; i
< times
.size(); i
++) {
1134 optimal_job_time
= optimal_job_time
+ poll
;
1135 SCOPED_TRACE(testing::Message() << "SyncShare # (" << i
<< ")");
1136 EXPECT_GE(times
[i
], optimal_job_time
);
1139 StopSyncScheduler();
1142 // Test that poll failures are ignored. They should have no effect on
1143 // subsequent poll attempts, nor should they trigger a backoff/retry.
1144 TEST_F(SyncSchedulerTest
, TransientPollFailure
) {
1145 SyncShareTimes times
;
1146 const TimeDelta
poll_interval(TimeDelta::FromMilliseconds(1));
1147 scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval
);
1148 UseMockDelayProvider(); // Will cause test failure if backoff is initiated.
1150 EXPECT_CALL(*syncer(), PollSyncShare(_
,_
))
1151 .WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollFailed
),
1152 RecordSyncShare(×
)))
1153 .WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollSuccess
),
1154 RecordSyncShare(×
)));
1156 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
1158 // Run the unsucessful poll. The failed poll should not trigger backoff.
1160 EXPECT_FALSE(scheduler()->IsBackingOff());
1162 // Run the successful poll.
1164 EXPECT_FALSE(scheduler()->IsBackingOff());
1167 // Test that starting the syncer thread without a valid connection doesn't
1168 // break things when a connection is detected.
1169 TEST_F(SyncSchedulerTest
, StartWhenNotConnected
) {
1170 connection()->SetServerNotReachable();
1171 connection()->UpdateConnectionStatus();
1172 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
1173 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConnectionFailure
),
1175 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
1177 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
1179 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS
), FROM_HERE
);
1180 // Should save the nudge for until after the server is reachable.
1181 base::MessageLoop::current()->RunUntilIdle();
1183 scheduler()->OnConnectionStatusChange();
1184 connection()->SetServerReachable();
1185 connection()->UpdateConnectionStatus();
1186 base::MessageLoop::current()->RunUntilIdle();
1189 TEST_F(SyncSchedulerTest
, ServerConnectionChangeDuringBackoff
) {
1190 UseMockDelayProvider();
1191 EXPECT_CALL(*delay(), GetDelay(_
))
1192 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(0)));
1194 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
1195 connection()->SetServerNotReachable();
1196 connection()->UpdateConnectionStatus();
1198 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
1199 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConnectionFailure
),
1201 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
1204 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS
), FROM_HERE
);
1205 PumpLoop(); // To get PerformDelayedNudge called.
1206 PumpLoop(); // Run the nudge, that will fail and schedule a quick retry.
1207 ASSERT_TRUE(scheduler()->IsBackingOff());
1209 // Before we run the scheduled canary, trigger a server connection change.
1210 scheduler()->OnConnectionStatusChange();
1211 connection()->SetServerReachable();
1212 connection()->UpdateConnectionStatus();
1213 base::MessageLoop::current()->RunUntilIdle();
1216 // This was supposed to test the scenario where we receive a nudge while a
1217 // connection change canary is scheduled, but has not run yet. Since we've made
1218 // the connection change canary synchronous, this is no longer possible.
1219 TEST_F(SyncSchedulerTest
, ConnectionChangeCanaryPreemptedByNudge
) {
1220 UseMockDelayProvider();
1221 EXPECT_CALL(*delay(), GetDelay(_
))
1222 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(0)));
1224 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
1225 connection()->SetServerNotReachable();
1226 connection()->UpdateConnectionStatus();
1228 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
1229 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConnectionFailure
),
1231 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
1233 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
1234 QuitLoopNowAction()));
1236 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS
), FROM_HERE
);
1238 PumpLoop(); // To get PerformDelayedNudge called.
1239 PumpLoop(); // Run the nudge, that will fail and schedule a quick retry.
1240 ASSERT_TRUE(scheduler()->IsBackingOff());
1242 // Before we run the scheduled canary, trigger a server connection change.
1243 scheduler()->OnConnectionStatusChange();
1245 connection()->SetServerReachable();
1246 connection()->UpdateConnectionStatus();
1247 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS
), FROM_HERE
);
1248 base::MessageLoop::current()->RunUntilIdle();
1251 // Tests that we don't crash trying to run two canaries at once if we receive
1252 // extra connection status change notifications. See crbug.com/190085.
1253 TEST_F(SyncSchedulerTest
, DoubleCanaryInConfigure
) {
1254 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
1255 .WillRepeatedly(DoAll(
1256 Invoke(sessions::test_util::SimulateConfigureConnectionFailure
),
1258 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
1259 connection()->SetServerNotReachable();
1260 connection()->UpdateConnectionStatus();
1262 ModelTypeSet
model_types(BOOKMARKS
);
1263 CallbackCounter ready_counter
;
1264 CallbackCounter retry_counter
;
1265 ConfigurationParams
params(
1266 GetUpdatesCallerInfo::RECONFIGURATION
,
1268 TypesToRoutingInfo(model_types
),
1269 base::Bind(&CallbackCounter::Callback
, base::Unretained(&ready_counter
)),
1270 base::Bind(&CallbackCounter::Callback
, base::Unretained(&retry_counter
)));
1271 scheduler()->ScheduleConfiguration(params
);
1273 scheduler()->OnConnectionStatusChange();
1274 scheduler()->OnConnectionStatusChange();
1276 PumpLoop(); // Run the nudge, that will fail and schedule a quick retry.
1279 TEST_F(SyncSchedulerTest
, PollFromCanaryAfterAuthError
) {
1280 SyncShareTimes times
;
1281 TimeDelta
poll(TimeDelta::FromMilliseconds(15));
1282 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
1284 ::testing::InSequence seq
;
1285 EXPECT_CALL(*syncer(), PollSyncShare(_
,_
))
1287 DoAll(Invoke(sessions::test_util::SimulatePollSuccess
),
1288 RecordSyncShareMultiple(×
, kMinNumSamples
)));
1290 connection()->SetServerStatus(HttpResponse::SYNC_AUTH_ERROR
);
1291 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
1293 // Run to wait for polling.
1296 // Normally OnCredentialsUpdated calls TryCanaryJob that doesn't run Poll,
1297 // but after poll finished with auth error from poll timer it should retry
1299 EXPECT_CALL(*syncer(), PollSyncShare(_
,_
))
1300 .WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollSuccess
),
1301 RecordSyncShare(×
)));
1302 scheduler()->OnCredentialsUpdated();
1303 connection()->SetServerStatus(HttpResponse::SERVER_CONNECTION_OK
);
1305 StopSyncScheduler();
1308 TEST_F(SyncSchedulerTest
, SuccessfulRetry
) {
1309 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
1311 SyncShareTimes times
;
1312 base::TimeDelta delay
= base::TimeDelta::FromMilliseconds(1);
1313 scheduler()->OnReceivedGuRetryDelay(delay
);
1314 EXPECT_EQ(delay
, GetRetryTimerDelay());
1316 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
1318 DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
1319 RecordSyncShare(×
)));
1321 // Run to wait for retrying.
1324 StopSyncScheduler();
1327 TEST_F(SyncSchedulerTest
, FailedRetry
) {
1328 UseMockDelayProvider();
1329 EXPECT_CALL(*delay(), GetDelay(_
))
1330 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(1)));
1332 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
1334 base::TimeDelta delay
= base::TimeDelta::FromMilliseconds(1);
1335 scheduler()->OnReceivedGuRetryDelay(delay
);
1337 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
1339 DoAll(Invoke(sessions::test_util::SimulateDownloadUpdatesFailed
),
1340 QuitLoopNowAction()));
1342 // Run to wait for retrying.
1345 EXPECT_TRUE(scheduler()->IsBackingOff());
1346 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
1348 DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
1349 QuitLoopNowAction()));
1351 // Run to wait for second retrying.
1354 StopSyncScheduler();
1357 ACTION_P2(VerifyRetryTimerDelay
, scheduler_test
, expected_delay
) {
1358 EXPECT_EQ(expected_delay
, scheduler_test
->GetRetryTimerDelay());
1361 TEST_F(SyncSchedulerTest
, ReceiveNewRetryDelay
) {
1362 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
1364 SyncShareTimes times
;
1365 base::TimeDelta delay1
= base::TimeDelta::FromMilliseconds(100);
1366 base::TimeDelta delay2
= base::TimeDelta::FromMilliseconds(200);
1368 scheduler()->ScheduleLocalRefreshRequest(zero(), ModelTypeSet(BOOKMARKS
),
1370 scheduler()->OnReceivedGuRetryDelay(delay1
);
1371 EXPECT_EQ(delay1
, GetRetryTimerDelay());
1373 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
1375 WithoutArgs(VerifyRetryTimerDelay(this, delay1
)),
1376 WithArg
<2>(sessions::test_util::SimulateGuRetryDelayCommand(delay2
)),
1377 RecordSyncShare(×
)));
1381 EXPECT_EQ(delay2
, GetRetryTimerDelay());
1383 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
1384 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
1385 RecordSyncShare(×
)));
1387 // Run to wait for retrying.
1390 StopSyncScheduler();
1393 } // namespace syncer