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.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/engine/throttled_data_type_tracker.h"
15 #include "sync/internal_api/public/base/model_type_state_map_test_util.h"
16 #include "sync/sessions/test_util.h"
17 #include "sync/test/callback_counter.h"
18 #include "sync/test/engine/fake_model_worker.h"
19 #include "sync/test/engine/mock_connection_manager.h"
20 #include "sync/test/engine/test_directory_setter_upper.h"
21 #include "sync/test/fake_extensions_activity_monitor.h"
22 #include "testing/gmock/include/gmock/gmock.h"
23 #include "testing/gtest/include/gtest/gtest.h"
25 using base::TimeDelta
;
26 using base::TimeTicks
;
28 using testing::AtLeast
;
31 using testing::Invoke
;
34 using testing::Return
;
35 using testing::WithArg
;
38 using sessions::SyncSession
;
39 using sessions::SyncSessionContext
;
40 using sessions::SyncSessionSnapshot
;
41 using sync_pb::GetUpdatesCallerInfo
;
43 class MockSyncer
: public Syncer
{
45 MOCK_METHOD3(SyncShare
, void(sessions::SyncSession
*, SyncerStep
,
49 // Used when tests want to record syncing activity to examine later.
50 struct SyncShareRecords
{
51 std::vector
<TimeTicks
> times
;
52 std::vector
<SyncSessionSnapshot
> snapshots
;
56 // We use QuitNow() instead of Quit() as the latter may get stalled
57 // indefinitely in the presence of repeated timers with low delays
58 // and a slow test (e.g., ThrottlingDoesThrottle [which has a poll
59 // delay of 5ms] run under TSAN on the trybots).
60 MessageLoop::current()->QuitNow();
64 MessageLoop::current()->Run();
68 // Do it this way instead of RunAllPending to pump loop exactly once
69 // (necessary in the presence of timers; see comment in
71 MessageLoop::current()->PostTask(FROM_HERE
, base::Bind(&QuitLoopNow
));
75 ModelSafeRoutingInfo
TypesToRoutingInfo(ModelTypeSet types
) {
76 ModelSafeRoutingInfo routes
;
77 for (ModelTypeSet::Iterator iter
= types
.First(); iter
.Good(); iter
.Inc()) {
78 routes
[iter
.Get()] = GROUP_PASSIVE
;
83 // Convenient to use in tests wishing to analyze SyncShare calls over time.
84 static const size_t kMinNumSamples
= 5;
85 class SyncSchedulerTest
: public testing::Test
{
88 : weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
93 class MockDelayProvider
: public BackoffDelayProvider
{
95 MockDelayProvider() : BackoffDelayProvider(
96 TimeDelta::FromSeconds(kInitialBackoffRetrySeconds
),
97 TimeDelta::FromSeconds(kInitialBackoffShortRetrySeconds
)) {
100 MOCK_METHOD1(GetDelay
, TimeDelta(const TimeDelta
&));
103 virtual void SetUp() {
105 syncer_
= new MockSyncer();
108 routing_info_
[BOOKMARKS
] = GROUP_UI
;
109 routing_info_
[AUTOFILL
] = GROUP_DB
;
110 routing_info_
[THEMES
] = GROUP_UI
;
111 routing_info_
[NIGORI
] = GROUP_PASSIVE
;
113 workers_
.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_UI
)));
114 workers_
.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_DB
)));
115 workers_
.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_PASSIVE
)));
117 std::vector
<ModelSafeWorker
*> workers
;
118 for (std::vector
<scoped_refptr
<FakeModelWorker
> >::iterator it
=
119 workers_
.begin(); it
!= workers_
.end(); ++it
) {
120 workers
.push_back(it
->get());
123 connection_
.reset(new MockConnectionManager(directory()));
124 connection_
->SetServerReachable();
125 throttled_data_type_tracker_
.reset(new ThrottledDataTypeTracker(NULL
));
126 context_
.reset(new SyncSessionContext(
127 connection_
.get(), directory(), workers
,
128 &extensions_activity_monitor_
, throttled_data_type_tracker_
.get(),
129 std::vector
<SyncEngineEventListener
*>(), NULL
, NULL
,
130 true /* enable keystore encryption */));
131 context_
->set_routing_info(routing_info_
);
132 context_
->set_notifications_enabled(true);
133 context_
->set_account_name("Test");
135 new SyncSchedulerImpl("TestSyncScheduler",
136 BackoffDelayProvider::FromDefaults(),
141 SyncSchedulerImpl
* scheduler() { return scheduler_
.get(); }
142 const ModelSafeRoutingInfo
& routing_info() { return routing_info_
; }
143 MockSyncer
* syncer() { return syncer_
; }
144 MockDelayProvider
* delay() { return delay_
; }
145 MockConnectionManager
* connection() { return connection_
.get(); }
146 TimeDelta
zero() { return TimeDelta::FromSeconds(0); }
147 TimeDelta
timeout() {
148 return TestTimeouts::action_timeout();
151 virtual void TearDown() {
155 dir_maker_
.TearDown();
158 void AnalyzePollRun(const SyncShareRecords
& records
, size_t min_num_samples
,
159 const TimeTicks
& optimal_start
, const TimeDelta
& poll_interval
) {
160 const std::vector
<TimeTicks
>& data(records
.times
);
161 EXPECT_GE(data
.size(), min_num_samples
);
162 for (size_t i
= 0; i
< data
.size(); i
++) {
163 SCOPED_TRACE(testing::Message() << "SyncShare # (" << i
<< ")");
164 TimeTicks optimal_next_sync
= optimal_start
+ poll_interval
* i
;
165 EXPECT_GE(data
[i
], optimal_next_sync
);
166 EXPECT_EQ(GetUpdatesCallerInfo::PERIODIC
,
167 records
.snapshots
[i
].source().updates_source
);
171 void DoQuitLoopNow() {
175 void StartSyncScheduler(SyncScheduler::Mode mode
) {
176 scheduler()->Start(mode
);
179 // This stops the scheduler synchronously.
180 void StopSyncScheduler() {
181 scheduler()->RequestStop(base::Bind(&SyncSchedulerTest::DoQuitLoopNow
,
182 weak_ptr_factory_
.GetWeakPtr()));
186 bool RunAndGetBackoff() {
187 ModelTypeSet
nudge_types(BOOKMARKS
);
188 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
190 scheduler()->ScheduleNudgeAsync(
191 zero(), NUDGE_SOURCE_LOCAL
, nudge_types
, FROM_HERE
);
194 return scheduler()->IsBackingOff();
197 void UseMockDelayProvider() {
198 delay_
= new MockDelayProvider();
199 scheduler_
->delay_provider_
.reset(delay_
);
202 // Compare a ModelTypeSet to a ModelTypeStateMap, ignoring
204 bool CompareModelTypeSetToModelTypeStateMap(
206 const ModelTypeStateMap
& rhs
) {
208 for (ModelTypeStateMap::const_iterator i
= rhs
.begin();
209 i
!= rhs
.end(); ++i
, ++count
) {
210 if (!lhs
.Has(i
->first
))
213 if (lhs
.Size() != count
)
218 SyncSessionContext
* context() { return context_
.get(); }
221 syncable::Directory
* directory() {
222 return dir_maker_
.directory();
225 base::WeakPtrFactory
<SyncSchedulerTest
> weak_ptr_factory_
;
226 MessageLoop message_loop_
;
227 TestDirectorySetterUpper dir_maker_
;
228 scoped_ptr
<MockConnectionManager
> connection_
;
229 scoped_ptr
<SyncSessionContext
> context_
;
230 scoped_ptr
<SyncSchedulerImpl
> scheduler_
;
232 MockDelayProvider
* delay_
;
233 std::vector
<scoped_refptr
<FakeModelWorker
> > workers_
;
234 FakeExtensionsActivityMonitor extensions_activity_monitor_
;
235 scoped_ptr
<ThrottledDataTypeTracker
> throttled_data_type_tracker_
;
236 ModelSafeRoutingInfo routing_info_
;
239 void RecordSyncShareImpl(SyncSession
* s
, SyncShareRecords
* record
) {
240 record
->times
.push_back(TimeTicks::Now());
241 record
->snapshots
.push_back(s
->TakeSnapshot());
244 ACTION_P(RecordSyncShare
, record
) {
245 RecordSyncShareImpl(arg0
, record
);
246 if (MessageLoop::current()->is_running())
250 ACTION_P2(RecordSyncShareMultiple
, record
, quit_after
) {
251 RecordSyncShareImpl(arg0
, record
);
252 EXPECT_LE(record
->times
.size(), quit_after
);
253 if (record
->times
.size() >= quit_after
&&
254 MessageLoop::current()->is_running()) {
259 ACTION(AddFailureAndQuitLoopNow
) {
264 ACTION(QuitLoopNowAction
) {
268 // Test nudge scheduling.
269 TEST_F(SyncSchedulerTest
, Nudge
) {
270 SyncShareRecords records
;
271 ModelTypeSet
model_types(BOOKMARKS
);
273 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
274 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
275 WithArg
<0>(RecordSyncShare(&records
))))
276 .RetiresOnSaturation();
278 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
280 scheduler()->ScheduleNudgeAsync(
281 zero(), NUDGE_SOURCE_LOCAL
, model_types
, FROM_HERE
);
284 ASSERT_EQ(1U, records
.snapshots
.size());
285 EXPECT_TRUE(CompareModelTypeSetToModelTypeStateMap(model_types
,
286 records
.snapshots
[0].source().types
));
287 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL
,
288 records
.snapshots
[0].source().updates_source
);
290 Mock::VerifyAndClearExpectations(syncer());
292 // Make sure a second, later, nudge is unaffected by first (no coalescing).
293 SyncShareRecords records2
;
294 model_types
.Remove(BOOKMARKS
);
295 model_types
.Put(AUTOFILL
);
296 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
297 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
298 WithArg
<0>(RecordSyncShare(&records2
))));
299 scheduler()->ScheduleNudgeAsync(
300 zero(), NUDGE_SOURCE_LOCAL
, model_types
, FROM_HERE
);
303 ASSERT_EQ(1U, records2
.snapshots
.size());
304 EXPECT_TRUE(CompareModelTypeSetToModelTypeStateMap(model_types
,
305 records2
.snapshots
[0].source().types
));
306 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL
,
307 records2
.snapshots
[0].source().updates_source
);
310 // Make sure a regular config command is scheduled fine in the absence of any
312 TEST_F(SyncSchedulerTest
, Config
) {
313 SyncShareRecords records
;
314 const ModelTypeSet
model_types(BOOKMARKS
);
316 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
317 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
318 WithArg
<0>(RecordSyncShare(&records
))));
320 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
322 CallbackCounter counter
;
323 ConfigurationParams
params(
324 GetUpdatesCallerInfo::RECONFIGURATION
,
326 TypesToRoutingInfo(model_types
),
327 base::Bind(&CallbackCounter::Callback
, base::Unretained(&counter
)));
328 ASSERT_TRUE(scheduler()->ScheduleConfiguration(params
));
329 ASSERT_EQ(1, counter
.times_called());
331 ASSERT_EQ(1U, records
.snapshots
.size());
332 EXPECT_TRUE(CompareModelTypeSetToModelTypeStateMap(model_types
,
333 records
.snapshots
[0].source().types
));
334 EXPECT_EQ(GetUpdatesCallerInfo::RECONFIGURATION
,
335 records
.snapshots
[0].source().updates_source
);
338 // Simulate a failure and make sure the config request is retried.
339 TEST_F(SyncSchedulerTest
, ConfigWithBackingOff
) {
340 UseMockDelayProvider();
341 EXPECT_CALL(*delay(), GetDelay(_
))
342 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(1)));
343 SyncShareRecords records
;
344 const ModelTypeSet
model_types(BOOKMARKS
);
346 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
347 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed
),
348 WithArg
<0>(RecordSyncShare(&records
))))
349 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
350 WithArg
<0>(RecordSyncShare(&records
))));
352 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
354 ASSERT_EQ(0U, records
.snapshots
.size());
355 CallbackCounter counter
;
356 ConfigurationParams
params(
357 GetUpdatesCallerInfo::RECONFIGURATION
,
359 TypesToRoutingInfo(model_types
),
360 base::Bind(&CallbackCounter::Callback
, base::Unretained(&counter
)));
361 ASSERT_FALSE(scheduler()->ScheduleConfiguration(params
));
362 ASSERT_EQ(0, counter
.times_called());
364 ASSERT_EQ(1U, records
.snapshots
.size());
367 ASSERT_EQ(2U, records
.snapshots
.size());
368 ASSERT_EQ(1, counter
.times_called());
369 EXPECT_TRUE(CompareModelTypeSetToModelTypeStateMap(model_types
,
370 records
.snapshots
[1].source().types
));
371 EXPECT_EQ(GetUpdatesCallerInfo::RECONFIGURATION
,
372 records
.snapshots
[1].source().updates_source
);
375 // Issue a nudge when the config has failed. Make sure both the config and
376 // nudge are executed.
377 TEST_F(SyncSchedulerTest
, NudgeWithConfigWithBackingOff
) {
378 const ModelTypeSet
model_types(BOOKMARKS
);
379 UseMockDelayProvider();
380 EXPECT_CALL(*delay(), GetDelay(_
))
381 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(50)));
382 SyncShareRecords records
;
384 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
385 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed
),
386 WithArg
<0>(RecordSyncShare(&records
))))
387 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed
),
388 WithArg
<0>(RecordSyncShare(&records
))))
389 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
390 WithArg
<0>(RecordSyncShare(&records
))))
391 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
392 WithArg
<0>(RecordSyncShare(&records
))));
394 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
396 ASSERT_EQ(0U, records
.snapshots
.size());
397 CallbackCounter counter
;
398 ConfigurationParams
params(
399 GetUpdatesCallerInfo::RECONFIGURATION
,
401 TypesToRoutingInfo(model_types
),
402 base::Bind(&CallbackCounter::Callback
, base::Unretained(&counter
)));
403 ASSERT_FALSE(scheduler()->ScheduleConfiguration(params
));
404 ASSERT_EQ(0, counter
.times_called());
405 ASSERT_EQ(1U, records
.snapshots
.size());
407 scheduler()->ScheduleNudgeAsync(
408 zero(), NUDGE_SOURCE_LOCAL
, model_types
, FROM_HERE
);
410 // Note that we're not RunLoop()ing for the NUDGE we just scheduled, but
411 // for the first retry attempt from the config job (after
412 // waiting ~+/- 50ms).
413 ASSERT_EQ(2U, records
.snapshots
.size());
414 ASSERT_EQ(0, counter
.times_called());
415 EXPECT_EQ(GetUpdatesCallerInfo::RECONFIGURATION
,
416 records
.snapshots
[1].source().updates_source
);
419 // This is the 3rd attempt, which we've set up to SimulateSuccess.
420 ASSERT_EQ(3U, records
.snapshots
.size());
421 ASSERT_EQ(1, counter
.times_called());
423 // Now change the mode so nudge can execute.
424 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
426 ASSERT_EQ(4U, records
.snapshots
.size());
428 EXPECT_TRUE(CompareModelTypeSetToModelTypeStateMap(model_types
,
429 records
.snapshots
[2].source().types
));
430 EXPECT_EQ(GetUpdatesCallerInfo::RECONFIGURATION
,
431 records
.snapshots
[2].source().updates_source
);
433 EXPECT_TRUE(CompareModelTypeSetToModelTypeStateMap(model_types
,
434 records
.snapshots
[3].source().types
));
435 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL
,
436 records
.snapshots
[3].source().updates_source
);
440 // Test that nudges are coalesced.
441 TEST_F(SyncSchedulerTest
, NudgeCoalescing
) {
442 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
445 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
446 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
447 WithArg
<0>(RecordSyncShare(&r
))));
448 const ModelTypeSet
types1(BOOKMARKS
), types2(AUTOFILL
), types3(THEMES
);
449 TimeDelta delay
= zero();
450 TimeTicks optimal_time
= TimeTicks::Now() + delay
;
451 scheduler()->ScheduleNudgeAsync(
452 delay
, NUDGE_SOURCE_UNKNOWN
, types1
, FROM_HERE
);
453 scheduler()->ScheduleNudgeAsync(
454 zero(), NUDGE_SOURCE_LOCAL
, types2
, FROM_HERE
);
457 ASSERT_EQ(1U, r
.snapshots
.size());
458 EXPECT_GE(r
.times
[0], optimal_time
);
459 EXPECT_TRUE(CompareModelTypeSetToModelTypeStateMap(
460 Union(types1
, types2
), r
.snapshots
[0].source().types
));
461 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL
,
462 r
.snapshots
[0].source().updates_source
);
464 Mock::VerifyAndClearExpectations(syncer());
467 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
468 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
469 WithArg
<0>(RecordSyncShare(&r2
))));
470 scheduler()->ScheduleNudgeAsync(
471 zero(), NUDGE_SOURCE_NOTIFICATION
, types3
, FROM_HERE
);
474 ASSERT_EQ(1U, r2
.snapshots
.size());
475 EXPECT_TRUE(CompareModelTypeSetToModelTypeStateMap(types3
,
476 r2
.snapshots
[0].source().types
));
477 EXPECT_EQ(GetUpdatesCallerInfo::NOTIFICATION
,
478 r2
.snapshots
[0].source().updates_source
);
481 // Test that nudges are coalesced.
482 TEST_F(SyncSchedulerTest
, NudgeCoalescingWithDifferentTimings
) {
483 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
486 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
487 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
488 WithArg
<0>(RecordSyncShare(&r
))));
489 ModelTypeSet
types1(BOOKMARKS
), types2(AUTOFILL
), types3
;
491 // Create a huge time delay.
492 TimeDelta delay
= TimeDelta::FromDays(1);
494 scheduler()->ScheduleNudgeAsync(
495 delay
, NUDGE_SOURCE_UNKNOWN
, types1
, FROM_HERE
);
497 scheduler()->ScheduleNudgeAsync(
498 zero(), NUDGE_SOURCE_UNKNOWN
, types2
, FROM_HERE
);
500 TimeTicks min_time
= TimeTicks::Now();
501 TimeTicks max_time
= TimeTicks::Now() + delay
;
505 // Make sure the sync has happened.
506 ASSERT_EQ(1U, r
.snapshots
.size());
507 EXPECT_TRUE(CompareModelTypeSetToModelTypeStateMap(
508 Union(types1
, types2
), r
.snapshots
[0].source().types
));
510 // Make sure the sync happened at the right time.
511 EXPECT_GE(r
.times
[0], min_time
);
512 EXPECT_LE(r
.times
[0], max_time
);
515 // Test nudge scheduling.
516 TEST_F(SyncSchedulerTest
, NudgeWithStates
) {
517 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
519 SyncShareRecords records
;
520 ModelTypeStateMap type_state_map
;
521 type_state_map
[BOOKMARKS
].payload
= "test";
523 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
524 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
525 WithArg
<0>(RecordSyncShare(&records
))))
526 .RetiresOnSaturation();
527 scheduler()->ScheduleNudgeWithStatesAsync(
528 zero(), NUDGE_SOURCE_LOCAL
, type_state_map
, FROM_HERE
);
531 ASSERT_EQ(1U, records
.snapshots
.size());
532 EXPECT_THAT(type_state_map
, Eq(records
.snapshots
[0].source().types
));
533 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL
,
534 records
.snapshots
[0].source().updates_source
);
536 Mock::VerifyAndClearExpectations(syncer());
538 // Make sure a second, later, nudge is unaffected by first (no coalescing).
539 SyncShareRecords records2
;
540 type_state_map
.erase(BOOKMARKS
);
541 type_state_map
[AUTOFILL
].payload
= "test2";
542 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
543 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
544 WithArg
<0>(RecordSyncShare(&records2
))));
545 scheduler()->ScheduleNudgeWithStatesAsync(
546 zero(), NUDGE_SOURCE_LOCAL
, type_state_map
, FROM_HERE
);
549 ASSERT_EQ(1U, records2
.snapshots
.size());
550 EXPECT_THAT(type_state_map
, Eq(records2
.snapshots
[0].source().types
));
551 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL
,
552 records2
.snapshots
[0].source().updates_source
);
555 // Test that nudges are coalesced.
556 TEST_F(SyncSchedulerTest
, NudgeWithStatesCoalescing
) {
557 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
560 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
561 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
562 WithArg
<0>(RecordSyncShare(&r
))));
563 ModelTypeStateMap types1
, types2
, types3
;
564 types1
[BOOKMARKS
].payload
= "test1";
565 types2
[AUTOFILL
].payload
= "test2";
566 types3
[THEMES
].payload
= "test3";
567 TimeDelta delay
= zero();
568 TimeTicks optimal_time
= TimeTicks::Now() + delay
;
569 scheduler()->ScheduleNudgeWithStatesAsync(
570 delay
, NUDGE_SOURCE_UNKNOWN
, types1
, FROM_HERE
);
571 scheduler()->ScheduleNudgeWithStatesAsync(
572 zero(), NUDGE_SOURCE_LOCAL
, types2
, FROM_HERE
);
575 ASSERT_EQ(1U, r
.snapshots
.size());
576 EXPECT_GE(r
.times
[0], optimal_time
);
577 ModelTypeStateMap coalesced_types
;
578 CoalesceStates(&coalesced_types
, types1
);
579 CoalesceStates(&coalesced_types
, types2
);
580 EXPECT_THAT(coalesced_types
, Eq(r
.snapshots
[0].source().types
));
581 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL
,
582 r
.snapshots
[0].source().updates_source
);
584 Mock::VerifyAndClearExpectations(syncer());
587 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
588 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
589 WithArg
<0>(RecordSyncShare(&r2
))));
590 scheduler()->ScheduleNudgeWithStatesAsync(
591 zero(), NUDGE_SOURCE_NOTIFICATION
, types3
, FROM_HERE
);
594 ASSERT_EQ(1U, r2
.snapshots
.size());
595 EXPECT_THAT(types3
, Eq(r2
.snapshots
[0].source().types
));
596 EXPECT_EQ(GetUpdatesCallerInfo::NOTIFICATION
,
597 r2
.snapshots
[0].source().updates_source
);
600 // Test that polling works as expected.
601 TEST_F(SyncSchedulerTest
, Polling
) {
602 SyncShareRecords records
;
603 TimeDelta
poll_interval(TimeDelta::FromMilliseconds(30));
604 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
)).Times(AtLeast(kMinNumSamples
))
605 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
606 WithArg
<0>(RecordSyncShareMultiple(&records
, kMinNumSamples
))));
608 scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval
);
610 TimeTicks optimal_start
= TimeTicks::Now() + poll_interval
;
611 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
613 // Run again to wait for polling.
617 AnalyzePollRun(records
, kMinNumSamples
, optimal_start
, poll_interval
);
620 // Test that the short poll interval is used.
621 TEST_F(SyncSchedulerTest
, PollNotificationsDisabled
) {
622 SyncShareRecords records
;
623 TimeDelta
poll_interval(TimeDelta::FromMilliseconds(30));
624 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
)).Times(AtLeast(kMinNumSamples
))
625 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
626 WithArg
<0>(RecordSyncShareMultiple(&records
, kMinNumSamples
))));
628 scheduler()->OnReceivedShortPollIntervalUpdate(poll_interval
);
629 scheduler()->SetNotificationsEnabled(false);
631 TimeTicks optimal_start
= TimeTicks::Now() + poll_interval
;
632 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
634 // Run again to wait for polling.
638 AnalyzePollRun(records
, kMinNumSamples
, optimal_start
, poll_interval
);
641 // Test that polling intervals are updated when needed.
642 TEST_F(SyncSchedulerTest
, PollIntervalUpdate
) {
643 SyncShareRecords records
;
644 TimeDelta
poll1(TimeDelta::FromMilliseconds(120));
645 TimeDelta
poll2(TimeDelta::FromMilliseconds(30));
646 scheduler()->OnReceivedLongPollIntervalUpdate(poll1
);
647 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
)).Times(AtLeast(kMinNumSamples
))
648 .WillOnce(WithArg
<0>(
649 sessions::test_util::SimulatePollIntervalUpdate(poll2
)))
651 DoAll(Invoke(sessions::test_util::SimulateSuccess
),
653 RecordSyncShareMultiple(&records
, kMinNumSamples
))));
655 TimeTicks optimal_start
= TimeTicks::Now() + poll1
+ poll2
;
656 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
658 // Run again to wait for polling.
662 AnalyzePollRun(records
, kMinNumSamples
, optimal_start
, poll2
);
665 // Test that the sessions commit delay is updated when needed.
666 TEST_F(SyncSchedulerTest
, SessionsCommitDelay
) {
667 SyncShareRecords records
;
668 TimeDelta
delay1(TimeDelta::FromMilliseconds(120));
669 TimeDelta
delay2(TimeDelta::FromMilliseconds(30));
670 scheduler()->OnReceivedSessionsCommitDelay(delay1
);
672 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
676 sessions::test_util::SimulateSessionsCommitDelayUpdate(
678 Invoke(sessions::test_util::SimulateSuccess
),
679 QuitLoopNowAction()));
681 EXPECT_EQ(delay1
, scheduler()->GetSessionsCommitDelay());
682 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
684 EXPECT_EQ(delay1
, scheduler()->GetSessionsCommitDelay());
685 const ModelTypeSet
model_types(BOOKMARKS
);
686 scheduler()->ScheduleNudgeAsync(
687 zero(), NUDGE_SOURCE_LOCAL
, model_types
, FROM_HERE
);
690 EXPECT_EQ(delay2
, scheduler()->GetSessionsCommitDelay());
694 // Test that a sync session is run through to completion.
695 TEST_F(SyncSchedulerTest
, HasMoreToSync
) {
696 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
697 .WillOnce(Invoke(sessions::test_util::SimulateHasMoreToSync
))
698 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
699 QuitLoopNowAction()));
700 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
702 scheduler()->ScheduleNudgeAsync(
703 zero(), NUDGE_SOURCE_LOCAL
, ModelTypeSet(BOOKMARKS
), FROM_HERE
);
705 // If more nudges are scheduled, they'll be waited on by TearDown, and would
706 // cause our expectation to break.
709 // Test that continuations can go into backoff.
710 TEST_F(SyncSchedulerTest
, HasMoreToSyncThenFails
) {
711 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
712 .WillOnce(Invoke(sessions::test_util::SimulateHasMoreToSync
))
713 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed
),
714 QuitLoopNowAction()));
715 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
717 scheduler()->ScheduleNudgeAsync(
718 zero(), NUDGE_SOURCE_LOCAL
, ModelTypeSet(BOOKMARKS
), FROM_HERE
);
720 // We should detect the failure on the second sync share, and go into backoff.
721 EXPECT_TRUE(RunAndGetBackoff());
724 // Test that no syncing occurs when throttled.
725 TEST_F(SyncSchedulerTest
, ThrottlingDoesThrottle
) {
726 const ModelTypeSet
types(BOOKMARKS
);
727 TimeDelta
poll(TimeDelta::FromMilliseconds(5));
728 TimeDelta
throttle(TimeDelta::FromMinutes(10));
729 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
731 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
732 .WillOnce(WithArg
<0>(sessions::test_util::SimulateThrottled(throttle
)))
733 .WillRepeatedly(AddFailureAndQuitLoopNow());
735 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
737 scheduler()->ScheduleNudgeAsync(
738 zero(), NUDGE_SOURCE_LOCAL
, types
, FROM_HERE
);
741 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
743 CallbackCounter counter
;
744 ConfigurationParams
params(
745 GetUpdatesCallerInfo::RECONFIGURATION
,
747 TypesToRoutingInfo(types
),
748 base::Bind(&CallbackCounter::Callback
, base::Unretained(&counter
)));
749 ASSERT_FALSE(scheduler()->ScheduleConfiguration(params
));
750 ASSERT_EQ(0, counter
.times_called());
753 TEST_F(SyncSchedulerTest
, ThrottlingExpires
) {
754 SyncShareRecords records
;
755 TimeDelta
poll(TimeDelta::FromMilliseconds(15));
756 TimeDelta
throttle1(TimeDelta::FromMilliseconds(150));
757 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
759 ::testing::InSequence seq
;
760 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
761 .WillOnce(WithArg
<0>(sessions::test_util::SimulateThrottled(throttle1
)))
762 .RetiresOnSaturation();
763 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
764 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
765 WithArg
<0>(RecordSyncShareMultiple(&records
, kMinNumSamples
))));
767 TimeTicks optimal_start
= TimeTicks::Now() + poll
+ throttle1
;
768 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
770 // Run again to wait for polling.
774 AnalyzePollRun(records
, kMinNumSamples
, optimal_start
, poll
);
777 // Test nudges / polls don't run in config mode and config tasks do.
778 TEST_F(SyncSchedulerTest
, ConfigurationMode
) {
779 TimeDelta
poll(TimeDelta::FromMilliseconds(15));
780 SyncShareRecords records
;
781 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
782 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
783 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
784 WithArg
<0>(RecordSyncShare(&records
))))
785 .RetiresOnSaturation();
787 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
789 const ModelTypeSet
nudge_types(AUTOFILL
);
790 scheduler()->ScheduleNudgeAsync(
791 zero(), NUDGE_SOURCE_LOCAL
, nudge_types
, FROM_HERE
);
792 scheduler()->ScheduleNudgeAsync(
793 zero(), NUDGE_SOURCE_LOCAL
, nudge_types
, FROM_HERE
);
795 const ModelTypeSet
config_types(BOOKMARKS
);
797 CallbackCounter counter
;
798 ConfigurationParams
params(
799 GetUpdatesCallerInfo::RECONFIGURATION
,
801 TypesToRoutingInfo(config_types
),
802 base::Bind(&CallbackCounter::Callback
, base::Unretained(&counter
)));
803 ASSERT_TRUE(scheduler()->ScheduleConfiguration(params
));
804 ASSERT_EQ(1, counter
.times_called());
806 ASSERT_EQ(1U, records
.snapshots
.size());
807 EXPECT_TRUE(CompareModelTypeSetToModelTypeStateMap(config_types
,
808 records
.snapshots
[0].source().types
));
810 // Switch to NORMAL_MODE to ensure NUDGES were properly saved and run.
811 // SyncSchedulerWhiteboxTest also provides coverage for this, but much
812 // more targeted ('whitebox' style).
813 scheduler()->OnReceivedLongPollIntervalUpdate(TimeDelta::FromDays(1));
814 SyncShareRecords records2
;
815 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
816 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
817 WithArg
<0>(RecordSyncShare(&records2
))));
819 // TODO(tim): Figure out how to remove this dangerous need to reset
820 // routing info between mode switches.
821 context()->set_routing_info(routing_info());
822 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
824 ASSERT_EQ(1U, records2
.snapshots
.size());
825 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL
,
826 records2
.snapshots
[0].source().updates_source
);
827 EXPECT_TRUE(CompareModelTypeSetToModelTypeStateMap(nudge_types
,
828 records2
.snapshots
[0].source().types
));
832 class BackoffTriggersSyncSchedulerTest
: public SyncSchedulerTest
{
834 SyncSchedulerTest::SetUp();
835 UseMockDelayProvider();
836 EXPECT_CALL(*delay(), GetDelay(_
))
837 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(1)));
842 SyncSchedulerTest::TearDown();
846 // Have the sycner fail during commit. Expect that the scheduler enters
848 TEST_F(BackoffTriggersSyncSchedulerTest
, FailCommitOnce
) {
849 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
850 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed
),
851 QuitLoopNowAction()));
852 EXPECT_TRUE(RunAndGetBackoff());
855 // Have the syncer fail during download updates and succeed on the first
856 // retry. Expect that this clears the backoff state.
857 TEST_F(BackoffTriggersSyncSchedulerTest
, FailDownloadOnceThenSucceed
) {
858 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
859 .WillOnce(Invoke(sessions::test_util::SimulateDownloadUpdatesFailed
))
860 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
861 QuitLoopNowAction()));
862 EXPECT_FALSE(RunAndGetBackoff());
865 // Have the syncer fail during commit and succeed on the first retry. Expect
866 // that this clears the backoff state.
867 TEST_F(BackoffTriggersSyncSchedulerTest
, FailCommitOnceThenSucceed
) {
868 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
869 .WillOnce(Invoke(sessions::test_util::SimulateCommitFailed
))
870 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
871 QuitLoopNowAction()));
872 EXPECT_FALSE(RunAndGetBackoff());
875 // Have the syncer fail to download updates and fail again on the retry.
876 // Expect this will leave the scheduler in backoff.
877 TEST_F(BackoffTriggersSyncSchedulerTest
, FailDownloadTwice
) {
878 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
879 .WillOnce(Invoke(sessions::test_util::SimulateDownloadUpdatesFailed
))
880 .WillRepeatedly(DoAll(
881 Invoke(sessions::test_util::SimulateDownloadUpdatesFailed
),
882 QuitLoopNowAction()));
883 EXPECT_TRUE(RunAndGetBackoff());
886 // Have the syncer fail to get the encryption key yet succeed in downloading
887 // updates. Expect this will leave the scheduler in backoff.
888 TEST_F(BackoffTriggersSyncSchedulerTest
, FailGetEncryptionKey
) {
889 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
890 .WillOnce(Invoke(sessions::test_util::SimulateGetEncryptionKeyFailed
))
891 .WillRepeatedly(DoAll(
892 Invoke(sessions::test_util::SimulateGetEncryptionKeyFailed
),
893 QuitLoopNowAction()));
894 EXPECT_TRUE(RunAndGetBackoff());
897 // Test that no polls or extraneous nudges occur when in backoff.
898 TEST_F(SyncSchedulerTest
, BackoffDropsJobs
) {
900 TimeDelta
poll(TimeDelta::FromMilliseconds(5));
901 const ModelTypeSet
types(BOOKMARKS
);
902 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
903 UseMockDelayProvider();
905 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
906 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateCommitFailed
),
907 RecordSyncShareMultiple(&r
, 1U)));
908 EXPECT_CALL(*delay(), GetDelay(_
)).
909 WillRepeatedly(Return(TimeDelta::FromDays(1)));
911 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
913 // This nudge should fail and put us into backoff. Thanks to our mock
914 // GetDelay() setup above, this will be a long backoff.
915 scheduler()->ScheduleNudgeAsync(zero(), NUDGE_SOURCE_LOCAL
, types
, FROM_HERE
);
918 Mock::VerifyAndClearExpectations(syncer());
919 ASSERT_EQ(1U, r
.snapshots
.size());
920 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL
,
921 r
.snapshots
[0].source().updates_source
);
923 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
)).Times(1)
924 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed
),
925 RecordSyncShare(&r
)));
927 // We schedule a nudge with enough delay (10X poll interval) that at least
928 // one or two polls would have taken place. The nudge should succeed.
929 scheduler()->ScheduleNudgeAsync(
930 poll
* 10, NUDGE_SOURCE_LOCAL
, types
, FROM_HERE
);
933 Mock::VerifyAndClearExpectations(syncer());
934 Mock::VerifyAndClearExpectations(delay());
935 ASSERT_EQ(2U, r
.snapshots
.size());
936 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL
,
937 r
.snapshots
[1].source().updates_source
);
939 EXPECT_CALL(*delay(), GetDelay(_
)).Times(0);
941 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
943 CallbackCounter counter
;
944 ConfigurationParams
params(
945 GetUpdatesCallerInfo::RECONFIGURATION
,
947 TypesToRoutingInfo(types
),
948 base::Bind(&CallbackCounter::Callback
, base::Unretained(&counter
)));
949 ASSERT_FALSE(scheduler()->ScheduleConfiguration(params
));
950 ASSERT_EQ(0, counter
.times_called());
953 // Test that backoff is shaping traffic properly with consecutive errors.
954 TEST_F(SyncSchedulerTest
, BackoffElevation
) {
956 UseMockDelayProvider();
958 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
)).Times(kMinNumSamples
)
959 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateCommitFailed
),
960 RecordSyncShareMultiple(&r
, kMinNumSamples
)));
962 const TimeDelta first
= TimeDelta::FromSeconds(kInitialBackoffRetrySeconds
);
963 const TimeDelta second
= TimeDelta::FromMilliseconds(2);
964 const TimeDelta third
= TimeDelta::FromMilliseconds(3);
965 const TimeDelta fourth
= TimeDelta::FromMilliseconds(4);
966 const TimeDelta fifth
= TimeDelta::FromMilliseconds(5);
967 const TimeDelta sixth
= TimeDelta::FromDays(1);
969 EXPECT_CALL(*delay(), GetDelay(first
)).WillOnce(Return(second
))
970 .RetiresOnSaturation();
971 EXPECT_CALL(*delay(), GetDelay(second
)).WillOnce(Return(third
))
972 .RetiresOnSaturation();
973 EXPECT_CALL(*delay(), GetDelay(third
)).WillOnce(Return(fourth
))
974 .RetiresOnSaturation();
975 EXPECT_CALL(*delay(), GetDelay(fourth
)).WillOnce(Return(fifth
))
976 .RetiresOnSaturation();
977 EXPECT_CALL(*delay(), GetDelay(fifth
)).WillOnce(Return(sixth
));
979 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
981 // Run again with a nudge.
982 scheduler()->ScheduleNudgeAsync(
983 zero(), NUDGE_SOURCE_LOCAL
, ModelTypeSet(BOOKMARKS
), FROM_HERE
);
986 ASSERT_EQ(kMinNumSamples
, r
.snapshots
.size());
987 EXPECT_GE(r
.times
[1] - r
.times
[0], second
);
988 EXPECT_GE(r
.times
[2] - r
.times
[1], third
);
989 EXPECT_GE(r
.times
[3] - r
.times
[2], fourth
);
990 EXPECT_GE(r
.times
[4] - r
.times
[3], fifth
);
993 // Test that things go back to normal once a retry makes forward progress.
994 TEST_F(SyncSchedulerTest
, BackoffRelief
) {
996 const TimeDelta
poll(TimeDelta::FromMilliseconds(10));
997 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
998 UseMockDelayProvider();
1000 const TimeDelta backoff
= TimeDelta::FromMilliseconds(5);
1002 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
1003 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed
),
1004 RecordSyncShareMultiple(&r
, kMinNumSamples
)))
1005 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
1006 RecordSyncShareMultiple(&r
, kMinNumSamples
)));
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 // Run again to wait for polling.
1014 scheduler()->ScheduleNudgeAsync(zero(), NUDGE_SOURCE_LOCAL
,
1015 ModelTypeSet(BOOKMARKS
), FROM_HERE
);
1018 StopSyncScheduler();
1020 EXPECT_EQ(kMinNumSamples
, r
.times
.size());
1022 // The first nudge ran as soon as possible. It failed.
1023 TimeTicks optimal_job_time
= optimal_start
;
1024 EXPECT_GE(r
.times
[0], optimal_job_time
);
1025 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL
,
1026 r
.snapshots
[0].source().updates_source
);
1028 // It was followed by a successful retry nudge shortly afterward.
1029 optimal_job_time
= optimal_job_time
+ backoff
;
1030 EXPECT_GE(r
.times
[1], optimal_job_time
);
1031 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL
,
1032 r
.snapshots
[1].source().updates_source
);
1033 // After that, we went back to polling.
1034 for (size_t i
= 2; i
< r
.snapshots
.size(); i
++) {
1035 optimal_job_time
= optimal_job_time
+ poll
;
1036 SCOPED_TRACE(testing::Message() << "SyncShare # (" << i
<< ")");
1037 EXPECT_GE(r
.times
[i
], optimal_job_time
);
1038 EXPECT_EQ(GetUpdatesCallerInfo::PERIODIC
,
1039 r
.snapshots
[i
].source().updates_source
);
1043 // Test that poll failures are ignored. They should have no effect on
1044 // subsequent poll attempts, nor should they trigger a backoff/retry.
1045 TEST_F(SyncSchedulerTest
, TransientPollFailure
) {
1047 const TimeDelta
poll_interval(TimeDelta::FromMilliseconds(1));
1048 scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval
);
1049 UseMockDelayProvider(); // Will cause test failure if backoff is initiated.
1051 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
1052 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed
),
1053 RecordSyncShare(&r
)))
1054 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
1055 RecordSyncShare(&r
)));
1057 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
1059 // Run the unsucessful poll. The failed poll should not trigger backoff.
1061 EXPECT_FALSE(scheduler()->IsBackingOff());
1063 // Run the successful poll.
1065 EXPECT_FALSE(scheduler()->IsBackingOff());
1068 // Test that appropriate syncer steps are requested for each job type.
1069 TEST_F(SyncSchedulerTest
, SyncerSteps
) {
1071 EXPECT_CALL(*syncer(), SyncShare(_
, SYNCER_BEGIN
, SYNCER_END
))
1072 .WillOnce(Invoke(sessions::test_util::SimulateSuccess
));
1073 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
1075 scheduler()->ScheduleNudgeAsync(
1076 zero(), NUDGE_SOURCE_LOCAL
, ModelTypeSet(BOOKMARKS
), FROM_HERE
);
1078 // Pump again to run job.
1081 StopSyncScheduler();
1082 Mock::VerifyAndClearExpectations(syncer());
1085 EXPECT_CALL(*syncer(), SyncShare(_
, DOWNLOAD_UPDATES
, APPLY_UPDATES
))
1086 .WillOnce(Invoke(sessions::test_util::SimulateSuccess
));
1087 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE
);
1089 ModelTypeSet
model_types(BOOKMARKS
);
1090 CallbackCounter counter
;
1091 ConfigurationParams
params(
1092 GetUpdatesCallerInfo::RECONFIGURATION
,
1094 TypesToRoutingInfo(model_types
),
1095 base::Bind(&CallbackCounter::Callback
, base::Unretained(&counter
)));
1096 ASSERT_TRUE(scheduler()->ScheduleConfiguration(params
));
1097 ASSERT_EQ(1, counter
.times_called());
1098 // Runs directly so no need to pump the loop.
1099 StopSyncScheduler();
1100 Mock::VerifyAndClearExpectations(syncer());
1102 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
1105 EXPECT_CALL(*syncer(), SyncShare(_
, SYNCER_BEGIN
, SYNCER_END
))
1107 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess
),
1108 QuitLoopNowAction()));
1109 const TimeDelta
poll(TimeDelta::FromMilliseconds(10));
1110 scheduler()->OnReceivedLongPollIntervalUpdate(poll
);
1112 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
1114 // Run again to wait for polling.
1117 StopSyncScheduler();
1118 Mock::VerifyAndClearExpectations(syncer());
1121 // Test that starting the syncer thread without a valid connection doesn't
1122 // break things when a connection is detected.
1123 TEST_F(SyncSchedulerTest
, StartWhenNotConnected
) {
1124 connection()->SetServerNotReachable();
1125 connection()->UpdateConnectionStatus();
1126 EXPECT_CALL(*syncer(), SyncShare(_
,_
,_
))
1127 .WillOnce(Invoke(sessions::test_util::SimulateConnectionFailure
))
1128 .WillOnce(QuitLoopNowAction());
1129 StartSyncScheduler(SyncScheduler::NORMAL_MODE
);
1131 scheduler()->ScheduleNudgeAsync(
1132 zero(), NUDGE_SOURCE_LOCAL
, ModelTypeSet(BOOKMARKS
), FROM_HERE
);
1133 // Should save the nudge for until after the server is reachable.
1134 MessageLoop::current()->RunAllPending();
1136 connection()->SetServerReachable();
1137 connection()->UpdateConnectionStatus();
1138 scheduler()->OnConnectionStatusChange();
1139 MessageLoop::current()->RunAllPending();
1142 } // namespace syncer