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
;
39 using sessions::SyncSession
;
40 using sessions::SyncSessionContext
;
41 using sync_pb::GetUpdatesCallerInfo
;
43 class MockSyncer
: public Syncer
{
46 MOCK_METHOD3(NormalSyncShare
, bool(ModelTypeSet
,
47 const sessions::NudgeTracker
&,
48 sessions::SyncSession
*));
49 MOCK_METHOD3(ConfigureSyncShare
,
51 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource
,
53 MOCK_METHOD2(PollSyncShare
, bool(ModelTypeSet
, sessions::SyncSession
*));
56 MockSyncer::MockSyncer()
59 typedef std::vector
<TimeTicks
> SyncShareTimes
;
62 // We use QuitNow() instead of Quit() as the latter may get stalled
63 // indefinitely in the presence of repeated timers with low delays
64 // and a slow test (e.g., ThrottlingDoesThrottle [which has a poll
65 // delay of 5ms] run under TSAN on the trybots).
66 base::MessageLoop::current()->QuitNow();
70 base::MessageLoop::current()->Run();
74 // Do it this way instead of RunAllPending to pump loop exactly once
75 // (necessary in the presence of timers; see comment in
77 base::MessageLoop::current()->PostTask(FROM_HERE
, base::Bind(&QuitLoopNow
));
81 void PumpLoopFor(base::TimeDelta time
) {
82 // Allow the loop to run for the specified amount of time.
83 base::MessageLoop::current()->PostDelayedTask(
84 FROM_HERE
, base::Bind(&QuitLoopNow
), time
);
88 ModelSafeRoutingInfo
TypesToRoutingInfo(ModelTypeSet types
) {
89 ModelSafeRoutingInfo routes
;
90 for (ModelTypeSet::Iterator iter
= types
.First(); iter
.Good(); iter
.Inc()) {
91 routes
[iter
.Get()] = GROUP_PASSIVE
;
96 // Convenient to use in tests wishing to analyze SyncShare calls over time.
97 static const size_t kMinNumSamples
= 5;
98 class SyncSchedulerTest
: public testing::Test
{
100 SyncSchedulerTest() : syncer_(NULL
), delay_(NULL
), weak_ptr_factory_(this) {}
102 class MockDelayProvider
: public BackoffDelayProvider
{
104 MockDelayProvider() : BackoffDelayProvider(
105 TimeDelta::FromSeconds(kInitialBackoffRetrySeconds
),
106 TimeDelta::FromSeconds(kInitialBackoffImmediateRetrySeconds
)) {
109 MOCK_METHOD1(GetDelay
, TimeDelta(const TimeDelta
&));
112 virtual void SetUp() {
114 syncer_
= new testing::StrictMock
<MockSyncer
>();
116 extensions_activity_
= new ExtensionsActivity();
118 routing_info_
[BOOKMARKS
] = GROUP_UI
;
119 routing_info_
[AUTOFILL
] = GROUP_DB
;
120 routing_info_
[THEMES
] = GROUP_UI
;
121 routing_info_
[NIGORI
] = GROUP_PASSIVE
;
124 workers_
.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_UI
)));
125 workers_
.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_DB
)));
126 workers_
.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_PASSIVE
)));
128 std::vector
<ModelSafeWorker
*> workers
;
129 for (std::vector
<scoped_refptr
<FakeModelWorker
> >::iterator it
=
130 workers_
.begin(); it
!= workers_
.end(); ++it
) {
131 workers
.push_back(it
->get());
134 connection_
.reset(new MockConnectionManager(directory(),
135 &cancelation_signal_
));
136 connection_
->SetServerReachable();
137 context_
.reset(new SyncSessionContext(
138 connection_
.get(), directory(), workers
,
139 extensions_activity_
.get(),
140 std::vector
<SyncEngineEventListener
*>(), NULL
, NULL
,
141 true, // enable keystore encryption
142 false, // force enable pre-commit GU avoidance
143 "fake_invalidator_client_id"));
144 context_
->set_routing_info(routing_info_
);
145 context_
->set_notifications_enabled(true);
146 context_
->set_account_name("Test");
148 new SyncSchedulerImpl("TestSyncScheduler",
149 BackoffDelayProvider::FromDefaults(),
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() {
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() {
185 void StartSyncScheduler(SyncScheduler::Mode mode
) {
186 scheduler()->Start(mode
);
189 // This stops the scheduler synchronously.
190 void StopSyncScheduler() {
191 base::MessageLoop::current()->PostTask(
193 base::Bind(&SyncSchedulerTest::DoQuitLoopNow
,
194 weak_ptr_factory_
.GetWeakPtr()));
198 bool RunAndGetBackoff() {
199 ModelTypeSet
nudge_types(BOOKMARKS
);
200 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
202 scheduler()->ScheduleLocalNudge(zero(), nudge_types
, FROM_HERE
);
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();
220 syncable::Directory
* directory() {
221 return dir_maker_
.directory();
224 base::MessageLoop loop_
;
225 TestDirectorySetterUpper dir_maker_
;
226 CancelationSignal cancelation_signal_
;
227 scoped_ptr
<MockConnectionManager
> connection_
;
228 scoped_ptr
<SyncSessionContext
> context_
;
229 scoped_ptr
<SyncSchedulerImpl
> scheduler_
;
231 MockDelayProvider
* delay_
;
232 std::vector
<scoped_refptr
<FakeModelWorker
> > workers_
;
233 scoped_refptr
<ExtensionsActivity
> extensions_activity_
;
234 ModelSafeRoutingInfo routing_info_
;
235 base::WeakPtrFactory
<SyncSchedulerTest
> weak_ptr_factory_
;
238 void RecordSyncShareImpl(SyncShareTimes
* times
) {
239 times
->push_back(TimeTicks::Now());
242 ACTION_P(RecordSyncShare
, times
) {
243 RecordSyncShareImpl(times
);
244 if (base::MessageLoop::current()->is_running())
249 ACTION_P2(RecordSyncShareMultiple
, times
, quit_after
) {
250 RecordSyncShareImpl(times
);
251 EXPECT_LE(times
->size(), quit_after
);
252 if (times
->size() >= quit_after
&&
253 base::MessageLoop::current()->is_running()) {
259 ACTION(AddFailureAndQuitLoopNow
) {
265 ACTION(QuitLoopNowAction
) {
270 // Test nudge scheduling.
271 TEST_F(SyncSchedulerTest
, Nudge
) {
272 SyncShareTimes times
;
273 ModelTypeSet
model_types(BOOKMARKS
);
275 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
276 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
277 RecordSyncShare(×
)))
278 .RetiresOnSaturation();
280 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
282 scheduler()->ScheduleLocalNudge(zero(), model_types
, FROM_HERE
);
285 Mock::VerifyAndClearExpectations(syncer());
287 // Make sure a second, later, nudge is unaffected by first (no coalescing).
288 SyncShareTimes times2
;
289 model_types
.Remove(BOOKMARKS
);
290 model_types
.Put(AUTOFILL
);
291 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
292 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
293 RecordSyncShare(×2
)));
294 scheduler()->ScheduleLocalNudge(zero(), model_types
, FROM_HERE
);
298 // Make sure a regular config command is scheduled fine in the absence of any
300 TEST_F(SyncSchedulerTest
, Config
) {
301 SyncShareTimes times
;
302 const ModelTypeSet
model_types(BOOKMARKS
);
304 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
305 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess
),
306 RecordSyncShare(×
)));
308 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
310 CallbackCounter counter
;
311 ConfigurationParams
params(
312 GetUpdatesCallerInfo::RECONFIGURATION
,
314 TypesToRoutingInfo(model_types
),
315 base::Bind(&CallbackCounter::Callback
, base::Unretained(&counter
)));
316 ASSERT_TRUE(scheduler()->ScheduleConfiguration(params
));
317 ASSERT_EQ(1, counter
.times_called());
320 // Simulate a failure and make sure the config request is retried.
321 TEST_F(SyncSchedulerTest
, ConfigWithBackingOff
) {
322 UseMockDelayProvider();
323 EXPECT_CALL(*delay(), GetDelay(_
))
324 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(1)));
325 SyncShareTimes times
;
326 const ModelTypeSet
model_types(BOOKMARKS
);
328 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
330 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
331 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed
),
332 RecordSyncShare(×
)));
334 CallbackCounter counter
;
335 ConfigurationParams
params(
336 GetUpdatesCallerInfo::RECONFIGURATION
,
338 TypesToRoutingInfo(model_types
),
339 base::Bind(&CallbackCounter::Callback
, base::Unretained(&counter
)));
340 ASSERT_FALSE(scheduler()->ScheduleConfiguration(params
));
341 ASSERT_EQ(0, counter
.times_called());
343 Mock::VerifyAndClearExpectations(syncer());
345 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
346 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess
),
347 RecordSyncShare(×
)));
350 ASSERT_EQ(1, counter
.times_called());
353 // Issue a nudge when the config has failed. Make sure both the config and
354 // nudge are executed.
355 TEST_F(SyncSchedulerTest
, NudgeWithConfigWithBackingOff
) {
356 const ModelTypeSet
model_types(BOOKMARKS
);
357 UseMockDelayProvider();
358 EXPECT_CALL(*delay(), GetDelay(_
))
359 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(50)));
360 SyncShareTimes times
;
362 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
364 // Request a configure and make sure it fails.
365 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
366 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed
),
367 RecordSyncShare(×
)));
368 CallbackCounter counter
;
369 ConfigurationParams
params(
370 GetUpdatesCallerInfo::RECONFIGURATION
,
372 TypesToRoutingInfo(model_types
),
373 base::Bind(&CallbackCounter::Callback
, base::Unretained(&counter
)));
374 ASSERT_FALSE(scheduler()->ScheduleConfiguration(params
));
375 ASSERT_EQ(0, counter
.times_called());
376 Mock::VerifyAndClearExpectations(syncer());
378 // Ask for a nudge while dealing with repeated configure failure.
379 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
380 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed
),
381 RecordSyncShare(×
)));
382 scheduler()->ScheduleLocalNudge(zero(), model_types
, FROM_HERE
);
384 // Note that we're not RunLoop()ing for the NUDGE we just scheduled, but
385 // for the first retry attempt from the config job (after
386 // waiting ~+/- 50ms).
387 Mock::VerifyAndClearExpectations(syncer());
388 ASSERT_EQ(0, counter
.times_called());
390 // Let the next configure retry succeed.
391 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
392 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess
),
393 RecordSyncShare(×
)));
396 // Now change the mode so nudge can execute.
397 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
398 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
399 RecordSyncShare(×
)));
400 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
403 // Test that nudges are coalesced.
404 TEST_F(SyncSchedulerTest
, NudgeCoalescing
) {
405 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
407 SyncShareTimes times
;
408 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
409 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
410 RecordSyncShare(×
)));
411 const ModelTypeSet
types1(BOOKMARKS
), types2(AUTOFILL
), types3(THEMES
);
412 TimeDelta delay
= zero();
413 TimeTicks optimal_time
= TimeTicks::Now() + delay
;
414 scheduler()->ScheduleLocalNudge(delay
, types1
, FROM_HERE
);
415 scheduler()->ScheduleLocalNudge(zero(), types2
, FROM_HERE
);
418 ASSERT_EQ(1U, times
.size());
419 EXPECT_GE(times
[0], optimal_time
);
421 Mock::VerifyAndClearExpectations(syncer());
423 SyncShareTimes times2
;
424 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
425 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
426 RecordSyncShare(×2
)));
427 scheduler()->ScheduleLocalNudge(zero(), types3
, FROM_HERE
);
431 // Test that nudges are coalesced.
432 TEST_F(SyncSchedulerTest
, NudgeCoalescingWithDifferentTimings
) {
433 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
435 SyncShareTimes times
;
436 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
437 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
438 RecordSyncShare(×
)));
439 ModelTypeSet
types1(BOOKMARKS
), types2(AUTOFILL
), types3
;
441 // Create a huge time delay.
442 TimeDelta delay
= TimeDelta::FromDays(1);
444 scheduler()->ScheduleLocalNudge(delay
, types1
, FROM_HERE
);
445 scheduler()->ScheduleLocalNudge(zero(), types2
, FROM_HERE
);
447 TimeTicks min_time
= TimeTicks::Now();
448 TimeTicks max_time
= TimeTicks::Now() + delay
;
451 Mock::VerifyAndClearExpectations(syncer());
453 // Make sure the sync happened at the right time.
454 ASSERT_EQ(1U, times
.size());
455 EXPECT_GE(times
[0], min_time
);
456 EXPECT_LE(times
[0], max_time
);
459 // Test nudge scheduling.
460 TEST_F(SyncSchedulerTest
, NudgeWithStates
) {
461 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
463 SyncShareTimes times1
;
464 ObjectIdInvalidationMap invalidations1
=
465 BuildInvalidationMap(BOOKMARKS
, 10, "test");
466 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
467 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
468 RecordSyncShare(×1
)))
469 .RetiresOnSaturation();
470 scheduler()->ScheduleInvalidationNudge(zero(), invalidations1
, FROM_HERE
);
473 Mock::VerifyAndClearExpectations(syncer());
475 // Make sure a second, later, nudge is unaffected by first (no coalescing).
476 SyncShareTimes times2
;
477 ObjectIdInvalidationMap invalidations2
=
478 BuildInvalidationMap(AUTOFILL
, 10, "test2");
479 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
480 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
481 RecordSyncShare(×2
)));
482 scheduler()->ScheduleInvalidationNudge(zero(), invalidations2
, FROM_HERE
);
486 // Test that polling works as expected.
487 TEST_F(SyncSchedulerTest
, Polling
) {
488 SyncShareTimes times
;
489 TimeDelta
poll_interval(TimeDelta::FromMilliseconds(30));
490 EXPECT_CALL(*syncer(), PollSyncShare(_
,_
)).Times(AtLeast(kMinNumSamples
))
491 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulatePollSuccess
),
492 RecordSyncShareMultiple(×
, kMinNumSamples
)));
494 scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval
);
496 TimeTicks optimal_start
= TimeTicks::Now() + poll_interval
;
497 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
499 // Run again to wait for polling.
503 AnalyzePollRun(times
, kMinNumSamples
, optimal_start
, poll_interval
);
506 // Test that the short poll interval is used.
507 TEST_F(SyncSchedulerTest
, PollNotificationsDisabled
) {
508 SyncShareTimes times
;
509 TimeDelta
poll_interval(TimeDelta::FromMilliseconds(30));
510 EXPECT_CALL(*syncer(), PollSyncShare(_
,_
)).Times(AtLeast(kMinNumSamples
))
511 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulatePollSuccess
),
512 RecordSyncShareMultiple(×
, kMinNumSamples
)));
514 scheduler()->OnReceivedShortPollIntervalUpdate(poll_interval
);
515 scheduler()->SetNotificationsEnabled(false);
517 TimeTicks optimal_start
= TimeTicks::Now() + poll_interval
;
518 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
520 // Run again to wait for polling.
524 AnalyzePollRun(times
, kMinNumSamples
, optimal_start
, poll_interval
);
527 // Test that polling intervals are updated when needed.
528 TEST_F(SyncSchedulerTest
, PollIntervalUpdate
) {
529 SyncShareTimes times
;
530 TimeDelta
poll1(TimeDelta::FromMilliseconds(120));
531 TimeDelta
poll2(TimeDelta::FromMilliseconds(30));
532 scheduler()->OnReceivedLongPollIntervalUpdate(poll1
);
533 EXPECT_CALL(*syncer(), PollSyncShare(_
,_
)).Times(AtLeast(kMinNumSamples
))
536 sessions::test_util::SimulatePollIntervalUpdate(poll2
)),
539 DoAll(Invoke(sessions::test_util::SimulatePollSuccess
),
541 RecordSyncShareMultiple(×
, kMinNumSamples
))));
543 TimeTicks optimal_start
= TimeTicks::Now() + poll1
+ poll2
;
544 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
546 // Run again to wait for polling.
550 AnalyzePollRun(times
, kMinNumSamples
, optimal_start
, poll2
);
553 // Test that the sessions commit delay is updated when needed.
554 TEST_F(SyncSchedulerTest
, SessionsCommitDelay
) {
555 SyncShareTimes times
;
556 TimeDelta
delay1(TimeDelta::FromMilliseconds(120));
557 TimeDelta
delay2(TimeDelta::FromMilliseconds(30));
558 scheduler()->OnReceivedSessionsCommitDelay(delay1
);
560 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
564 sessions::test_util::SimulateSessionsCommitDelayUpdate(
566 Invoke(sessions::test_util::SimulateNormalSuccess
),
567 QuitLoopNowAction()));
569 EXPECT_EQ(delay1
, scheduler()->GetSessionsCommitDelay());
570 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
572 EXPECT_EQ(delay1
, scheduler()->GetSessionsCommitDelay());
573 const ModelTypeSet
model_types(BOOKMARKS
);
574 scheduler()->ScheduleLocalNudge(zero(), model_types
, FROM_HERE
);
577 EXPECT_EQ(delay2
, scheduler()->GetSessionsCommitDelay());
581 // Test that no syncing occurs when throttled.
582 TEST_F(SyncSchedulerTest
, ThrottlingDoesThrottle
) {
583 const ModelTypeSet
types(BOOKMARKS
);
584 TimeDelta
poll(TimeDelta::FromMilliseconds(5));
585 TimeDelta
throttle(TimeDelta::FromMinutes(10));
586 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
588 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
590 WithArg
<2>(sessions::test_util::SimulateThrottled(throttle
)),
592 .WillRepeatedly(AddFailureAndQuitLoopNow());
594 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
596 scheduler()->ScheduleLocalNudge(
597 TimeDelta::FromMicroseconds(1), types
, FROM_HERE
);
600 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
602 CallbackCounter counter
;
603 ConfigurationParams
params(
604 GetUpdatesCallerInfo::RECONFIGURATION
,
606 TypesToRoutingInfo(types
),
607 base::Bind(&CallbackCounter::Callback
, base::Unretained(&counter
)));
608 ASSERT_FALSE(scheduler()->ScheduleConfiguration(params
));
609 ASSERT_EQ(0, counter
.times_called());
612 TEST_F(SyncSchedulerTest
, ThrottlingExpiresFromPoll
) {
613 SyncShareTimes times
;
614 TimeDelta
poll(TimeDelta::FromMilliseconds(15));
615 TimeDelta
throttle1(TimeDelta::FromMilliseconds(150));
616 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
618 ::testing::InSequence seq
;
619 EXPECT_CALL(*syncer(), PollSyncShare(_
,_
))
621 WithArg
<1>(sessions::test_util::SimulateThrottled(throttle1
)),
623 .RetiresOnSaturation();
624 EXPECT_CALL(*syncer(), PollSyncShare(_
,_
))
625 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulatePollSuccess
),
626 RecordSyncShareMultiple(×
, kMinNumSamples
)));
628 TimeTicks optimal_start
= TimeTicks::Now() + poll
+ throttle1
;
629 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
631 // Run again to wait for polling.
635 AnalyzePollRun(times
, kMinNumSamples
, optimal_start
, poll
);
638 TEST_F(SyncSchedulerTest
, ThrottlingExpiresFromNudge
) {
639 SyncShareTimes times
;
640 TimeDelta
poll(TimeDelta::FromDays(1));
641 TimeDelta
throttle1(TimeDelta::FromMilliseconds(150));
642 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
644 ::testing::InSequence seq
;
645 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
647 WithArg
<2>(sessions::test_util::SimulateThrottled(throttle1
)),
649 .RetiresOnSaturation();
650 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
651 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
652 QuitLoopNowAction()));
654 const ModelTypeSet
types(BOOKMARKS
);
655 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
656 scheduler()->ScheduleLocalNudge(zero(), types
, FROM_HERE
);
659 EXPECT_TRUE(scheduler()->IsCurrentlyThrottled());
661 EXPECT_FALSE(scheduler()->IsCurrentlyThrottled());
666 TEST_F(SyncSchedulerTest
, ThrottlingExpiresFromConfigure
) {
667 SyncShareTimes times
;
668 TimeDelta
poll(TimeDelta::FromDays(1));
669 TimeDelta
throttle1(TimeDelta::FromMilliseconds(150));
670 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
672 ::testing::InSequence seq
;
673 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
675 WithArg
<2>(sessions::test_util::SimulateThrottled(throttle1
)),
677 .RetiresOnSaturation();
678 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
679 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess
),
680 QuitLoopNowAction()));
682 const ModelTypeSet
types(BOOKMARKS
);
683 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
685 CallbackCounter counter
;
686 ConfigurationParams
params(
687 GetUpdatesCallerInfo::RECONFIGURATION
,
689 TypesToRoutingInfo(types
),
690 base::Bind(&CallbackCounter::Callback
, base::Unretained(&counter
)));
691 EXPECT_FALSE(scheduler()->ScheduleConfiguration(params
));
692 EXPECT_EQ(0, counter
.times_called());
693 EXPECT_TRUE(scheduler()->IsCurrentlyThrottled());
696 EXPECT_FALSE(scheduler()->IsCurrentlyThrottled());
701 TEST_F(SyncSchedulerTest
, TypeThrottlingBlocksNudge
) {
702 UseMockDelayProvider();
703 EXPECT_CALL(*delay(), GetDelay(_
))
704 .WillRepeatedly(Return(zero()));
706 TimeDelta
poll(TimeDelta::FromDays(1));
707 TimeDelta
throttle1(TimeDelta::FromSeconds(60));
708 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
710 const ModelTypeSet
types(BOOKMARKS
);
712 ::testing::InSequence seq
;
713 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
716 sessions::test_util::SimulateTypesThrottled(types
, throttle1
)),
718 .RetiresOnSaturation();
720 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
721 scheduler()->ScheduleLocalNudge(zero(), types
, FROM_HERE
);
723 EXPECT_TRUE(GetThrottledTypes().HasAll(types
));
725 // This won't cause a sync cycle because the types are throttled.
726 scheduler()->ScheduleLocalNudge(zero(), types
, FROM_HERE
);
732 TEST_F(SyncSchedulerTest
, TypeThrottlingDoesBlockOtherSources
) {
733 UseMockDelayProvider();
734 EXPECT_CALL(*delay(), GetDelay(_
))
735 .WillRepeatedly(Return(zero()));
737 SyncShareTimes times
;
738 TimeDelta
poll(TimeDelta::FromDays(1));
739 TimeDelta
throttle1(TimeDelta::FromSeconds(60));
740 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
742 const ModelTypeSet
throttled_types(BOOKMARKS
);
743 const ModelTypeSet
unthrottled_types(PREFERENCES
);
745 ::testing::InSequence seq
;
746 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
749 sessions::test_util::SimulateTypesThrottled(
750 throttled_types
, throttle1
)),
752 .RetiresOnSaturation();
754 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
755 scheduler()->ScheduleLocalNudge(zero(), throttled_types
, FROM_HERE
);
757 EXPECT_TRUE(GetThrottledTypes().HasAll(throttled_types
));
759 // Ignore invalidations for throttled types.
760 ObjectIdInvalidationMap invalidations
=
761 BuildInvalidationMap(BOOKMARKS
, 10, "test");
762 scheduler()->ScheduleInvalidationNudge(zero(), invalidations
, FROM_HERE
);
765 // Ignore refresh requests for throttled types.
766 scheduler()->ScheduleLocalRefreshRequest(zero(), throttled_types
, FROM_HERE
);
769 Mock::VerifyAndClearExpectations(syncer());
771 // Local nudges for non-throttled types will trigger a sync.
772 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
773 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
774 RecordSyncShare(×
)));
775 scheduler()->ScheduleLocalNudge(zero(), unthrottled_types
, FROM_HERE
);
777 Mock::VerifyAndClearExpectations(syncer());
782 // Test nudges / polls don't run in config mode and config tasks do.
783 TEST_F(SyncSchedulerTest
, ConfigurationMode
) {
784 TimeDelta
poll(TimeDelta::FromMilliseconds(15));
785 SyncShareTimes times
;
786 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
788 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
790 const ModelTypeSet
nudge_types(AUTOFILL
);
791 scheduler()->ScheduleLocalNudge(zero(), nudge_types
, FROM_HERE
);
792 scheduler()->ScheduleLocalNudge(zero(), nudge_types
, FROM_HERE
);
794 const ModelTypeSet
config_types(BOOKMARKS
);
796 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
797 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureSuccess
),
798 RecordSyncShare(×
)))
799 .RetiresOnSaturation();
800 CallbackCounter counter
;
801 ConfigurationParams
params(
802 GetUpdatesCallerInfo::RECONFIGURATION
,
804 TypesToRoutingInfo(config_types
),
805 base::Bind(&CallbackCounter::Callback
, base::Unretained(&counter
)));
806 ASSERT_TRUE(scheduler()->ScheduleConfiguration(params
));
807 ASSERT_EQ(1, counter
.times_called());
808 Mock::VerifyAndClearExpectations(syncer());
810 // Switch to NORMAL_MODE to ensure NUDGES were properly saved and run.
811 scheduler()->OnReceivedLongPollIntervalUpdate(TimeDelta::FromDays(1));
812 SyncShareTimes times2
;
813 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
814 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
815 RecordSyncShare(×2
)));
817 // TODO(tim): Figure out how to remove this dangerous need to reset
818 // routing info between mode switches.
819 context()->set_routing_info(routing_info());
820 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
825 class BackoffTriggersSyncSchedulerTest
: public SyncSchedulerTest
{
826 virtual void SetUp() {
827 SyncSchedulerTest::SetUp();
828 UseMockDelayProvider();
829 EXPECT_CALL(*delay(), GetDelay(_
))
830 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(1)));
833 virtual void TearDown() {
835 SyncSchedulerTest::TearDown();
839 // Have the sycner fail during commit. Expect that the scheduler enters
841 TEST_F(BackoffTriggersSyncSchedulerTest
, FailCommitOnce
) {
842 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
843 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed
),
844 QuitLoopNowAction()));
845 EXPECT_TRUE(RunAndGetBackoff());
848 // Have the syncer fail during download updates and succeed on the first
849 // retry. Expect that this clears the backoff state.
850 TEST_F(BackoffTriggersSyncSchedulerTest
, FailDownloadOnceThenSucceed
) {
851 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
853 Invoke(sessions::test_util::SimulateDownloadUpdatesFailed
),
855 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
856 QuitLoopNowAction()));
857 EXPECT_FALSE(RunAndGetBackoff());
860 // Have the syncer fail during commit and succeed on the first retry. Expect
861 // that this clears the backoff state.
862 TEST_F(BackoffTriggersSyncSchedulerTest
, FailCommitOnceThenSucceed
) {
863 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
865 Invoke(sessions::test_util::SimulateCommitFailed
),
867 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
868 QuitLoopNowAction()));
869 EXPECT_FALSE(RunAndGetBackoff());
872 // Have the syncer fail to download updates and fail again on the retry.
873 // Expect this will leave the scheduler in backoff.
874 TEST_F(BackoffTriggersSyncSchedulerTest
, FailDownloadTwice
) {
875 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
877 Invoke(sessions::test_util::SimulateDownloadUpdatesFailed
),
879 .WillRepeatedly(DoAll(
880 Invoke(sessions::test_util::SimulateDownloadUpdatesFailed
),
881 QuitLoopNowAction()));
882 EXPECT_TRUE(RunAndGetBackoff());
885 // Have the syncer fail to get the encryption key yet succeed in downloading
886 // updates. Expect this will leave the scheduler in backoff.
887 TEST_F(BackoffTriggersSyncSchedulerTest
, FailGetEncryptionKey
) {
888 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
890 Invoke(sessions::test_util::SimulateGetEncryptionKeyFailed
),
892 .WillRepeatedly(DoAll(
893 Invoke(sessions::test_util::SimulateGetEncryptionKeyFailed
),
894 QuitLoopNowAction()));
895 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
897 ModelTypeSet
types(BOOKMARKS
);
898 CallbackCounter counter
;
899 ConfigurationParams
params(
900 GetUpdatesCallerInfo::RECONFIGURATION
,
902 TypesToRoutingInfo(types
),
903 base::Bind(&CallbackCounter::Callback
, base::Unretained(&counter
)));
904 scheduler()->ScheduleConfiguration(params
);
907 EXPECT_TRUE(scheduler()->IsBackingOff());
910 // Test that no polls or extraneous nudges occur when in backoff.
911 TEST_F(SyncSchedulerTest
, BackoffDropsJobs
) {
912 SyncShareTimes times
;
913 TimeDelta
poll(TimeDelta::FromMilliseconds(5));
914 const ModelTypeSet
types(BOOKMARKS
);
915 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
916 UseMockDelayProvider();
918 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
919 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed
),
920 RecordSyncShareMultiple(×
, 1U)));
921 EXPECT_CALL(*delay(), GetDelay(_
)).
922 WillRepeatedly(Return(TimeDelta::FromDays(1)));
924 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
926 // This nudge should fail and put us into backoff. Thanks to our mock
927 // GetDelay() setup above, this will be a long backoff.
928 scheduler()->ScheduleLocalNudge(zero(), types
, FROM_HERE
);
931 // From this point forward, no SyncShare functions should be invoked.
932 Mock::VerifyAndClearExpectations(syncer());
934 // Wait a while (10x poll interval) so a few poll jobs will be attempted.
935 PumpLoopFor(poll
* 10);
937 // Try (and fail) to schedule a nudge.
938 scheduler()->ScheduleLocalNudge(
939 base::TimeDelta::FromMilliseconds(1),
943 Mock::VerifyAndClearExpectations(syncer());
944 Mock::VerifyAndClearExpectations(delay());
946 EXPECT_CALL(*delay(), GetDelay(_
)).Times(0);
948 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
950 CallbackCounter counter
;
951 ConfigurationParams
params(
952 GetUpdatesCallerInfo::RECONFIGURATION
,
954 TypesToRoutingInfo(types
),
955 base::Bind(&CallbackCounter::Callback
, base::Unretained(&counter
)));
956 ASSERT_FALSE(scheduler()->ScheduleConfiguration(params
));
957 ASSERT_EQ(0, counter
.times_called());
960 // Test that backoff is shaping traffic properly with consecutive errors.
961 TEST_F(SyncSchedulerTest
, BackoffElevation
) {
962 SyncShareTimes times
;
963 UseMockDelayProvider();
965 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
)).Times(kMinNumSamples
)
966 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateCommitFailed
),
967 RecordSyncShareMultiple(×
, kMinNumSamples
)));
969 const TimeDelta first
= TimeDelta::FromSeconds(kInitialBackoffRetrySeconds
);
970 const TimeDelta second
= TimeDelta::FromMilliseconds(2);
971 const TimeDelta third
= TimeDelta::FromMilliseconds(3);
972 const TimeDelta fourth
= TimeDelta::FromMilliseconds(4);
973 const TimeDelta fifth
= TimeDelta::FromMilliseconds(5);
974 const TimeDelta sixth
= TimeDelta::FromDays(1);
976 EXPECT_CALL(*delay(), GetDelay(first
)).WillOnce(Return(second
))
977 .RetiresOnSaturation();
978 EXPECT_CALL(*delay(), GetDelay(second
)).WillOnce(Return(third
))
979 .RetiresOnSaturation();
980 EXPECT_CALL(*delay(), GetDelay(third
)).WillOnce(Return(fourth
))
981 .RetiresOnSaturation();
982 EXPECT_CALL(*delay(), GetDelay(fourth
)).WillOnce(Return(fifth
))
983 .RetiresOnSaturation();
984 EXPECT_CALL(*delay(), GetDelay(fifth
)).WillOnce(Return(sixth
));
986 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
988 // Run again with a nudge.
989 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS
), FROM_HERE
);
992 ASSERT_EQ(kMinNumSamples
, times
.size());
993 EXPECT_GE(times
[1] - times
[0], second
);
994 EXPECT_GE(times
[2] - times
[1], third
);
995 EXPECT_GE(times
[3] - times
[2], fourth
);
996 EXPECT_GE(times
[4] - times
[3], fifth
);
999 // Test that things go back to normal once a retry makes forward progress.
1000 TEST_F(SyncSchedulerTest
, BackoffRelief
) {
1001 SyncShareTimes times
;
1002 const TimeDelta
poll(TimeDelta::FromMilliseconds(10));
1003 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
1004 UseMockDelayProvider();
1006 const TimeDelta backoff
= TimeDelta::FromMilliseconds(5);
1007 EXPECT_CALL(*delay(), GetDelay(_
)).WillOnce(Return(backoff
));
1009 // Optimal start for the post-backoff poll party.
1010 TimeTicks optimal_start
= TimeTicks::Now();
1011 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
1013 // Kick off the test with a failed nudge.
1014 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
1015 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed
),
1016 RecordSyncShare(×
)));
1017 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS
), FROM_HERE
);
1019 Mock::VerifyAndClearExpectations(syncer());
1020 TimeTicks optimal_job_time
= optimal_start
;
1021 ASSERT_EQ(1U, times
.size());
1022 EXPECT_GE(times
[0], optimal_job_time
);
1024 // The retry succeeds.
1025 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
1027 Invoke(sessions::test_util::SimulateNormalSuccess
),
1028 RecordSyncShare(×
)));
1030 Mock::VerifyAndClearExpectations(syncer());
1031 optimal_job_time
= optimal_job_time
+ backoff
;
1032 ASSERT_EQ(2U, times
.size());
1033 EXPECT_GE(times
[1], optimal_job_time
);
1035 // Now let the Poll timer do its thing.
1036 EXPECT_CALL(*syncer(), PollSyncShare(_
,_
))
1037 .WillRepeatedly(DoAll(
1038 Invoke(sessions::test_util::SimulatePollSuccess
),
1039 RecordSyncShareMultiple(×
, kMinNumSamples
)));
1041 Mock::VerifyAndClearExpectations(syncer());
1042 ASSERT_EQ(kMinNumSamples
, times
.size());
1043 for (size_t i
= 2; i
< times
.size(); i
++) {
1044 optimal_job_time
= optimal_job_time
+ poll
;
1045 SCOPED_TRACE(testing::Message() << "SyncShare # (" << i
<< ")");
1046 EXPECT_GE(times
[i
], optimal_job_time
);
1049 StopSyncScheduler();
1052 // Test that poll failures are ignored. They should have no effect on
1053 // subsequent poll attempts, nor should they trigger a backoff/retry.
1054 TEST_F(SyncSchedulerTest
, TransientPollFailure
) {
1055 SyncShareTimes times
;
1056 const TimeDelta
poll_interval(TimeDelta::FromMilliseconds(1));
1057 scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval
);
1058 UseMockDelayProvider(); // Will cause test failure if backoff is initiated.
1060 EXPECT_CALL(*syncer(), PollSyncShare(_
,_
))
1061 .WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollFailed
),
1062 RecordSyncShare(×
)))
1063 .WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollSuccess
),
1064 RecordSyncShare(×
)));
1066 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
1068 // Run the unsucessful poll. The failed poll should not trigger backoff.
1070 EXPECT_FALSE(scheduler()->IsBackingOff());
1072 // Run the successful poll.
1074 EXPECT_FALSE(scheduler()->IsBackingOff());
1077 // Test that starting the syncer thread without a valid connection doesn't
1078 // break things when a connection is detected.
1079 TEST_F(SyncSchedulerTest
, StartWhenNotConnected
) {
1080 connection()->SetServerNotReachable();
1081 connection()->UpdateConnectionStatus();
1082 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
1083 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConnectionFailure
),
1085 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
1087 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
1089 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS
), FROM_HERE
);
1090 // Should save the nudge for until after the server is reachable.
1091 base::MessageLoop::current()->RunUntilIdle();
1093 scheduler()->OnConnectionStatusChange();
1094 connection()->SetServerReachable();
1095 connection()->UpdateConnectionStatus();
1096 base::MessageLoop::current()->RunUntilIdle();
1099 TEST_F(SyncSchedulerTest
, ServerConnectionChangeDuringBackoff
) {
1100 UseMockDelayProvider();
1101 EXPECT_CALL(*delay(), GetDelay(_
))
1102 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(0)));
1104 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
1105 connection()->SetServerNotReachable();
1106 connection()->UpdateConnectionStatus();
1108 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
1109 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConnectionFailure
),
1111 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
1114 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS
), FROM_HERE
);
1116 PumpLoop(); // Run the nudge, that will fail and schedule a quick retry.
1117 ASSERT_TRUE(scheduler()->IsBackingOff());
1119 // Before we run the scheduled canary, trigger a server connection change.
1120 scheduler()->OnConnectionStatusChange();
1121 connection()->SetServerReachable();
1122 connection()->UpdateConnectionStatus();
1123 base::MessageLoop::current()->RunUntilIdle();
1126 // This was supposed to test the scenario where we receive a nudge while a
1127 // connection change canary is scheduled, but has not run yet. Since we've made
1128 // the connection change canary synchronous, this is no longer possible.
1129 TEST_F(SyncSchedulerTest
, ConnectionChangeCanaryPreemptedByNudge
) {
1130 UseMockDelayProvider();
1131 EXPECT_CALL(*delay(), GetDelay(_
))
1132 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(0)));
1134 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
1135 connection()->SetServerNotReachable();
1136 connection()->UpdateConnectionStatus();
1138 EXPECT_CALL(*syncer(), NormalSyncShare(_
,_
,_
))
1139 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConnectionFailure
),
1141 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
1143 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess
),
1144 QuitLoopNowAction()));
1146 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS
), FROM_HERE
);
1148 PumpLoop(); // Run the nudge, that will fail and schedule a quick retry.
1149 ASSERT_TRUE(scheduler()->IsBackingOff());
1151 // Before we run the scheduled canary, trigger a server connection change.
1152 scheduler()->OnConnectionStatusChange();
1153 connection()->SetServerReachable();
1154 connection()->UpdateConnectionStatus();
1155 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS
), FROM_HERE
);
1156 base::MessageLoop::current()->RunUntilIdle();
1159 // Tests that we don't crash trying to run two canaries at once if we receive
1160 // extra connection status change notifications. See crbug.com/190085.
1161 TEST_F(SyncSchedulerTest
, DoubleCanaryInConfigure
) {
1162 EXPECT_CALL(*syncer(), ConfigureSyncShare(_
,_
,_
))
1163 .WillRepeatedly(DoAll(
1164 Invoke(sessions::test_util::SimulateConfigureConnectionFailure
),
1166 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
1167 connection()->SetServerNotReachable();
1168 connection()->UpdateConnectionStatus();
1170 ModelTypeSet
model_types(BOOKMARKS
);
1171 CallbackCounter counter
;
1172 ConfigurationParams
params(
1173 GetUpdatesCallerInfo::RECONFIGURATION
,
1175 TypesToRoutingInfo(model_types
),
1176 base::Bind(&CallbackCounter::Callback
, base::Unretained(&counter
)));
1177 scheduler()->ScheduleConfiguration(params
);
1179 scheduler()->OnConnectionStatusChange();
1180 scheduler()->OnConnectionStatusChange();
1182 PumpLoop(); // Run the nudge, that will fail and schedule a quick retry.
1185 TEST_F(SyncSchedulerTest
, PollFromCanaryAfterAuthError
) {
1186 SyncShareTimes times
;
1187 TimeDelta
poll(TimeDelta::FromMilliseconds(15));
1188 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
1190 ::testing::InSequence seq
;
1191 EXPECT_CALL(*syncer(), PollSyncShare(_
,_
))
1192 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulatePollSuccess
),
1193 RecordSyncShareMultiple(×
, kMinNumSamples
)));
1195 connection()->SetServerStatus(HttpResponse::SYNC_AUTH_ERROR
);
1196 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
1198 // Run to wait for polling.
1201 // Normally OnCredentialsUpdated calls TryCanaryJob that doesn't run Poll,
1202 // but after poll finished with auth error from poll timer it should retry
1204 EXPECT_CALL(*syncer(), PollSyncShare(_
,_
))
1205 .WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollSuccess
),
1206 RecordSyncShare(×
)));
1207 scheduler()->OnCredentialsUpdated();
1208 connection()->SetServerStatus(HttpResponse::SERVER_CONNECTION_OK
);
1209 StopSyncScheduler();
1212 } // namespace syncer