Fix app list and overflow icon drawing problems
[chromium-blink-merge.git] / sync / engine / sync_scheduler_unittest.cc
blob63dc3c3cc7e2baa525456dda55bec939108c14c2
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.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;
27 using testing::_;
28 using testing::AtLeast;
29 using testing::DoAll;
30 using testing::Eq;
31 using testing::Invoke;
32 using testing::Mock;
33 using testing::Not;
34 using testing::Return;
35 using testing::WithArg;
37 namespace syncer {
38 using sessions::SyncSession;
39 using sessions::SyncSessionContext;
40 using sessions::SyncSessionSnapshot;
41 using sync_pb::GetUpdatesCallerInfo;
43 class MockSyncer : public Syncer {
44 public:
45 MOCK_METHOD3(SyncShare, void(sessions::SyncSession*, SyncerStep,
46 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;
55 void QuitLoopNow() {
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();
63 void RunLoop() {
64 MessageLoop::current()->Run();
67 void PumpLoop() {
68 // Do it this way instead of RunAllPending to pump loop exactly once
69 // (necessary in the presence of timers; see comment in
70 // QuitLoopNow).
71 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&QuitLoopNow));
72 RunLoop();
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;
80 return routes;
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 {
86 public:
87 SyncSchedulerTest()
88 : weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
89 context_(NULL),
90 syncer_(NULL),
91 delay_(NULL) {}
93 class MockDelayProvider : public BackoffDelayProvider {
94 public:
95 MockDelayProvider() : BackoffDelayProvider(
96 TimeDelta::FromSeconds(kInitialBackoffRetrySeconds),
97 TimeDelta::FromSeconds(kInitialBackoffShortRetrySeconds)) {
100 MOCK_METHOD1(GetDelay, TimeDelta(const TimeDelta&));
103 virtual void SetUp() {
104 dir_maker_.SetUp();
105 syncer_ = new MockSyncer();
106 delay_ = NULL;
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");
134 scheduler_.reset(
135 new SyncSchedulerImpl("TestSyncScheduler",
136 BackoffDelayProvider::FromDefaults(),
137 context(),
138 syncer_));
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() {
152 PumpLoop();
153 scheduler_.reset();
154 PumpLoop();
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() {
172 QuitLoopNow();
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()));
183 RunLoop();
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);
192 RunLoop();
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
203 // state values.
204 bool CompareModelTypeSetToModelTypeStateMap(
205 ModelTypeSet lhs,
206 const ModelTypeStateMap& rhs) {
207 size_t count = 0;
208 for (ModelTypeStateMap::const_iterator i = rhs.begin();
209 i != rhs.end(); ++i, ++count) {
210 if (!lhs.Has(i->first))
211 return false;
213 if (lhs.Size() != count)
214 return false;
215 return true;
218 SyncSessionContext* context() { return context_.get(); }
220 private:
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_;
231 MockSyncer* syncer_;
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())
247 QuitLoopNow();
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()) {
255 QuitLoopNow();
259 ACTION(AddFailureAndQuitLoopNow) {
260 ADD_FAILURE();
261 QuitLoopNow();
264 ACTION(QuitLoopNowAction) {
265 QuitLoopNow();
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);
282 RunLoop();
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);
301 RunLoop();
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
311 // errors.
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,
325 model_types,
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,
358 model_types,
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());
365 RunLoop();
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,
400 model_types,
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);
409 RunLoop();
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);
418 RunLoop();
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);
444 SyncShareRecords r;
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);
455 RunLoop();
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());
466 SyncShareRecords r2;
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);
472 RunLoop();
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);
485 SyncShareRecords r;
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;
503 RunLoop();
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);
529 RunLoop();
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);
547 RunLoop();
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);
559 SyncShareRecords r;
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);
573 RunLoop();
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());
586 SyncShareRecords r2;
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);
592 RunLoop();
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.
614 RunLoop();
616 StopSyncScheduler();
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.
635 RunLoop();
637 StopSyncScheduler();
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)))
650 .WillRepeatedly(
651 DoAll(Invoke(sessions::test_util::SimulateSuccess),
652 WithArg<0>(
653 RecordSyncShareMultiple(&records, kMinNumSamples))));
655 TimeTicks optimal_start = TimeTicks::Now() + poll1 + poll2;
656 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
658 // Run again to wait for polling.
659 RunLoop();
661 StopSyncScheduler();
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(_,_,_))
673 .WillOnce(
674 DoAll(
675 WithArg<0>(
676 sessions::test_util::SimulateSessionsCommitDelayUpdate(
677 delay2)),
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);
688 RunLoop();
690 EXPECT_EQ(delay2, scheduler()->GetSessionsCommitDelay());
691 StopSyncScheduler();
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);
704 RunLoop();
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);
739 PumpLoop();
741 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
743 CallbackCounter counter;
744 ConfigurationParams params(
745 GetUpdatesCallerInfo::RECONFIGURATION,
746 types,
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.
771 RunLoop();
773 StopSyncScheduler();
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,
800 config_types,
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));
829 PumpLoop();
832 class BackoffTriggersSyncSchedulerTest : public SyncSchedulerTest {
833 void SetUp() {
834 SyncSchedulerTest::SetUp();
835 UseMockDelayProvider();
836 EXPECT_CALL(*delay(), GetDelay(_))
837 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(1)));
840 void TearDown() {
841 StopSyncScheduler();
842 SyncSchedulerTest::TearDown();
846 // Have the sycner fail during commit. Expect that the scheduler enters
847 // backoff.
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) {
899 SyncShareRecords r;
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);
916 RunLoop();
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);
931 RunLoop();
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,
946 types,
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) {
955 SyncShareRecords r;
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);
984 RunLoop();
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) {
995 SyncShareRecords r;
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);
1016 RunLoop();
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) {
1046 SyncShareRecords r;
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.
1060 RunLoop();
1061 EXPECT_FALSE(scheduler()->IsBackingOff());
1063 // Run the successful poll.
1064 RunLoop();
1065 EXPECT_FALSE(scheduler()->IsBackingOff());
1068 // Test that appropriate syncer steps are requested for each job type.
1069 TEST_F(SyncSchedulerTest, SyncerSteps) {
1070 // Nudges.
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);
1077 PumpLoop();
1078 // Pump again to run job.
1079 PumpLoop();
1081 StopSyncScheduler();
1082 Mock::VerifyAndClearExpectations(syncer());
1084 // Configuration.
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,
1093 model_types,
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);
1104 // Poll.
1105 EXPECT_CALL(*syncer(), SyncShare(_, SYNCER_BEGIN, SYNCER_END))
1106 .Times(AtLeast(1))
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.
1115 RunLoop();
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