Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(422)

Side by Side Diff: chrome/browser/sync/engine/sync_scheduler_unittest.cc

Issue 9699057: [Sync] Move 'sync' target to sync/ (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address Tim's comments Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
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 "chrome/browser/sync/engine/sync_scheduler.h"
12 #include "chrome/browser/sync/engine/syncer.h"
13 #include "chrome/browser/sync/sessions/test_util.h"
14 #include "chrome/browser/sync/test/engine/fake_model_safe_worker_registrar.h"
15 #include "chrome/browser/sync/test/engine/mock_connection_manager.h"
16 #include "chrome/browser/sync/test/engine/test_directory_setter_upper.h"
17 #include "chrome/browser/sync/test/fake_extensions_activity_monitor.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20
21 using base::TimeDelta;
22 using base::TimeTicks;
23 using testing::_;
24 using testing::AtLeast;
25 using testing::DoAll;
26 using testing::Eq;
27 using testing::Invoke;
28 using testing::Mock;
29 using testing::Return;
30 using testing::WithArg;
31
32 namespace browser_sync {
33 using sessions::SyncSession;
34 using sessions::SyncSessionContext;
35 using sessions::SyncSessionSnapshot;
36 using syncable::ModelTypeSet;
37 using sync_pb::GetUpdatesCallerInfo;
38
39 class MockSyncer : public Syncer {
40 public:
41 MOCK_METHOD3(SyncShare, void(sessions::SyncSession*, SyncerStep,
42 SyncerStep));
43 };
44
45 // Used when tests want to record syncing activity to examine later.
46 struct SyncShareRecords {
47 std::vector<TimeTicks> times;
48 std::vector<linked_ptr<SyncSessionSnapshot> > snapshots;
49 };
50
51 void QuitLoopNow() {
52 // We use QuitNow() instead of Quit() as the latter may get stalled
53 // indefinitely in the presence of repeated timers with low delays
54 // and a slow test (e.g., ThrottlingDoesThrottle [which has a poll
55 // delay of 5ms] run under TSAN on the trybots).
56 MessageLoop::current()->QuitNow();
57 }
58
59 void RunLoop() {
60 MessageLoop::current()->Run();
61 }
62
63 void PumpLoop() {
64 // Do it this way instead of RunAllPending to pump loop exactly once
65 // (necessary in the presence of timers; see comment in
66 // QuitLoopNow).
67 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&QuitLoopNow));
68 RunLoop();
69 }
70
71 // Convenient to use in tests wishing to analyze SyncShare calls over time.
72 static const size_t kMinNumSamples = 5;
73 class SyncSchedulerTest : public testing::Test {
74 public:
75 SyncSchedulerTest()
76 : weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
77 context_(NULL),
78 syncer_(NULL),
79 delay_(NULL) {}
80
81 class MockDelayProvider : public SyncScheduler::DelayProvider {
82 public:
83 MOCK_METHOD1(GetDelay, TimeDelta(const TimeDelta&));
84 };
85
86 virtual void SetUp() {
87 dir_maker_.SetUp();
88 syncer_ = new MockSyncer();
89 delay_ = NULL;
90 ModelSafeRoutingInfo routing_info;
91 routing_info[syncable::BOOKMARKS] = GROUP_UI;
92 routing_info[syncable::AUTOFILL] = GROUP_DB;
93 routing_info[syncable::THEMES] = GROUP_UI;
94 routing_info[syncable::NIGORI] = GROUP_PASSIVE;
95 registrar_.reset(new FakeModelSafeWorkerRegistrar(routing_info));
96 connection_.reset(new MockConnectionManager(directory()));
97 connection_->SetServerReachable();
98 context_ = new SyncSessionContext(
99 connection_.get(), directory(), registrar_.get(),
100 &extensions_activity_monitor_,
101 std::vector<SyncEngineEventListener*>(), NULL);
102 context_->set_notifications_enabled(true);
103 context_->set_account_name("Test");
104 scheduler_.reset(
105 new SyncScheduler("TestSyncScheduler", context_, syncer_));
106 }
107
108 SyncScheduler* scheduler() { return scheduler_.get(); }
109 MockSyncer* syncer() { return syncer_; }
110 MockDelayProvider* delay() { return delay_; }
111 MockConnectionManager* connection() { return connection_.get(); }
112 TimeDelta zero() { return TimeDelta::FromSeconds(0); }
113 TimeDelta timeout() {
114 return TimeDelta::FromMilliseconds(TestTimeouts::action_timeout_ms());
115 }
116
117 virtual void TearDown() {
118 PumpLoop();
119 scheduler_.reset();
120 PumpLoop();
121 dir_maker_.TearDown();
122 }
123
124 void AnalyzePollRun(const SyncShareRecords& records, size_t min_num_samples,
125 const TimeTicks& optimal_start, const TimeDelta& poll_interval) {
126 const std::vector<TimeTicks>& data(records.times);
127 EXPECT_GE(data.size(), min_num_samples);
128 for (size_t i = 0; i < data.size(); i++) {
129 SCOPED_TRACE(testing::Message() << "SyncShare # (" << i << ")");
130 TimeTicks optimal_next_sync = optimal_start + poll_interval * i;
131 EXPECT_GE(data[i], optimal_next_sync);
132 EXPECT_EQ(GetUpdatesCallerInfo::PERIODIC,
133 records.snapshots[i]->source.updates_source);
134 }
135 }
136
137 void DoQuitLoopNow() {
138 QuitLoopNow();
139 }
140
141 void StartSyncScheduler(SyncScheduler::Mode mode) {
142 scheduler()->Start(
143 mode,
144 base::Bind(&SyncSchedulerTest::DoQuitLoopNow,
145 weak_ptr_factory_.GetWeakPtr()));
146 }
147
148 // This stops the scheduler synchronously.
149 void StopSyncScheduler() {
150 scheduler()->RequestStop(base::Bind(&SyncSchedulerTest::DoQuitLoopNow,
151 weak_ptr_factory_.GetWeakPtr()));
152 RunLoop();
153 }
154
155 bool RunAndGetBackoff() {
156 ModelTypeSet nudge_types;
157 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
158 RunLoop();
159
160 scheduler()->ScheduleNudge(
161 zero(), NUDGE_SOURCE_LOCAL, nudge_types, FROM_HERE);
162 RunLoop();
163
164 return scheduler()->IsBackingOff();
165 }
166
167 void UseMockDelayProvider() {
168 delay_ = new MockDelayProvider();
169 scheduler_->delay_provider_.reset(delay_);
170 }
171
172 // Compare a ModelTypeSet to a ModelTypePayloadMap, ignoring
173 // payload values.
174 bool CompareModelTypeSetToModelTypePayloadMap(
175 ModelTypeSet lhs,
176 const syncable::ModelTypePayloadMap& rhs) {
177 size_t count = 0;
178 for (syncable::ModelTypePayloadMap::const_iterator i = rhs.begin();
179 i != rhs.end(); ++i, ++count) {
180 if (!lhs.Has(i->first))
181 return false;
182 }
183 if (lhs.Size() != count)
184 return false;
185 return true;
186 }
187
188 SyncSessionContext* context() { return context_; }
189
190 private:
191 syncable::Directory* directory() {
192 return dir_maker_.directory();
193 }
194
195 base::WeakPtrFactory<SyncSchedulerTest> weak_ptr_factory_;
196 MessageLoop message_loop_;
197 TestDirectorySetterUpper dir_maker_;
198 scoped_ptr<SyncScheduler> scheduler_;
199 scoped_ptr<MockConnectionManager> connection_;
200 SyncSessionContext* context_;
201 MockSyncer* syncer_;
202 MockDelayProvider* delay_;
203 scoped_ptr<FakeModelSafeWorkerRegistrar> registrar_;
204 FakeExtensionsActivityMonitor extensions_activity_monitor_;
205 };
206
207 class BackoffTriggersSyncSchedulerTest : public SyncSchedulerTest {
208 void SetUp() {
209 SyncSchedulerTest::SetUp();
210 UseMockDelayProvider();
211 EXPECT_CALL(*delay(), GetDelay(_))
212 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(1)));
213 }
214
215 void TearDown() {
216 StopSyncScheduler();
217 SyncSchedulerTest::TearDown();
218 }
219 };
220
221 void RecordSyncShareImpl(SyncSession* s, SyncShareRecords* record) {
222 record->times.push_back(TimeTicks::Now());
223 record->snapshots.push_back(make_linked_ptr(new SyncSessionSnapshot(
224 s->TakeSnapshot())));
225 }
226
227 ACTION_P(RecordSyncShare, record) {
228 RecordSyncShareImpl(arg0, record);
229 QuitLoopNow();
230 }
231
232 ACTION_P2(RecordSyncShareMultiple, record, quit_after) {
233 RecordSyncShareImpl(arg0, record);
234 EXPECT_LE(record->times.size(), quit_after);
235 if (record->times.size() >= quit_after) {
236 QuitLoopNow();
237 }
238 }
239
240 ACTION(AddFailureAndQuitLoopNow) {
241 ADD_FAILURE();
242 QuitLoopNow();
243 }
244
245 ACTION(QuitLoopNowAction) {
246 QuitLoopNow();
247 }
248
249 // Test nudge scheduling.
250 TEST_F(SyncSchedulerTest, Nudge) {
251 SyncShareRecords records;
252 ModelTypeSet model_types(syncable::BOOKMARKS);
253
254 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
255 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
256 WithArg<0>(RecordSyncShare(&records))))
257 .RetiresOnSaturation();
258
259 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
260 RunLoop();
261
262 scheduler()->ScheduleNudge(
263 zero(), NUDGE_SOURCE_LOCAL, model_types, FROM_HERE);
264 RunLoop();
265
266 ASSERT_EQ(1U, records.snapshots.size());
267 EXPECT_TRUE(CompareModelTypeSetToModelTypePayloadMap(model_types,
268 records.snapshots[0]->source.types));
269 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL,
270 records.snapshots[0]->source.updates_source);
271
272 Mock::VerifyAndClearExpectations(syncer());
273
274 // Make sure a second, later, nudge is unaffected by first (no coalescing).
275 SyncShareRecords records2;
276 model_types.Remove(syncable::BOOKMARKS);
277 model_types.Put(syncable::AUTOFILL);
278 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
279 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
280 WithArg<0>(RecordSyncShare(&records2))));
281 scheduler()->ScheduleNudge(
282 zero(), NUDGE_SOURCE_LOCAL, model_types, FROM_HERE);
283 RunLoop();
284
285 ASSERT_EQ(1U, records2.snapshots.size());
286 EXPECT_TRUE(CompareModelTypeSetToModelTypePayloadMap(model_types,
287 records2.snapshots[0]->source.types));
288 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL,
289 records2.snapshots[0]->source.updates_source);
290 }
291
292 // Make sure a regular config command is scheduled fine in the absence of any
293 // errors.
294 TEST_F(SyncSchedulerTest, Config) {
295 SyncShareRecords records;
296 const ModelTypeSet model_types(syncable::BOOKMARKS);
297
298 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
299 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
300 WithArg<0>(RecordSyncShare(&records))));
301
302 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
303 RunLoop();
304
305 scheduler()->ScheduleConfig(
306 model_types, GetUpdatesCallerInfo::RECONFIGURATION);
307 RunLoop();
308
309 ASSERT_EQ(1U, records.snapshots.size());
310 EXPECT_TRUE(CompareModelTypeSetToModelTypePayloadMap(model_types,
311 records.snapshots[0]->source.types));
312 EXPECT_EQ(GetUpdatesCallerInfo::RECONFIGURATION,
313 records.snapshots[0]->source.updates_source);
314 }
315
316 // Simulate a failure and make sure the config request is retried.
317 TEST_F(SyncSchedulerTest, ConfigWithBackingOff) {
318 UseMockDelayProvider();
319 EXPECT_CALL(*delay(), GetDelay(_))
320 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(1)));
321 SyncShareRecords records;
322 const ModelTypeSet model_types(syncable::BOOKMARKS);
323
324 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
325 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
326 WithArg<0>(RecordSyncShare(&records))))
327 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
328 WithArg<0>(RecordSyncShare(&records))));
329
330 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
331 RunLoop();
332
333 ASSERT_EQ(0U, records.snapshots.size());
334 scheduler()->ScheduleConfig(
335 model_types, GetUpdatesCallerInfo::RECONFIGURATION);
336 RunLoop();
337
338 ASSERT_EQ(1U, records.snapshots.size());
339 RunLoop();
340
341 ASSERT_EQ(2U, records.snapshots.size());
342 EXPECT_TRUE(CompareModelTypeSetToModelTypePayloadMap(model_types,
343 records.snapshots[1]->source.types));
344 EXPECT_EQ(GetUpdatesCallerInfo::RECONFIGURATION,
345 records.snapshots[1]->source.updates_source);
346 }
347
348 // Issue 2 config commands. Second one right after the first has failed
349 // and make sure LATEST is executed.
350 TEST_F(SyncSchedulerTest, MultipleConfigWithBackingOff) {
351 const ModelTypeSet
352 model_types1(syncable::BOOKMARKS),
353 model_types2(syncable::AUTOFILL);
354 UseMockDelayProvider();
355 EXPECT_CALL(*delay(), GetDelay(_))
356 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(30)));
357 SyncShareRecords records;
358
359 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
360 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
361 WithArg<0>(RecordSyncShare(&records))))
362 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
363 WithArg<0>(RecordSyncShare(&records))))
364 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
365 WithArg<0>(RecordSyncShare(&records))));
366
367 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
368 RunLoop();
369
370 ASSERT_EQ(0U, records.snapshots.size());
371 scheduler()->ScheduleConfig(
372 model_types1, GetUpdatesCallerInfo::RECONFIGURATION);
373 RunLoop();
374
375 ASSERT_EQ(1U, records.snapshots.size());
376 scheduler()->ScheduleConfig(
377 model_types2, GetUpdatesCallerInfo::RECONFIGURATION);
378 RunLoop();
379
380 ASSERT_EQ(2U, records.snapshots.size());
381 RunLoop();
382
383 ASSERT_EQ(3U, records.snapshots.size());
384 EXPECT_TRUE(CompareModelTypeSetToModelTypePayloadMap(model_types2,
385 records.snapshots[2]->source.types));
386 EXPECT_EQ(GetUpdatesCallerInfo::RECONFIGURATION,
387 records.snapshots[2]->source.updates_source);
388 }
389
390 // Issue a nudge when the config has failed. Make sure both the config and
391 // nudge are executed.
392 TEST_F(SyncSchedulerTest, NudgeWithConfigWithBackingOff) {
393 const ModelTypeSet model_types(syncable::BOOKMARKS);
394 UseMockDelayProvider();
395 EXPECT_CALL(*delay(), GetDelay(_))
396 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(50)));
397 SyncShareRecords records;
398
399 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
400 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
401 WithArg<0>(RecordSyncShare(&records))))
402 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
403 WithArg<0>(RecordSyncShare(&records))))
404 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
405 WithArg<0>(RecordSyncShare(&records))))
406 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
407 WithArg<0>(RecordSyncShare(&records))));
408
409 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
410 RunLoop();
411
412 ASSERT_EQ(0U, records.snapshots.size());
413 scheduler()->ScheduleConfig(
414 model_types, GetUpdatesCallerInfo::RECONFIGURATION);
415 RunLoop();
416
417 ASSERT_EQ(1U, records.snapshots.size());
418 scheduler()->ScheduleNudge(
419 zero(), NUDGE_SOURCE_LOCAL, model_types, FROM_HERE);
420 RunLoop();
421
422 ASSERT_EQ(2U, records.snapshots.size());
423 RunLoop();
424
425 // Now change the mode so nudge can execute.
426 ASSERT_EQ(3U, records.snapshots.size());
427 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
428 RunLoop();
429
430 ASSERT_EQ(4U, records.snapshots.size());
431
432 EXPECT_TRUE(CompareModelTypeSetToModelTypePayloadMap(model_types,
433 records.snapshots[2]->source.types));
434 EXPECT_EQ(GetUpdatesCallerInfo::RECONFIGURATION,
435 records.snapshots[2]->source.updates_source);
436
437 EXPECT_TRUE(CompareModelTypeSetToModelTypePayloadMap(model_types,
438 records.snapshots[3]->source.types));
439 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL,
440 records.snapshots[3]->source.updates_source);
441
442 }
443
444 // Test that nudges are coalesced.
445 TEST_F(SyncSchedulerTest, NudgeCoalescing) {
446 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
447 RunLoop();
448
449 SyncShareRecords r;
450 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
451 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
452 WithArg<0>(RecordSyncShare(&r))));
453 const ModelTypeSet
454 types1(syncable::BOOKMARKS),
455 types2(syncable::AUTOFILL),
456 types3(syncable::THEMES);
457 TimeDelta delay = zero();
458 TimeTicks optimal_time = TimeTicks::Now() + delay;
459 scheduler()->ScheduleNudge(
460 delay, NUDGE_SOURCE_UNKNOWN, types1, FROM_HERE);
461 scheduler()->ScheduleNudge(
462 zero(), NUDGE_SOURCE_LOCAL, types2, FROM_HERE);
463 RunLoop();
464
465 ASSERT_EQ(1U, r.snapshots.size());
466 EXPECT_GE(r.times[0], optimal_time);
467 EXPECT_TRUE(CompareModelTypeSetToModelTypePayloadMap(
468 Union(types1, types2), r.snapshots[0]->source.types));
469 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL,
470 r.snapshots[0]->source.updates_source);
471
472 Mock::VerifyAndClearExpectations(syncer());
473
474 SyncShareRecords r2;
475 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
476 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
477 WithArg<0>(RecordSyncShare(&r2))));
478 scheduler()->ScheduleNudge(
479 zero(), NUDGE_SOURCE_NOTIFICATION, types3, FROM_HERE);
480 RunLoop();
481
482 ASSERT_EQ(1U, r2.snapshots.size());
483 EXPECT_TRUE(CompareModelTypeSetToModelTypePayloadMap(types3,
484 r2.snapshots[0]->source.types));
485 EXPECT_EQ(GetUpdatesCallerInfo::NOTIFICATION,
486 r2.snapshots[0]->source.updates_source);
487 }
488
489 // Test that nudges are coalesced.
490 TEST_F(SyncSchedulerTest, NudgeCoalescingWithDifferentTimings) {
491 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
492 RunLoop();
493
494 SyncShareRecords r;
495 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
496 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
497 WithArg<0>(RecordSyncShare(&r))));
498 syncable::ModelTypeSet types1(syncable::BOOKMARKS),
499 types2(syncable::AUTOFILL), types3;
500
501 // Create a huge time delay.
502 TimeDelta delay = TimeDelta::FromDays(1);
503
504 scheduler()->ScheduleNudge(
505 delay, NUDGE_SOURCE_UNKNOWN, types1, FROM_HERE);
506
507 scheduler()->ScheduleNudge(
508 zero(), NUDGE_SOURCE_UNKNOWN, types2, FROM_HERE);
509
510 TimeTicks min_time = TimeTicks::Now();
511 TimeTicks max_time = TimeTicks::Now() + delay;
512
513 RunLoop();
514
515 // Make sure the sync has happened.
516 ASSERT_EQ(1U, r.snapshots.size());
517 EXPECT_TRUE(CompareModelTypeSetToModelTypePayloadMap(
518 Union(types1, types2), r.snapshots[0]->source.types));
519
520 // Make sure the sync happened at the right time.
521 EXPECT_GE(r.times[0], min_time);
522 EXPECT_LE(r.times[0], max_time);
523 }
524
525 // Test nudge scheduling.
526 TEST_F(SyncSchedulerTest, NudgeWithPayloads) {
527 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
528 RunLoop();
529
530 SyncShareRecords records;
531 syncable::ModelTypePayloadMap model_types_with_payloads;
532 model_types_with_payloads[syncable::BOOKMARKS] = "test";
533
534 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
535 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
536 WithArg<0>(RecordSyncShare(&records))))
537 .RetiresOnSaturation();
538 scheduler()->ScheduleNudgeWithPayloads(
539 zero(), NUDGE_SOURCE_LOCAL, model_types_with_payloads, FROM_HERE);
540 RunLoop();
541
542 ASSERT_EQ(1U, records.snapshots.size());
543 EXPECT_EQ(model_types_with_payloads, records.snapshots[0]->source.types);
544 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL,
545 records.snapshots[0]->source.updates_source);
546
547 Mock::VerifyAndClearExpectations(syncer());
548
549 // Make sure a second, later, nudge is unaffected by first (no coalescing).
550 SyncShareRecords records2;
551 model_types_with_payloads.erase(syncable::BOOKMARKS);
552 model_types_with_payloads[syncable::AUTOFILL] = "test2";
553 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
554 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
555 WithArg<0>(RecordSyncShare(&records2))));
556 scheduler()->ScheduleNudgeWithPayloads(
557 zero(), NUDGE_SOURCE_LOCAL, model_types_with_payloads, FROM_HERE);
558 RunLoop();
559
560 ASSERT_EQ(1U, records2.snapshots.size());
561 EXPECT_EQ(model_types_with_payloads, records2.snapshots[0]->source.types);
562 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL,
563 records2.snapshots[0]->source.updates_source);
564 }
565
566 // Test that nudges are coalesced.
567 TEST_F(SyncSchedulerTest, NudgeWithPayloadsCoalescing) {
568 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
569 RunLoop();
570
571 SyncShareRecords r;
572 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
573 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
574 WithArg<0>(RecordSyncShare(&r))));
575 syncable::ModelTypePayloadMap types1, types2, types3;
576 types1[syncable::BOOKMARKS] = "test1";
577 types2[syncable::AUTOFILL] = "test2";
578 types3[syncable::THEMES] = "test3";
579 TimeDelta delay = zero();
580 TimeTicks optimal_time = TimeTicks::Now() + delay;
581 scheduler()->ScheduleNudgeWithPayloads(
582 delay, NUDGE_SOURCE_UNKNOWN, types1, FROM_HERE);
583 scheduler()->ScheduleNudgeWithPayloads(
584 zero(), NUDGE_SOURCE_LOCAL, types2, FROM_HERE);
585 RunLoop();
586
587 ASSERT_EQ(1U, r.snapshots.size());
588 EXPECT_GE(r.times[0], optimal_time);
589 syncable::ModelTypePayloadMap coalesced_types;
590 syncable::CoalescePayloads(&coalesced_types, types1);
591 syncable::CoalescePayloads(&coalesced_types, types2);
592 EXPECT_EQ(coalesced_types, r.snapshots[0]->source.types);
593 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL,
594 r.snapshots[0]->source.updates_source);
595
596 Mock::VerifyAndClearExpectations(syncer());
597
598 SyncShareRecords r2;
599 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
600 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
601 WithArg<0>(RecordSyncShare(&r2))));
602 scheduler()->ScheduleNudgeWithPayloads(
603 zero(), NUDGE_SOURCE_NOTIFICATION, types3, FROM_HERE);
604 RunLoop();
605
606 ASSERT_EQ(1U, r2.snapshots.size());
607 EXPECT_EQ(types3, r2.snapshots[0]->source.types);
608 EXPECT_EQ(GetUpdatesCallerInfo::NOTIFICATION,
609 r2.snapshots[0]->source.updates_source);
610 }
611
612 // Test that polling works as expected.
613 TEST_F(SyncSchedulerTest, Polling) {
614 SyncShareRecords records;
615 TimeDelta poll_interval(TimeDelta::FromMilliseconds(30));
616 EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(AtLeast(kMinNumSamples))
617 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess),
618 WithArg<0>(RecordSyncShareMultiple(&records, kMinNumSamples))));
619
620 scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval);
621
622 TimeTicks optimal_start = TimeTicks::Now() + poll_interval;
623 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
624 RunLoop();
625
626 // Run again to wait for polling.
627 RunLoop();
628
629 StopSyncScheduler();
630 AnalyzePollRun(records, kMinNumSamples, optimal_start, poll_interval);
631 }
632
633 // Test that the short poll interval is used.
634 TEST_F(SyncSchedulerTest, PollNotificationsDisabled) {
635 SyncShareRecords records;
636 TimeDelta poll_interval(TimeDelta::FromMilliseconds(30));
637 EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(AtLeast(kMinNumSamples))
638 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess),
639 WithArg<0>(RecordSyncShareMultiple(&records, kMinNumSamples))));
640
641 scheduler()->OnReceivedShortPollIntervalUpdate(poll_interval);
642 scheduler()->set_notifications_enabled(false);
643
644 TimeTicks optimal_start = TimeTicks::Now() + poll_interval;
645 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
646 RunLoop();
647
648 // Run again to wait for polling.
649 RunLoop();
650
651 StopSyncScheduler();
652 AnalyzePollRun(records, kMinNumSamples, optimal_start, poll_interval);
653 }
654
655 // Test that polling intervals are updated when needed.
656 TEST_F(SyncSchedulerTest, PollIntervalUpdate) {
657 SyncShareRecords records;
658 TimeDelta poll1(TimeDelta::FromMilliseconds(120));
659 TimeDelta poll2(TimeDelta::FromMilliseconds(30));
660 scheduler()->OnReceivedLongPollIntervalUpdate(poll1);
661 EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(AtLeast(kMinNumSamples))
662 .WillOnce(WithArg<0>(
663 sessions::test_util::SimulatePollIntervalUpdate(poll2)))
664 .WillRepeatedly(
665 DoAll(Invoke(sessions::test_util::SimulateSuccess),
666 WithArg<0>(
667 RecordSyncShareMultiple(&records, kMinNumSamples))));
668
669 TimeTicks optimal_start = TimeTicks::Now() + poll1 + poll2;
670 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
671 RunLoop();
672
673 // Run again to wait for polling.
674 RunLoop();
675
676 StopSyncScheduler();
677 AnalyzePollRun(records, kMinNumSamples, optimal_start, poll2);
678 }
679
680 // Test that the sessions commit delay is updated when needed.
681 TEST_F(SyncSchedulerTest, SessionsCommitDelay) {
682 SyncShareRecords records;
683 TimeDelta delay1(TimeDelta::FromMilliseconds(120));
684 TimeDelta delay2(TimeDelta::FromMilliseconds(30));
685 scheduler()->OnReceivedSessionsCommitDelay(delay1);
686
687 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
688 .WillOnce(
689 DoAll(
690 WithArg<0>(
691 sessions::test_util::SimulateSessionsCommitDelayUpdate(
692 delay2)),
693 Invoke(sessions::test_util::SimulateSuccess),
694 QuitLoopNowAction()));
695
696 EXPECT_EQ(delay1, scheduler()->sessions_commit_delay());
697 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
698 RunLoop();
699
700 EXPECT_EQ(delay1, scheduler()->sessions_commit_delay());
701 const ModelTypeSet model_types(syncable::BOOKMARKS);
702 scheduler()->ScheduleNudge(
703 zero(), NUDGE_SOURCE_LOCAL, model_types, FROM_HERE);
704 RunLoop();
705
706 EXPECT_EQ(delay2, scheduler()->sessions_commit_delay());
707 StopSyncScheduler();
708 }
709
710 // Test that a sync session is run through to completion.
711 TEST_F(SyncSchedulerTest, HasMoreToSync) {
712 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
713 .WillOnce(Invoke(sessions::test_util::SimulateHasMoreToSync))
714 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
715 QuitLoopNowAction()));
716 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
717 RunLoop();
718
719 scheduler()->ScheduleNudge(
720 zero(), NUDGE_SOURCE_LOCAL, ModelTypeSet(), FROM_HERE);
721 RunLoop();
722 // If more nudges are scheduled, they'll be waited on by TearDown, and would
723 // cause our expectation to break.
724 }
725
726 // Test that no syncing occurs when throttled.
727 TEST_F(SyncSchedulerTest, ThrottlingDoesThrottle) {
728 const ModelTypeSet types(syncable::BOOKMARKS);
729 TimeDelta poll(TimeDelta::FromMilliseconds(5));
730 TimeDelta throttle(TimeDelta::FromMinutes(10));
731 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
732 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
733 .WillOnce(WithArg<0>(sessions::test_util::SimulateThrottled(throttle)))
734 .WillRepeatedly(AddFailureAndQuitLoopNow());
735
736 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
737 RunLoop();
738
739 scheduler()->ScheduleNudge(
740 zero(), NUDGE_SOURCE_LOCAL, types, FROM_HERE);
741 PumpLoop();
742
743 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
744 RunLoop();
745
746 scheduler()->ScheduleConfig(
747 types, GetUpdatesCallerInfo::RECONFIGURATION);
748 PumpLoop();
749 }
750
751 TEST_F(SyncSchedulerTest, ThrottlingExpires) {
752 SyncShareRecords records;
753 TimeDelta poll(TimeDelta::FromMilliseconds(15));
754 TimeDelta throttle1(TimeDelta::FromMilliseconds(150));
755 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
756
757 ::testing::InSequence seq;
758 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
759 .WillOnce(WithArg<0>(sessions::test_util::SimulateThrottled(throttle1)))
760 .RetiresOnSaturation();
761 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
762 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess),
763 WithArg<0>(RecordSyncShareMultiple(&records, kMinNumSamples))));
764
765 TimeTicks optimal_start = TimeTicks::Now() + poll + throttle1;
766 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
767 RunLoop();
768
769 // Run again to wait for polling.
770 RunLoop();
771
772 StopSyncScheduler();
773 AnalyzePollRun(records, kMinNumSamples, optimal_start, poll);
774 }
775
776 // Test nudges / polls don't run in config mode and config tasks do.
777 TEST_F(SyncSchedulerTest, ConfigurationMode) {
778 TimeDelta poll(TimeDelta::FromMilliseconds(15));
779 SyncShareRecords records;
780 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
781 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
782 .WillOnce((Invoke(sessions::test_util::SimulateSuccess),
783 WithArg<0>(RecordSyncShare(&records))));
784
785 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
786 RunLoop();
787
788 const ModelTypeSet nudge_types(syncable::AUTOFILL);
789 scheduler()->ScheduleNudge(
790 zero(), NUDGE_SOURCE_LOCAL, nudge_types, FROM_HERE);
791 scheduler()->ScheduleNudge(
792 zero(), NUDGE_SOURCE_LOCAL, nudge_types, FROM_HERE);
793
794 const ModelTypeSet config_types(syncable::BOOKMARKS);
795
796 scheduler()->ScheduleConfig(
797 config_types, GetUpdatesCallerInfo::RECONFIGURATION);
798 RunLoop();
799
800 ASSERT_EQ(1U, records.snapshots.size());
801 EXPECT_TRUE(CompareModelTypeSetToModelTypePayloadMap(config_types,
802 records.snapshots[0]->source.types));
803 }
804
805 // Have the sycner fail during commit. Expect that the scheduler enters
806 // backoff.
807 TEST_F(BackoffTriggersSyncSchedulerTest, FailCommitOnce) {
808 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
809 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
810 QuitLoopNowAction()));
811 EXPECT_TRUE(RunAndGetBackoff());
812 }
813
814 // Have the syncer fail during download updates and succeed on the first
815 // retry. Expect that this clears the backoff state.
816 TEST_F(BackoffTriggersSyncSchedulerTest, FailDownloadOnceThenSucceed) {
817 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
818 .WillOnce(Invoke(sessions::test_util::SimulateDownloadUpdatesFailed))
819 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
820 QuitLoopNowAction()));
821 EXPECT_FALSE(RunAndGetBackoff());
822 }
823
824 // Have the syncer fail during commit and succeed on the first retry. Expect
825 // that this clears the backoff state.
826 TEST_F(BackoffTriggersSyncSchedulerTest, FailCommitOnceThenSucceed) {
827 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
828 .WillOnce(Invoke(sessions::test_util::SimulateCommitFailed))
829 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
830 QuitLoopNowAction()));
831 EXPECT_FALSE(RunAndGetBackoff());
832 }
833
834 // Have the syncer fail to download updates and fail again on the retry.
835 // Expect this will leave the scheduler in backoff.
836 TEST_F(BackoffTriggersSyncSchedulerTest, FailDownloadTwice) {
837 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
838 .WillOnce(Invoke(sessions::test_util::SimulateDownloadUpdatesFailed))
839 .WillRepeatedly(DoAll(
840 Invoke(sessions::test_util::SimulateDownloadUpdatesFailed),
841 QuitLoopNowAction()));
842 EXPECT_TRUE(RunAndGetBackoff());
843 }
844
845 // Test that no polls or extraneous nudges occur when in backoff.
846 TEST_F(SyncSchedulerTest, BackoffDropsJobs) {
847 SyncShareRecords r;
848 TimeDelta poll(TimeDelta::FromMilliseconds(5));
849 const ModelTypeSet types(syncable::BOOKMARKS);
850 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
851 UseMockDelayProvider();
852
853 EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(1)
854 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
855 RecordSyncShareMultiple(&r, 1U)));
856 EXPECT_CALL(*delay(), GetDelay(_)).
857 WillRepeatedly(Return(TimeDelta::FromDays(1)));
858
859 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
860 RunLoop();
861
862 // This nudge should fail and put us into backoff. Thanks to our mock
863 // GetDelay() setup above, this will be a long backoff.
864 scheduler()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL, types, FROM_HERE);
865 RunLoop();
866
867 Mock::VerifyAndClearExpectations(syncer());
868 ASSERT_EQ(1U, r.snapshots.size());
869 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL, r.snapshots[0]->source.updates_source);
870
871 EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(1)
872 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
873 RecordSyncShare(&r)));
874
875 // We schedule a nudge with enough delay (10X poll interval) that at least
876 // one or two polls would have taken place. The nudge should succeed.
877 scheduler()->ScheduleNudge(poll * 10, NUDGE_SOURCE_LOCAL, types, FROM_HERE);
878 RunLoop();
879
880 Mock::VerifyAndClearExpectations(syncer());
881 Mock::VerifyAndClearExpectations(delay());
882 ASSERT_EQ(2U, r.snapshots.size());
883 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL, r.snapshots[1]->source.updates_source);
884
885 EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(0);
886 EXPECT_CALL(*delay(), GetDelay(_)).Times(0);
887
888 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
889 RunLoop();
890
891 scheduler()->ScheduleConfig(
892 types, GetUpdatesCallerInfo::RECONFIGURATION);
893 PumpLoop();
894
895 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
896 RunLoop();
897
898 scheduler()->ScheduleNudge(
899 zero(), NUDGE_SOURCE_LOCAL, types, FROM_HERE);
900 scheduler()->ScheduleNudge(
901 zero(), NUDGE_SOURCE_LOCAL, types, FROM_HERE);
902 PumpLoop();
903 }
904
905 // Test that backoff is shaping traffic properly with consecutive errors.
906 TEST_F(SyncSchedulerTest, BackoffElevation) {
907 SyncShareRecords r;
908 UseMockDelayProvider();
909
910 EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(kMinNumSamples)
911 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
912 RecordSyncShareMultiple(&r, kMinNumSamples)));
913
914 const TimeDelta first = TimeDelta::FromSeconds(1);
915 const TimeDelta second = TimeDelta::FromMilliseconds(2);
916 const TimeDelta third = TimeDelta::FromMilliseconds(3);
917 const TimeDelta fourth = TimeDelta::FromMilliseconds(4);
918 const TimeDelta fifth = TimeDelta::FromMilliseconds(5);
919 const TimeDelta sixth = TimeDelta::FromDays(1);
920
921 EXPECT_CALL(*delay(), GetDelay(Eq(first))).WillOnce(Return(second))
922 .RetiresOnSaturation();
923 EXPECT_CALL(*delay(), GetDelay(Eq(second))).WillOnce(Return(third))
924 .RetiresOnSaturation();
925 EXPECT_CALL(*delay(), GetDelay(Eq(third))).WillOnce(Return(fourth))
926 .RetiresOnSaturation();
927 EXPECT_CALL(*delay(), GetDelay(Eq(fourth))).WillOnce(Return(fifth))
928 .RetiresOnSaturation();
929 EXPECT_CALL(*delay(), GetDelay(Eq(fifth))).WillOnce(Return(sixth));
930
931 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
932 RunLoop();
933
934 // Run again with a nudge.
935 scheduler()->ScheduleNudge(
936 zero(), NUDGE_SOURCE_LOCAL, ModelTypeSet(), FROM_HERE);
937 RunLoop();
938
939 ASSERT_EQ(kMinNumSamples, r.snapshots.size());
940 EXPECT_GE(r.times[1] - r.times[0], second);
941 EXPECT_GE(r.times[2] - r.times[1], third);
942 EXPECT_GE(r.times[3] - r.times[2], fourth);
943 EXPECT_GE(r.times[4] - r.times[3], fifth);
944 }
945
946 // Test that things go back to normal once a retry makes forward progress.
947 TEST_F(SyncSchedulerTest, BackoffRelief) {
948 SyncShareRecords r;
949 const TimeDelta poll(TimeDelta::FromMilliseconds(10));
950 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
951 UseMockDelayProvider();
952
953 const TimeDelta backoff = TimeDelta::FromMilliseconds(5);
954
955 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
956 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
957 RecordSyncShareMultiple(&r, kMinNumSamples)))
958 .WillRepeatedly(DoAll(Invoke(sessions::test_util::SimulateSuccess),
959 RecordSyncShareMultiple(&r, kMinNumSamples)));
960 EXPECT_CALL(*delay(), GetDelay(_)).WillOnce(Return(backoff));
961
962 // Optimal start for the post-backoff poll party.
963 TimeTicks optimal_start = TimeTicks::Now();
964 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
965 RunLoop();
966
967 // Run again to wait for polling.
968 scheduler()->ScheduleNudge(zero(), NUDGE_SOURCE_LOCAL,
969 ModelTypeSet(), FROM_HERE);
970 RunLoop();
971
972 StopSyncScheduler();
973
974 EXPECT_EQ(kMinNumSamples, r.times.size());
975
976 // The first nudge ran as soon as possible. It failed.
977 TimeTicks optimal_job_time = optimal_start;
978 EXPECT_GE(r.times[0], optimal_job_time);
979 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL,
980 r.snapshots[0]->source.updates_source);
981
982 // It was followed by a successful retry nudge shortly afterward.
983 optimal_job_time = optimal_job_time + backoff;
984 EXPECT_GE(r.times[1], optimal_job_time);
985 EXPECT_EQ(GetUpdatesCallerInfo::LOCAL,
986 r.snapshots[1]->source.updates_source);
987 // After that, we went back to polling.
988 for (size_t i = 2; i < r.snapshots.size(); i++) {
989 optimal_job_time = optimal_job_time + poll;
990 SCOPED_TRACE(testing::Message() << "SyncShare # (" << i << ")");
991 EXPECT_GE(r.times[i], optimal_job_time);
992 EXPECT_EQ(GetUpdatesCallerInfo::PERIODIC,
993 r.snapshots[i]->source.updates_source);
994 }
995 }
996
997 // Test that poll failures are ignored. They should have no effect on
998 // subsequent poll attempts, nor should they trigger a backoff/retry.
999 TEST_F(SyncSchedulerTest, TransientPollFailure) {
1000 SyncShareRecords r;
1001 const TimeDelta poll_interval(TimeDelta::FromMilliseconds(10));
1002 scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval);
1003 UseMockDelayProvider(); // Will cause test failure if backoff is initiated.
1004
1005 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
1006 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateCommitFailed),
1007 RecordSyncShare(&r)))
1008 .WillOnce(DoAll(Invoke(sessions::test_util::SimulateSuccess),
1009 RecordSyncShare(&r)));
1010
1011 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1012 RunLoop();
1013
1014 // Run the unsucessful poll. The failed poll should not trigger backoff.
1015 RunLoop();
1016 EXPECT_FALSE(scheduler()->IsBackingOff());
1017
1018 // Run the successful poll.
1019 RunLoop();
1020 EXPECT_FALSE(scheduler()->IsBackingOff());
1021
1022 // Verify the the two SyncShare() calls were made one poll interval apart.
1023 ASSERT_EQ(2U, r.snapshots.size());
1024 EXPECT_GE(r.times[1] - r.times[0], poll_interval);
1025 }
1026
1027 TEST_F(SyncSchedulerTest, GetRecommendedDelay) {
1028 EXPECT_LE(TimeDelta::FromSeconds(0),
1029 SyncScheduler::GetRecommendedDelay(TimeDelta::FromSeconds(0)));
1030 EXPECT_LE(TimeDelta::FromSeconds(1),
1031 SyncScheduler::GetRecommendedDelay(TimeDelta::FromSeconds(1)));
1032 EXPECT_LE(TimeDelta::FromSeconds(50),
1033 SyncScheduler::GetRecommendedDelay(TimeDelta::FromSeconds(50)));
1034 EXPECT_LE(TimeDelta::FromSeconds(10),
1035 SyncScheduler::GetRecommendedDelay(TimeDelta::FromSeconds(10)));
1036 EXPECT_EQ(TimeDelta::FromSeconds(kMaxBackoffSeconds),
1037 SyncScheduler::GetRecommendedDelay(
1038 TimeDelta::FromSeconds(kMaxBackoffSeconds)));
1039 EXPECT_EQ(TimeDelta::FromSeconds(kMaxBackoffSeconds),
1040 SyncScheduler::GetRecommendedDelay(
1041 TimeDelta::FromSeconds(kMaxBackoffSeconds + 1)));
1042 }
1043
1044 // Test that appropriate syncer steps are requested for each job type.
1045 TEST_F(SyncSchedulerTest, SyncerSteps) {
1046 // Nudges.
1047 EXPECT_CALL(*syncer(), SyncShare(_, SYNCER_BEGIN, SYNCER_END))
1048 .Times(1);
1049 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1050 RunLoop();
1051
1052 scheduler()->ScheduleNudge(
1053 zero(), NUDGE_SOURCE_LOCAL, ModelTypeSet(), FROM_HERE);
1054 PumpLoop();
1055 // Pump again to run job.
1056 PumpLoop();
1057
1058 StopSyncScheduler();
1059 Mock::VerifyAndClearExpectations(syncer());
1060
1061 // ClearUserData.
1062 EXPECT_CALL(*syncer(), SyncShare(_, CLEAR_PRIVATE_DATA, CLEAR_PRIVATE_DATA))
1063 .Times(1);
1064 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1065 RunLoop();
1066
1067 scheduler()->ScheduleClearUserData();
1068 PumpLoop();
1069 PumpLoop();
1070
1071 StopSyncScheduler();
1072 Mock::VerifyAndClearExpectations(syncer());
1073
1074 // Configuration.
1075 EXPECT_CALL(*syncer(), SyncShare(_, DOWNLOAD_UPDATES, APPLY_UPDATES));
1076 StartSyncScheduler(SyncScheduler::CONFIGURATION_MODE);
1077 RunLoop();
1078
1079 scheduler()->ScheduleConfig(
1080 ModelTypeSet(), GetUpdatesCallerInfo::RECONFIGURATION);
1081 PumpLoop();
1082 PumpLoop();
1083
1084 StopSyncScheduler();
1085 Mock::VerifyAndClearExpectations(syncer());
1086
1087 // Cleanup disabled types.
1088 EXPECT_CALL(*syncer(),
1089 SyncShare(_, CLEANUP_DISABLED_TYPES, CLEANUP_DISABLED_TYPES));
1090 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1091 RunLoop();
1092
1093 scheduler()->ScheduleCleanupDisabledTypes();
1094 // Only need to pump once, as ScheduleCleanupDisabledTypes()
1095 // schedules the job directly.
1096 PumpLoop();
1097
1098 StopSyncScheduler();
1099 Mock::VerifyAndClearExpectations(syncer());
1100
1101 // Poll.
1102 EXPECT_CALL(*syncer(), SyncShare(_, SYNCER_BEGIN, SYNCER_END))
1103 .Times(AtLeast(1))
1104 .WillRepeatedly(QuitLoopNowAction());
1105 const TimeDelta poll(TimeDelta::FromMilliseconds(10));
1106 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
1107
1108 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1109 RunLoop();
1110
1111 // Run again to wait for polling.
1112 RunLoop();
1113
1114 StopSyncScheduler();
1115 Mock::VerifyAndClearExpectations(syncer());
1116 }
1117
1118 // Test config tasks don't run during normal mode.
1119 // TODO(tim): Implement this test and then the functionality!
1120 TEST_F(SyncSchedulerTest, DISABLED_NoConfigDuringNormal) {
1121 }
1122
1123 // Test that starting the syncer thread without a valid connection doesn't
1124 // break things when a connection is detected.
1125 TEST_F(SyncSchedulerTest, StartWhenNotConnected) {
1126 connection()->SetServerNotReachable();
1127 EXPECT_CALL(*syncer(), SyncShare(_,_,_))
1128 .WillOnce(Invoke(sessions::test_util::SimulateDownloadUpdatesFailed))
1129 .WillOnce(QuitLoopNowAction());
1130 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1131 MessageLoop::current()->RunAllPending();
1132
1133 scheduler()->ScheduleNudge(
1134 zero(), NUDGE_SOURCE_LOCAL, ModelTypeSet(), FROM_HERE);
1135 // Should save the nudge for until after the server is reachable.
1136 MessageLoop::current()->RunAllPending();
1137
1138 connection()->SetServerReachable();
1139 scheduler()->OnConnectionStatusChange();
1140 MessageLoop::current()->RunAllPending();
1141 }
1142
1143 TEST_F(SyncSchedulerTest, SetsPreviousRoutingInfo) {
1144 ModelSafeRoutingInfo info;
1145 EXPECT_TRUE(info == context()->previous_session_routing_info());
1146 ModelSafeRoutingInfo expected;
1147 context()->registrar()->GetModelSafeRoutingInfo(&expected);
1148 ASSERT_FALSE(expected.empty());
1149 EXPECT_CALL(*syncer(), SyncShare(_,_,_)).Times(1);
1150
1151 StartSyncScheduler(SyncScheduler::NORMAL_MODE);
1152 RunLoop();
1153
1154 scheduler()->ScheduleNudge(
1155 zero(), NUDGE_SOURCE_LOCAL, ModelTypeSet(), FROM_HERE);
1156 PumpLoop();
1157 // Pump again to run job.
1158 PumpLoop();
1159
1160 StopSyncScheduler();
1161
1162 EXPECT_TRUE(expected == context()->previous_session_routing_info());
1163 }
1164
1165 } // namespace browser_sync
OLDNEW
« no previous file with comments | « chrome/browser/sync/engine/sync_scheduler.cc ('k') | chrome/browser/sync/engine/sync_scheduler_whitebox_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698