Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / sync / engine / sync_scheduler_unittest.cc
blobc231087f9c98683ed81d5094847ed1aa9ba65b39
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*));
57 MockSyncer::MockSyncer()
58 : Syncer(NULL) {}
60 typedef std::vector<TimeTicks> SyncShareTimes;
62 void QuitLoopNow() {
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();
70 void RunLoop() {
71 base::MessageLoop::current()->Run();
74 void PumpLoop() {
75 // Do it this way instead of RunAllPending to pump loop exactly once
76 // (necessary in the presence of timers; see comment in
77 // QuitLoopNow).
78 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&QuitLoopNow));
79 RunLoop();
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);
86 RunLoop();
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;
94 return routes;
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 {
100 public:
101 SyncSchedulerTest() : syncer_(NULL), delay_(NULL), weak_ptr_factory_(this) {}
103 class MockDelayProvider : public BackoffDelayProvider {
104 public:
105 MockDelayProvider() : BackoffDelayProvider(
106 TimeDelta::FromSeconds(kInitialBackoffRetrySeconds),
107 TimeDelta::FromSeconds(kInitialBackoffImmediateRetrySeconds)) {
110 MOCK_METHOD1(GetDelay, TimeDelta(const TimeDelta&));
113 virtual void SetUp() {
114 dir_maker_.SetUp();
115 syncer_ = new testing::StrictMock<MockSyncer>();
116 delay_ = NULL;
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;
124 workers_.clear();
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");
146 scheduler_.reset(
147 new SyncSchedulerImpl("TestSyncScheduler",
148 BackoffDelayProvider::FromDefaults(),
149 context(),
150 syncer_));
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() {
164 PumpLoop();
165 scheduler_.reset();
166 PumpLoop();
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() {
181 QuitLoopNow();
184 void StartSyncScheduler(SyncScheduler::Mode mode) {
185 scheduler()->Start(mode);
188 // This stops the scheduler synchronously.
189 void StopSyncScheduler() {
190 base::MessageLoop::current()->PostTask(
191 FROM_HERE,
192 base::Bind(&SyncSchedulerTest::DoQuitLoopNow,
193 weak_ptr_factory_.GetWeakPtr()));
194 RunLoop();
197 bool RunAndGetBackoff() {
198 ModelTypeSet nudge_types(BOOKMARKS);
199 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
201 scheduler()->ScheduleLocalNudge(zero(), nudge_types, FROM_HERE);
202 RunLoop();
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();
223 private:
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_;
235 MockSyncer* syncer_;
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())
250 QuitLoopNow();
251 return true;
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()) {
259 QuitLoopNow();
261 return true;
264 ACTION_P(StopScheduler, scheduler) {
265 scheduler->Stop();
268 ACTION(AddFailureAndQuitLoopNow) {
269 ADD_FAILURE();
270 QuitLoopNow();
271 return true;
274 ACTION(QuitLoopNowAction) {
275 QuitLoopNow();
276 return true;
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(&times)))
287 .RetiresOnSaturation();
289 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
291 scheduler()->ScheduleLocalNudge(zero(), model_types, FROM_HERE);
292 RunLoop();
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(&times2)));
303 scheduler()->ScheduleLocalNudge(zero(), model_types, FROM_HERE);
304 RunLoop();
307 // Make sure a regular config command is scheduled fine in the absence of any
308 // errors.
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(&times)));
317 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
319 CallbackCounter ready_counter;
320 CallbackCounter retry_counter;
321 ConfigurationParams params(
322 GetUpdatesCallerInfo::RECONFIGURATION,
323 model_types,
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);
328 PumpLoop();
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(&times)))
346 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateConfigureFailed),
347 RecordSyncShare(&times)));
349 CallbackCounter ready_counter;
350 CallbackCounter retry_counter;
351 ConfigurationParams params(
352 GetUpdatesCallerInfo::RECONFIGURATION,
353 model_types,
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);
358 RunLoop();
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.
364 RunLoop();
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(&times)));
373 RunLoop();
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(&times)));
396 CallbackCounter ready_counter;
397 CallbackCounter retry_counter;
398 ConfigurationParams params(
399 GetUpdatesCallerInfo::RECONFIGURATION,
400 model_types,
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);
405 PumpLoop();
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(&times)));
425 CallbackCounter ready_counter;
426 CallbackCounter retry_counter;
427 ConfigurationParams params(
428 GetUpdatesCallerInfo::RECONFIGURATION,
429 model_types,
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);
434 RunLoop();
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(&times)));
443 scheduler()->ScheduleLocalNudge(zero(), model_types, FROM_HERE);
444 RunLoop();
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(&times)));
455 RunLoop();
457 // Now change the mode so nudge can execute.
458 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
459 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
460 RecordSyncShare(&times)));
461 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
462 PumpLoop();
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(&times)));
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);
478 RunLoop();
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(&times2)));
489 scheduler()->ScheduleLocalNudge(zero(), types3, FROM_HERE);
490 RunLoop();
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(&times)));
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;
512 RunLoop();
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(&times1)))
531 .RetiresOnSaturation();
532 scheduler()->ScheduleInvalidationNudge(zero(), invalidations1, FROM_HERE);
533 RunLoop();
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(&times2)));
544 scheduler()->ScheduleInvalidationNudge(zero(), invalidations2, FROM_HERE);
545 RunLoop();
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))
553 .WillRepeatedly(
554 DoAll(Invoke(sessions::test_util::SimulatePollSuccess),
555 RecordSyncShareMultiple(&times, 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.
563 RunLoop();
565 StopSyncScheduler();
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))
574 .WillRepeatedly(
575 DoAll(Invoke(sessions::test_util::SimulatePollSuccess),
576 RecordSyncShareMultiple(&times, 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.
585 RunLoop();
587 StopSyncScheduler();
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))
598 .WillOnce(DoAll(
599 WithArgs<0,1>(
600 sessions::test_util::SimulatePollIntervalUpdate(poll2)),
601 Return(true)))
602 .WillRepeatedly(
603 DoAll(Invoke(sessions::test_util::SimulatePollSuccess),
604 WithArg<1>(
605 RecordSyncShareMultiple(&times, kMinNumSamples))));
607 TimeTicks optimal_start = TimeTicks::Now() + poll1 + poll2;
608 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
610 // Run again to wait for polling.
611 RunLoop();
613 StopSyncScheduler();
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(_,_,_))
625 .WillOnce(
626 DoAll(
627 WithArgs<0,1,2>(
628 sessions::test_util::SimulateSessionsCommitDelayUpdate(
629 delay2)),
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);
639 RunLoop();
641 EXPECT_EQ(delay2, scheduler()->GetSessionsCommitDelay());
642 StopSyncScheduler();
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(_,_,_))
653 .WillOnce(DoAll(
654 WithArg<2>(sessions::test_util::SimulateThrottled(throttle)),
655 Return(true)))
656 .WillRepeatedly(AddFailureAndQuitLoopNow());
658 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
660 scheduler()->ScheduleLocalNudge(
661 TimeDelta::FromMicroseconds(1), types, FROM_HERE);
662 PumpLoop();
664 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
666 CallbackCounter ready_counter;
667 CallbackCounter retry_counter;
668 ConfigurationParams params(
669 GetUpdatesCallerInfo::RECONFIGURATION,
670 types,
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);
675 PumpLoop();
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(_,_))
689 .WillOnce(DoAll(
690 WithArg<1>(sessions::test_util::SimulateThrottled(throttle1)),
691 Return(true)))
692 .RetiresOnSaturation();
693 EXPECT_CALL(*syncer(), PollSyncShare(_,_))
694 .WillRepeatedly(
695 DoAll(Invoke(sessions::test_util::SimulatePollSuccess),
696 RecordSyncShareMultiple(&times, kMinNumSamples)));
698 TimeTicks optimal_start = TimeTicks::Now() + poll + throttle1;
699 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
701 // Run again to wait for polling.
702 RunLoop();
704 StopSyncScheduler();
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(_,_,_))
716 .WillOnce(DoAll(
717 WithArg<2>(sessions::test_util::SimulateThrottled(throttle1)),
718 Return(true)))
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());
731 RunLoop();
732 EXPECT_FALSE(scheduler()->IsCurrentlyThrottled());
734 StopSyncScheduler();
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(_,_,_))
745 .WillOnce(DoAll(
746 WithArg<2>(sessions::test_util::SimulateThrottled(throttle1)),
747 Return(true)))
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,
760 types,
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);
765 PumpLoop();
766 EXPECT_EQ(0, ready_counter.times_called());
767 EXPECT_EQ(1, retry_counter.times_called());
768 EXPECT_TRUE(scheduler()->IsCurrentlyThrottled());
770 RunLoop();
771 EXPECT_FALSE(scheduler()->IsCurrentlyThrottled());
773 StopSyncScheduler();
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(_,_,_))
789 .WillOnce(DoAll(
790 WithArg<2>(
791 sessions::test_util::SimulateTypesThrottled(types, throttle1)),
792 Return(true)))
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);
803 PumpLoop();
805 StopSyncScheduler();
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(_,_,_))
823 .WillOnce(DoAll(
824 WithArg<2>(
825 sessions::test_util::SimulateTypesThrottled(
826 throttled_types, throttle1)),
827 Return(true)))
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);
840 PumpLoop();
842 // Ignore refresh requests for throttled types.
843 scheduler()->ScheduleLocalRefreshRequest(zero(), throttled_types, FROM_HERE);
844 PumpLoop();
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(&times)));
852 scheduler()->ScheduleLocalNudge(zero(), unthrottled_types, FROM_HERE);
853 RunLoop();
854 Mock::VerifyAndClearExpectations(syncer());
856 StopSyncScheduler();
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(&times)))
876 .RetiresOnSaturation();
877 CallbackCounter ready_counter;
878 CallbackCounter retry_counter;
879 ConfigurationParams params(
880 GetUpdatesCallerInfo::RECONFIGURATION,
881 config_types,
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);
886 RunLoop();
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(&times2)));
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);
904 RunLoop();
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() {
917 StopSyncScheduler();
918 SyncSchedulerTest::TearDown();
922 // Have the sycner fail during commit. Expect that the scheduler enters
923 // backoff.
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(_,_,_))
935 .WillOnce(DoAll(
936 Invoke(sessions::test_util::SimulateDownloadUpdatesFailed),
937 Return(true)))
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(_,_,_))
947 .WillOnce(DoAll(
948 Invoke(sessions::test_util::SimulateCommitFailed),
949 Return(true)))
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(_,_,_))
959 .WillOnce(DoAll(
960 Invoke(sessions::test_util::SimulateDownloadUpdatesFailed),
961 Return(true)))
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(_,_,_))
972 .WillOnce(DoAll(
973 Invoke(sessions::test_util::SimulateGetEncryptionKeyFailed),
974 Return(true)))
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,
985 types,
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);
990 RunLoop();
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(&times, 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);
1014 RunLoop();
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),
1025 types,
1026 FROM_HERE);
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,
1039 types,
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);
1044 PumpLoop();
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(&times, 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);
1080 RunLoop();
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(&times)));
1107 scheduler()->ScheduleLocalNudge(zero(), ModelTypeSet(BOOKMARKS), FROM_HERE);
1108 RunLoop();
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(_,_,_))
1116 .WillOnce(DoAll(
1117 Invoke(sessions::test_util::SimulateNormalSuccess),
1118 RecordSyncShare(&times)));
1119 RunLoop();
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(&times, kMinNumSamples)));
1130 RunLoop();
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(&times)))
1153 .WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollSuccess),
1154 RecordSyncShare(&times)));
1156 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1158 // Run the unsucessful poll. The failed poll should not trigger backoff.
1159 RunLoop();
1160 EXPECT_FALSE(scheduler()->IsBackingOff());
1162 // Run the successful poll.
1163 RunLoop();
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),
1174 Return(true)))
1175 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
1176 Return(true)));
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),
1200 Return(true)))
1201 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
1202 Return(true)));
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),
1230 Return(true)))
1231 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
1232 Return(true)))
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();
1244 PumpLoop();
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),
1257 Return(true)));
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,
1267 model_types,
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(_,_))
1286 .WillRepeatedly(
1287 DoAll(Invoke(sessions::test_util::SimulatePollSuccess),
1288 RecordSyncShareMultiple(&times, kMinNumSamples)));
1290 connection()->SetServerStatus(HttpResponse::SYNC_AUTH_ERROR);
1291 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1293 // Run to wait for polling.
1294 RunLoop();
1296 // Normally OnCredentialsUpdated calls TryCanaryJob that doesn't run Poll,
1297 // but after poll finished with auth error from poll timer it should retry
1298 // poll once more
1299 EXPECT_CALL(*syncer(), PollSyncShare(_,_))
1300 .WillOnce(DoAll(Invoke(sessions::test_util::SimulatePollSuccess),
1301 RecordSyncShare(&times)));
1302 scheduler()->OnCredentialsUpdated();
1303 connection()->SetServerStatus(HttpResponse::SERVER_CONNECTION_OK);
1304 RunLoop();
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(_,_,_))
1317 .WillOnce(
1318 DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
1319 RecordSyncShare(&times)));
1321 // Run to wait for retrying.
1322 RunLoop();
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(_,_,_))
1338 .WillOnce(
1339 DoAll(Invoke(sessions::test_util::SimulateDownloadUpdatesFailed),
1340 QuitLoopNowAction()));
1342 // Run to wait for retrying.
1343 RunLoop();
1345 EXPECT_TRUE(scheduler()->IsBackingOff());
1346 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
1347 .WillOnce(
1348 DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
1349 QuitLoopNowAction()));
1351 // Run to wait for second retrying.
1352 RunLoop();
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),
1369 FROM_HERE);
1370 scheduler()->OnReceivedGuRetryDelay(delay1);
1371 EXPECT_EQ(delay1, GetRetryTimerDelay());
1373 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
1374 .WillOnce(DoAll(
1375 WithoutArgs(VerifyRetryTimerDelay(this, delay1)),
1376 WithArg<2>(sessions::test_util::SimulateGuRetryDelayCommand(delay2)),
1377 RecordSyncShare(&times)));
1379 // Run nudge GU.
1380 RunLoop();
1381 EXPECT_EQ(delay2, GetRetryTimerDelay());
1383 EXPECT_CALL(*syncer(), NormalSyncShare(_,_,_))
1384 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateNormalSuccess),
1385 RecordSyncShare(&times)));
1387 // Run to wait for retrying.
1388 RunLoop();
1390 StopSyncScheduler();
1393 } // namespace syncer