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

Side by Side Diff: components/sync/engine_impl/sync_scheduler_unittest.cc

Issue 2388973002: [Sync] Removing duplicate includes, part 2. (Closed)
Patch Set: Update for Max's comments. Created 4 years, 2 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
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 <stddef.h>
6 #include <stdint.h>
7
8 #include "base/bind.h"
9 #include "base/callback.h"
10 #include "base/compiler_specific.h"
11 #include "base/location.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/run_loop.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/test/test_timeouts.h"
16 #include "base/threading/thread_task_runner_handle.h"
17 #include "components/sync/base/cancelation_signal.h"
18 #include "components/sync/base/extensions_activity.h"
19 #include "components/sync/base/model_type_test_util.h"
20 #include "components/sync/engine_impl/backoff_delay_provider.h"
21 #include "components/sync/engine_impl/cycle/test_util.h"
22 #include "components/sync/engine_impl/sync_scheduler_impl.h"
23 #include "components/sync/engine_impl/syncer.h"
24 #include "components/sync/test/callback_counter.h"
25 #include "components/sync/test/engine/fake_model_worker.h"
26 #include "components/sync/test/engine/mock_connection_manager.h"
27 #include "components/sync/test/engine/mock_nudge_handler.h"
28 #include "components/sync/test/engine/test_directory_setter_upper.h"
29 #include "components/sync/test/mock_invalidation.h"
30 #include "testing/gmock/include/gmock/gmock.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32
33 using base::TimeDelta;
34 using base::TimeTicks;
35 using testing::_;
36 using testing::AtLeast;
37 using testing::DoAll;
38 using testing::Invoke;
39 using testing::Mock;
40 using testing::Return;
41 using testing::WithArg;
42 using testing::WithArgs;
43 using testing::WithoutArgs;
44
45 namespace syncer {
46
47 using sync_pb::GetUpdatesCallerInfo;
48
49 class MockSyncer : public Syncer {
50 public:
51 MockSyncer();
52 MOCK_METHOD3(NormalSyncShare, bool(ModelTypeSet, NudgeTracker*, SyncCycle*));
53 MOCK_METHOD3(ConfigureSyncShare,
54 bool(ModelTypeSet,
55 sync_pb::GetUpdatesCallerInfo::GetUpdatesSource,
56 SyncCycle*));
57 MOCK_METHOD2(PollSyncShare, bool(ModelTypeSet, SyncCycle*));
58 };
59
60 MockSyncer::MockSyncer() : Syncer(NULL) {}
61
62 typedef std::vector<TimeTicks> SyncShareTimes;
63
64 void QuitLoopNow() {
65 // We use QuitNow() instead of Quit() as the latter may get stalled
66 // indefinitely in the presence of repeated timers with low delays
67 // and a slow test (e.g., ThrottlingDoesThrottle [which has a poll
68 // delay of 5ms] run under TSAN on the trybots).
69 base::MessageLoop::current()->QuitNow();
70 }
71
72 void RunLoop() {
73 base::RunLoop().Run();
74 }
75
76 void PumpLoop() {
77 // Do it this way instead of RunAllPending to pump loop exactly once
78 // (necessary in the presence of timers; see comment in
79 // QuitLoopNow).
80 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
81 base::Bind(&QuitLoopNow));
82 RunLoop();
83 }
84
85 void PumpLoopFor(base::TimeDelta time) {
86 // Allow the loop to run for the specified amount of time.
87 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
88 FROM_HERE, base::Bind(&QuitLoopNow), time);
89 RunLoop();
90 }
91
92 ModelSafeRoutingInfo TypesToRoutingInfo(ModelTypeSet types) {
93 ModelSafeRoutingInfo routes;
94 for (ModelTypeSet::Iterator iter = types.First(); iter.Good(); iter.Inc()) {
95 routes[iter.Get()] = GROUP_PASSIVE;
96 }
97 return routes;
98 }
99
100 static const size_t kMinNumSamples = 5;
101
102 // Test harness for the SyncScheduler. Test the delays and backoff timers used
103 // in response to various events.
104 //
105 // These tests execute in real time with real timers. We try to keep the
106 // delays short, but there is a limit to how short we can make them. The
107 // timers on some platforms (ie. Windows) have a timer resolution greater than
108 // 1ms. Using 1ms delays may result in test flakiness.
109 //
110 // See crbug.com/402212 for more info.
111 class SyncSchedulerTest : public testing::Test {
112 public:
113 SyncSchedulerTest() : syncer_(NULL), delay_(NULL), weak_ptr_factory_(this) {}
114
115 class MockDelayProvider : public BackoffDelayProvider {
116 public:
117 MockDelayProvider()
118 : BackoffDelayProvider(
119 TimeDelta::FromSeconds(kInitialBackoffRetrySeconds),
120 TimeDelta::FromSeconds(kInitialBackoffImmediateRetrySeconds)) {}
121
122 MOCK_METHOD1(GetDelay, TimeDelta(const TimeDelta&));
123 };
124
125 void SetUp() override {
126 dir_maker_.SetUp();
127 syncer_ = new testing::StrictMock<MockSyncer>();
128 delay_ = NULL;
129 extensions_activity_ = new ExtensionsActivity();
130
131 routing_info_[THEMES] = GROUP_UI;
132 routing_info_[TYPED_URLS] = GROUP_DB;
133 routing_info_[THEMES] = GROUP_UI;
134 routing_info_[NIGORI] = GROUP_PASSIVE;
135
136 workers_.clear();
137 workers_.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_UI)));
138 workers_.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_DB)));
139 workers_.push_back(make_scoped_refptr(new FakeModelWorker(GROUP_PASSIVE)));
140
141 connection_.reset(
142 new MockConnectionManager(directory(), &cancelation_signal_));
143 connection_->SetServerReachable();
144
145 model_type_registry_.reset(
146 new ModelTypeRegistry(workers_, directory(), &mock_nudge_handler_));
147
148 context_.reset(new SyncCycleContext(
149 connection_.get(), directory(), extensions_activity_.get(),
150 std::vector<SyncEngineEventListener*>(), NULL,
151 model_type_registry_.get(),
152 true, // enable keystore encryption
153 false, // force enable pre-commit GU avoidance
154 "fake_invalidator_client_id"));
155 context_->SetRoutingInfo(routing_info_);
156 context_->set_notifications_enabled(true);
157 context_->set_account_name("Test");
158 scheduler_.reset(new SyncSchedulerImpl("TestSyncScheduler",
159 BackoffDelayProvider::FromDefaults(),
160 context(), syncer_));
161 scheduler_->SetDefaultNudgeDelay(default_delay());
162 }
163
164 SyncSchedulerImpl* scheduler() { return scheduler_.get(); }
165 const ModelSafeRoutingInfo& routing_info() { return routing_info_; }
166 MockSyncer* syncer() { return syncer_; }
167 MockDelayProvider* delay() { return delay_; }
168 MockConnectionManager* connection() { return connection_.get(); }
169 TimeDelta default_delay() { return TimeDelta::FromSeconds(0); }
170 TimeDelta timeout() { return TestTimeouts::action_timeout(); }
171
172 void TearDown() override {
173 PumpLoop();
174 scheduler_.reset();
175 PumpLoop();
176 dir_maker_.TearDown();
177 }
178
179 void AnalyzePollRun(const SyncShareTimes& times,
180 size_t min_num_samples,
181 const TimeTicks& optimal_start,
182 const TimeDelta& poll_interval) {
183 EXPECT_GE(times.size(), min_num_samples);
184 for (size_t i = 0; i < times.size(); i++) {
185 SCOPED_TRACE(testing::Message() << "SyncShare # (" << i << ")");
186 TimeTicks optimal_next_sync = optimal_start + poll_interval * i;
187 EXPECT_GE(times[i], optimal_next_sync);
188 }
189 }
190
191 void DoQuitLoopNow() { QuitLoopNow(); }
192
193 void StartSyncConfiguration() {
194 scheduler()->Start(SyncScheduler::CONFIGURATION_MODE, base::Time());
195 }
196
197 void StartSyncScheduler(base::Time last_poll_time) {
198 scheduler()->Start(SyncScheduler::NORMAL_MODE, last_poll_time);
199 }
200
201 // This stops the scheduler synchronously.
202 void StopSyncScheduler() {
203 base::ThreadTaskRunnerHandle::Get()->PostTask(
204 FROM_HERE, base::Bind(&SyncSchedulerTest::DoQuitLoopNow,
205 weak_ptr_factory_.GetWeakPtr()));
206 RunLoop();
207 }
208
209 bool RunAndGetBackoff() {
210 ModelTypeSet nudge_types(THEMES);
211 StartSyncScheduler(base::Time());
212
213 scheduler()->ScheduleLocalNudge(nudge_types, FROM_HERE);
214 RunLoop();
215
216 return scheduler()->IsBackingOff();
217 }
218
219 void UseMockDelayProvider() {
220 delay_ = new MockDelayProvider();
221 scheduler_->delay_provider_.reset(delay_);
222 }
223
224 SyncCycleContext* context() { return context_.get(); }
225
226 ModelTypeSet GetThrottledTypes() {
227 return scheduler_->nudge_tracker_.GetThrottledTypes();
228 }
229
230 base::TimeDelta GetRetryTimerDelay() {
231 EXPECT_TRUE(scheduler_->retry_timer_.IsRunning());
232 return scheduler_->retry_timer_.GetCurrentDelay();
233 }
234
235 static std::unique_ptr<InvalidationInterface> BuildInvalidation(
236 int64_t version,
237 const std::string& payload) {
238 return MockInvalidation::Build(version, payload);
239 }
240
241 private:
242 syncable::Directory* directory() { return dir_maker_.directory(); }
243
244 base::MessageLoop loop_;
245 TestDirectorySetterUpper dir_maker_;
246 CancelationSignal cancelation_signal_;
247 std::unique_ptr<MockConnectionManager> connection_;
248 std::unique_ptr<ModelTypeRegistry> model_type_registry_;
249 std::unique_ptr<SyncCycleContext> context_;
250 std::unique_ptr<SyncSchedulerImpl> scheduler_;
251 MockNudgeHandler mock_nudge_handler_;
252 MockSyncer* syncer_;
253 MockDelayProvider* delay_;
254 std::vector<scoped_refptr<ModelSafeWorker>> workers_;
255 scoped_refptr<ExtensionsActivity> extensions_activity_;
256 ModelSafeRoutingInfo routing_info_;
257 base::WeakPtrFactory<SyncSchedulerTest> weak_ptr_factory_;
258 };
259
260 void RecordSyncShareImpl(SyncShareTimes* times) {
261 times->push_back(TimeTicks::Now());
262 }
263
264 ACTION_P2(RecordSyncShare, times, success) {
265 RecordSyncShareImpl(times);
266 if (base::MessageLoop::current()->is_running())
267 QuitLoopNow();
268 return success;
269 }
270
271 ACTION_P3(RecordSyncShareMultiple, times, quit_after, success) {
272 RecordSyncShareImpl(times);
273 EXPECT_LE(times->size(), quit_after);
274 if (times->size() >= quit_after &&
275 base::MessageLoop::current()->is_running()) {
276 QuitLoopNow();
277 }
278 return success;
279 }
280
281 ACTION_P(StopScheduler, scheduler) {
282 scheduler->Stop();
283 }
284
285 ACTION(AddFailureAndQuitLoopNow) {
286 ADD_FAILURE();
287 QuitLoopNow();
288 return true;
289 }
290
291 ACTION_P(QuitLoopNowAction, success) {
292 QuitLoopNow();
293 return success;
294 }
295
296 // Test nudge scheduling.
297 TEST_F(SyncSchedulerTest, Nudge) {
298 SyncShareTimes times;
299 ModelTypeSet model_types(THEMES);
300
301 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
302 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess),
303 RecordSyncShare(&times, true)))
304 .RetiresOnSaturation();
305
306 StartSyncScheduler(base::Time());
307
308 scheduler()->ScheduleLocalNudge(model_types, FROM_HERE);
309 RunLoop();
310
311 Mock::VerifyAndClearExpectations(syncer());
312
313 // Make sure a second, later, nudge is unaffected by first (no coalescing).
314 SyncShareTimes times2;
315 model_types.Remove(THEMES);
316 model_types.Put(TYPED_URLS);
317 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
318 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess),
319 RecordSyncShare(&times2, true)));
320 scheduler()->ScheduleLocalNudge(model_types, FROM_HERE);
321 RunLoop();
322 }
323
324 // Make sure a regular config command is scheduled fine in the absence of any
325 // errors.
326 TEST_F(SyncSchedulerTest, Config) {
327 SyncShareTimes times;
328 const ModelTypeSet model_types(THEMES);
329
330 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
331 .WillOnce(DoAll(Invoke(test_util::SimulateConfigureSuccess),
332 RecordSyncShare(&times, true)));
333
334 StartSyncConfiguration();
335
336 CallbackCounter ready_counter;
337 CallbackCounter retry_counter;
338 ConfigurationParams params(
339 GetUpdatesCallerInfo::RECONFIGURATION, model_types,
340 TypesToRoutingInfo(model_types),
341 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
342 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
343 scheduler()->ScheduleConfiguration(params);
344 PumpLoop();
345 ASSERT_EQ(1, ready_counter.times_called());
346 ASSERT_EQ(0, retry_counter.times_called());
347 }
348
349 // Simulate a failure and make sure the config request is retried.
350 TEST_F(SyncSchedulerTest, ConfigWithBackingOff) {
351 UseMockDelayProvider();
352 EXPECT_CALL(*delay(), GetDelay(_))
353 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(20)));
354 SyncShareTimes times;
355 const ModelTypeSet model_types(THEMES);
356
357 StartSyncConfiguration();
358
359 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
360 .WillOnce(DoAll(Invoke(test_util::SimulateConfigureFailed),
361 RecordSyncShare(&times, false)))
362 .WillOnce(DoAll(Invoke(test_util::SimulateConfigureFailed),
363 RecordSyncShare(&times, false)));
364
365 CallbackCounter ready_counter;
366 CallbackCounter retry_counter;
367 ConfigurationParams params(
368 GetUpdatesCallerInfo::RECONFIGURATION, model_types,
369 TypesToRoutingInfo(model_types),
370 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
371 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
372 scheduler()->ScheduleConfiguration(params);
373 RunLoop();
374 ASSERT_EQ(0, ready_counter.times_called());
375 ASSERT_EQ(1, retry_counter.times_called());
376
377 // RunLoop() will trigger TryCanaryJob which will retry configuration.
378 // Since retry_task was already called it shouldn't be called again.
379 RunLoop();
380 ASSERT_EQ(0, ready_counter.times_called());
381 ASSERT_EQ(1, retry_counter.times_called());
382
383 Mock::VerifyAndClearExpectations(syncer());
384
385 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
386 .WillOnce(DoAll(Invoke(test_util::SimulateConfigureSuccess),
387 RecordSyncShare(&times, true)));
388 RunLoop();
389
390 ASSERT_EQ(1, ready_counter.times_called());
391 }
392
393 // Simuilate SyncSchedulerImpl::Stop being called in the middle of Configure.
394 // This can happen if server returns NOT_MY_BIRTHDAY.
395 TEST_F(SyncSchedulerTest, ConfigWithStop) {
396 UseMockDelayProvider();
397 EXPECT_CALL(*delay(), GetDelay(_))
398 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(20)));
399 SyncShareTimes times;
400 const ModelTypeSet model_types(THEMES);
401
402 StartSyncConfiguration();
403
404 // Make ConfigureSyncShare call scheduler->Stop(). It is not supposed to call
405 // retry_task or dereference configuration params.
406 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
407 .WillOnce(DoAll(Invoke(test_util::SimulateConfigureFailed),
408 StopScheduler(scheduler()),
409 RecordSyncShare(&times, false)));
410
411 CallbackCounter ready_counter;
412 CallbackCounter retry_counter;
413 ConfigurationParams params(
414 GetUpdatesCallerInfo::RECONFIGURATION, model_types,
415 TypesToRoutingInfo(model_types),
416 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
417 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
418 scheduler()->ScheduleConfiguration(params);
419 PumpLoop();
420 ASSERT_EQ(0, ready_counter.times_called());
421 ASSERT_EQ(0, retry_counter.times_called());
422 }
423
424 // Issue a nudge when the config has failed. Make sure both the config and
425 // nudge are executed.
426 TEST_F(SyncSchedulerTest, NudgeWithConfigWithBackingOff) {
427 const ModelTypeSet model_types(THEMES);
428 UseMockDelayProvider();
429 EXPECT_CALL(*delay(), GetDelay(_))
430 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(50)));
431 SyncShareTimes times;
432
433 StartSyncConfiguration();
434
435 // Request a configure and make sure it fails.
436 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
437 .WillOnce(DoAll(Invoke(test_util::SimulateConfigureFailed),
438 RecordSyncShare(&times, false)));
439 CallbackCounter ready_counter;
440 CallbackCounter retry_counter;
441 ConfigurationParams params(
442 GetUpdatesCallerInfo::RECONFIGURATION, model_types,
443 TypesToRoutingInfo(model_types),
444 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
445 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
446 scheduler()->ScheduleConfiguration(params);
447 RunLoop();
448 ASSERT_EQ(0, ready_counter.times_called());
449 ASSERT_EQ(1, retry_counter.times_called());
450 Mock::VerifyAndClearExpectations(syncer());
451
452 // Ask for a nudge while dealing with repeated configure failure.
453 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
454 .WillOnce(DoAll(Invoke(test_util::SimulateConfigureFailed),
455 RecordSyncShare(&times, false)));
456 scheduler()->ScheduleLocalNudge(model_types, FROM_HERE);
457 RunLoop();
458 // Note that we're not RunLoop()ing for the NUDGE we just scheduled, but
459 // for the first retry attempt from the config job (after
460 // waiting ~+/- 50ms).
461 Mock::VerifyAndClearExpectations(syncer());
462 ASSERT_EQ(0, ready_counter.times_called());
463
464 // Let the next configure retry succeed.
465 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
466 .WillOnce(DoAll(Invoke(test_util::SimulateConfigureSuccess),
467 RecordSyncShare(&times, true)));
468 RunLoop();
469
470 // Now change the mode so nudge can execute.
471 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
472 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess),
473 RecordSyncShare(&times, true)));
474 StartSyncScheduler(base::Time());
475 PumpLoop();
476 }
477
478 // Test that nudges are coalesced.
479 TEST_F(SyncSchedulerTest, NudgeCoalescing) {
480 StartSyncScheduler(base::Time());
481
482 SyncShareTimes times;
483 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
484 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess),
485 RecordSyncShare(&times, true)));
486 const ModelTypeSet types1(THEMES), types2(TYPED_URLS), types3(THEMES);
487 TimeTicks optimal_time = TimeTicks::Now() + default_delay();
488 scheduler()->ScheduleLocalNudge(types1, FROM_HERE);
489 scheduler()->ScheduleLocalNudge(types2, FROM_HERE);
490 RunLoop();
491
492 ASSERT_EQ(1U, times.size());
493 EXPECT_GE(times[0], optimal_time);
494
495 Mock::VerifyAndClearExpectations(syncer());
496
497 SyncShareTimes times2;
498 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
499 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess),
500 RecordSyncShare(&times2, true)));
501 scheduler()->ScheduleLocalNudge(types3, FROM_HERE);
502 RunLoop();
503 }
504
505 // Test that nudges are coalesced.
506 TEST_F(SyncSchedulerTest, NudgeCoalescingWithDifferentTimings) {
507 StartSyncScheduler(base::Time());
508
509 SyncShareTimes times;
510 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
511 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess),
512 RecordSyncShare(&times, true)));
513 ModelTypeSet types1(THEMES), types2(TYPED_URLS), types3;
514
515 // Create a huge time delay.
516 TimeDelta delay = TimeDelta::FromDays(1);
517
518 std::map<ModelType, TimeDelta> delay_map;
519 delay_map[types1.First().Get()] = delay;
520 scheduler()->OnReceivedCustomNudgeDelays(delay_map);
521 scheduler()->ScheduleLocalNudge(types1, FROM_HERE);
522 scheduler()->ScheduleLocalNudge(types2, FROM_HERE);
523
524 TimeTicks min_time = TimeTicks::Now();
525 TimeTicks max_time = TimeTicks::Now() + delay;
526
527 RunLoop();
528 Mock::VerifyAndClearExpectations(syncer());
529
530 // Make sure the sync happened at the right time.
531 ASSERT_EQ(1U, times.size());
532 EXPECT_GE(times[0], min_time);
533 EXPECT_LE(times[0], max_time);
534 }
535
536 // Test nudge scheduling.
537 TEST_F(SyncSchedulerTest, NudgeWithStates) {
538 StartSyncScheduler(base::Time());
539
540 SyncShareTimes times1;
541 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
542 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess),
543 RecordSyncShare(&times1, true)))
544 .RetiresOnSaturation();
545 scheduler()->ScheduleInvalidationNudge(THEMES, BuildInvalidation(10, "test"),
546 FROM_HERE);
547 RunLoop();
548
549 Mock::VerifyAndClearExpectations(syncer());
550
551 // Make sure a second, later, nudge is unaffected by first (no coalescing).
552 SyncShareTimes times2;
553 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
554 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess),
555 RecordSyncShare(&times2, true)));
556 scheduler()->ScheduleInvalidationNudge(
557 TYPED_URLS, BuildInvalidation(10, "test2"), FROM_HERE);
558 RunLoop();
559 }
560
561 // Test that polling works as expected.
562 TEST_F(SyncSchedulerTest, Polling) {
563 SyncShareTimes times;
564 TimeDelta poll_interval(TimeDelta::FromMilliseconds(30));
565 EXPECT_CALL(*syncer(), PollSyncShare(_, _))
566 .Times(AtLeast(kMinNumSamples))
567 .WillRepeatedly(
568 DoAll(Invoke(test_util::SimulatePollSuccess),
569 RecordSyncShareMultiple(&times, kMinNumSamples, true)));
570
571 scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval);
572
573 TimeTicks optimal_start = TimeTicks::Now() + poll_interval;
574 StartSyncScheduler(base::Time());
575
576 // Run again to wait for polling.
577 RunLoop();
578
579 StopSyncScheduler();
580 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll_interval);
581 }
582
583 // Test that we reuse the previous poll time on startup, triggering the first
584 // poll based on when the last one happened. Subsequent polls should have the
585 // normal delay.
586 TEST_F(SyncSchedulerTest, PollingPersistence) {
587 SyncShareTimes times;
588 // Use a large poll interval that wouldn't normally get hit on its own for
589 // some time yet.
590 TimeDelta poll_interval(TimeDelta::FromMilliseconds(500));
591 EXPECT_CALL(*syncer(), PollSyncShare(_, _))
592 .Times(AtLeast(kMinNumSamples))
593 .WillRepeatedly(
594 DoAll(Invoke(test_util::SimulatePollSuccess),
595 RecordSyncShareMultiple(&times, kMinNumSamples, true)));
596
597 scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval);
598
599 // Set the start time to now, as the poll was overdue.
600 TimeTicks optimal_start = TimeTicks::Now();
601 StartSyncScheduler(base::Time::Now() - poll_interval);
602
603 // Run again to wait for polling.
604 RunLoop();
605
606 StopSyncScheduler();
607 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll_interval);
608 }
609
610 // Test that if the persisted poll is in the future, it's ignored (the case
611 // where the local time has been modified).
612 TEST_F(SyncSchedulerTest, PollingPersistenceBadClock) {
613 SyncShareTimes times;
614 TimeDelta poll_interval(TimeDelta::FromMilliseconds(30));
615 EXPECT_CALL(*syncer(), PollSyncShare(_, _))
616 .Times(AtLeast(kMinNumSamples))
617 .WillRepeatedly(
618 DoAll(Invoke(test_util::SimulatePollSuccess),
619 RecordSyncShareMultiple(&times, kMinNumSamples, true)));
620
621 scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval);
622
623 // Set the start time to |poll_interval| in the future.
624 TimeTicks optimal_start = TimeTicks::Now() + poll_interval;
625 StartSyncScheduler(base::Time::Now() + base::TimeDelta::FromMinutes(10));
626
627 // Run again to wait for polling.
628 RunLoop();
629
630 StopSyncScheduler();
631 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll_interval);
632 }
633
634 // Test that the short poll interval is used.
635 TEST_F(SyncSchedulerTest, PollNotificationsDisabled) {
636 SyncShareTimes times;
637 TimeDelta poll_interval(TimeDelta::FromMilliseconds(30));
638 EXPECT_CALL(*syncer(), PollSyncShare(_, _))
639 .Times(AtLeast(kMinNumSamples))
640 .WillRepeatedly(
641 DoAll(Invoke(test_util::SimulatePollSuccess),
642 RecordSyncShareMultiple(&times, kMinNumSamples, true)));
643
644 scheduler()->OnReceivedShortPollIntervalUpdate(poll_interval);
645 scheduler()->SetNotificationsEnabled(false);
646
647 TimeTicks optimal_start = TimeTicks::Now() + poll_interval;
648 StartSyncScheduler(base::Time());
649
650 // Run again to wait for polling.
651 RunLoop();
652
653 StopSyncScheduler();
654 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll_interval);
655 }
656
657 // Test that polling intervals are updated when needed.
658 TEST_F(SyncSchedulerTest, PollIntervalUpdate) {
659 SyncShareTimes times;
660 TimeDelta poll1(TimeDelta::FromMilliseconds(120));
661 TimeDelta poll2(TimeDelta::FromMilliseconds(30));
662 scheduler()->OnReceivedLongPollIntervalUpdate(poll1);
663 EXPECT_CALL(*syncer(), PollSyncShare(_, _))
664 .Times(AtLeast(kMinNumSamples))
665 .WillOnce(
666 DoAll(WithArgs<0, 1>(test_util::SimulatePollIntervalUpdate(poll2)),
667 Return(true)))
668 .WillRepeatedly(DoAll(
669 Invoke(test_util::SimulatePollSuccess),
670 WithArg<1>(RecordSyncShareMultiple(&times, kMinNumSamples, true))));
671
672 TimeTicks optimal_start = TimeTicks::Now() + poll1 + poll2;
673 StartSyncScheduler(base::Time());
674
675 // Run again to wait for polling.
676 RunLoop();
677
678 StopSyncScheduler();
679 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll2);
680 }
681
682 // Test that no syncing occurs when throttled.
683 TEST_F(SyncSchedulerTest, ThrottlingDoesThrottle) {
684 const ModelTypeSet types(THEMES);
685 TimeDelta poll(TimeDelta::FromMilliseconds(20));
686 TimeDelta throttle(TimeDelta::FromMinutes(10));
687 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
688
689 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
690 .WillOnce(DoAll(WithArg<2>(test_util::SimulateThrottled(throttle)),
691 Return(false)))
692 .WillRepeatedly(AddFailureAndQuitLoopNow());
693
694 StartSyncScheduler(base::Time());
695
696 scheduler()->ScheduleLocalNudge(types, FROM_HERE);
697 PumpLoop();
698
699 StartSyncConfiguration();
700
701 CallbackCounter ready_counter;
702 CallbackCounter retry_counter;
703 ConfigurationParams params(
704 GetUpdatesCallerInfo::RECONFIGURATION, types, TypesToRoutingInfo(types),
705 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
706 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
707 scheduler()->ScheduleConfiguration(params);
708 PumpLoop();
709 ASSERT_EQ(0, ready_counter.times_called());
710 ASSERT_EQ(1, retry_counter.times_called());
711 }
712
713 TEST_F(SyncSchedulerTest, ThrottlingExpiresFromPoll) {
714 SyncShareTimes times;
715 TimeDelta poll(TimeDelta::FromMilliseconds(15));
716 TimeDelta throttle1(TimeDelta::FromMilliseconds(150));
717 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
718
719 ::testing::InSequence seq;
720 EXPECT_CALL(*syncer(), PollSyncShare(_, _))
721 .WillOnce(DoAll(WithArg<1>(test_util::SimulateThrottled(throttle1)),
722 Return(false)))
723 .RetiresOnSaturation();
724 EXPECT_CALL(*syncer(), PollSyncShare(_, _))
725 .WillRepeatedly(
726 DoAll(Invoke(test_util::SimulatePollSuccess),
727 RecordSyncShareMultiple(&times, kMinNumSamples, true)));
728
729 TimeTicks optimal_start = TimeTicks::Now() + poll + throttle1;
730 StartSyncScheduler(base::Time());
731
732 // Run again to wait for polling.
733 RunLoop();
734
735 StopSyncScheduler();
736 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll);
737 }
738
739 TEST_F(SyncSchedulerTest, ThrottlingExpiresFromNudge) {
740 SyncShareTimes times;
741 TimeDelta poll(TimeDelta::FromDays(1));
742 TimeDelta throttle1(TimeDelta::FromMilliseconds(150));
743 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
744
745 ::testing::InSequence seq;
746 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
747 .WillOnce(DoAll(WithArg<2>(test_util::SimulateThrottled(throttle1)),
748 Return(false)))
749 .RetiresOnSaturation();
750 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
751 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess),
752 QuitLoopNowAction(true)));
753
754 const ModelTypeSet types(THEMES);
755 StartSyncScheduler(base::Time());
756 scheduler()->ScheduleLocalNudge(types, FROM_HERE);
757
758 PumpLoop(); // To get PerformDelayedNudge called.
759 PumpLoop(); // To get TrySyncCycleJob called
760 EXPECT_TRUE(scheduler()->IsCurrentlyThrottled());
761 RunLoop();
762 EXPECT_FALSE(scheduler()->IsCurrentlyThrottled());
763
764 StopSyncScheduler();
765 }
766
767 TEST_F(SyncSchedulerTest, ThrottlingExpiresFromConfigure) {
768 SyncShareTimes times;
769 TimeDelta poll(TimeDelta::FromDays(1));
770 TimeDelta throttle1(TimeDelta::FromMilliseconds(150));
771 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
772
773 ::testing::InSequence seq;
774 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
775 .WillOnce(DoAll(WithArg<2>(test_util::SimulateThrottled(throttle1)),
776 Return(false)))
777 .RetiresOnSaturation();
778 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
779 .WillOnce(DoAll(Invoke(test_util::SimulateConfigureSuccess),
780 QuitLoopNowAction(true)));
781
782 const ModelTypeSet types(THEMES);
783 StartSyncConfiguration();
784
785 CallbackCounter ready_counter;
786 CallbackCounter retry_counter;
787 ConfigurationParams params(
788 GetUpdatesCallerInfo::RECONFIGURATION, types, TypesToRoutingInfo(types),
789 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
790 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
791 scheduler()->ScheduleConfiguration(params);
792 PumpLoop();
793 EXPECT_EQ(0, ready_counter.times_called());
794 EXPECT_EQ(1, retry_counter.times_called());
795 EXPECT_TRUE(scheduler()->IsCurrentlyThrottled());
796
797 RunLoop();
798 EXPECT_FALSE(scheduler()->IsCurrentlyThrottled());
799
800 StopSyncScheduler();
801 }
802
803 TEST_F(SyncSchedulerTest, TypeThrottlingBlocksNudge) {
804 UseMockDelayProvider();
805 EXPECT_CALL(*delay(), GetDelay(_)).WillRepeatedly(Return(default_delay()));
806
807 TimeDelta poll(TimeDelta::FromDays(1));
808 TimeDelta throttle1(TimeDelta::FromSeconds(60));
809 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
810
811 const ModelTypeSet types(THEMES);
812
813 ::testing::InSequence seq;
814 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
815 .WillOnce(
816 DoAll(WithArg<2>(test_util::SimulateTypesThrottled(types, throttle1)),
817 Return(false)))
818 .RetiresOnSaturation();
819
820 StartSyncScheduler(base::Time());
821 scheduler()->ScheduleLocalNudge(types, FROM_HERE);
822 PumpLoop(); // To get PerformDelayedNudge called.
823 PumpLoop(); // To get TrySyncCycleJob called
824 EXPECT_TRUE(GetThrottledTypes().HasAll(types));
825
826 // This won't cause a sync cycle because the types are throttled.
827 scheduler()->ScheduleLocalNudge(types, FROM_HERE);
828 PumpLoop();
829
830 StopSyncScheduler();
831 }
832
833 TEST_F(SyncSchedulerTest, TypeThrottlingDoesBlockOtherSources) {
834 UseMockDelayProvider();
835 EXPECT_CALL(*delay(), GetDelay(_)).WillRepeatedly(Return(default_delay()));
836
837 SyncShareTimes times;
838 TimeDelta poll(TimeDelta::FromDays(1));
839 TimeDelta throttle1(TimeDelta::FromSeconds(60));
840 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
841
842 const ModelTypeSet throttled_types(THEMES);
843 const ModelTypeSet unthrottled_types(PREFERENCES);
844
845 ::testing::InSequence seq;
846 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
847 .WillOnce(DoAll(WithArg<2>(test_util::SimulateTypesThrottled(
848 throttled_types, throttle1)),
849 Return(false)))
850 .RetiresOnSaturation();
851
852 StartSyncScheduler(base::Time());
853 scheduler()->ScheduleLocalNudge(throttled_types, FROM_HERE);
854 PumpLoop(); // To get PerformDelayedNudge called.
855 PumpLoop(); // To get TrySyncCycleJob called
856 EXPECT_TRUE(GetThrottledTypes().HasAll(throttled_types));
857
858 // Ignore invalidations for throttled types.
859 scheduler()->ScheduleInvalidationNudge(THEMES, BuildInvalidation(10, "test"),
860 FROM_HERE);
861 PumpLoop();
862
863 // Ignore refresh requests for throttled types.
864 scheduler()->ScheduleLocalRefreshRequest(throttled_types, FROM_HERE);
865 PumpLoop();
866
867 Mock::VerifyAndClearExpectations(syncer());
868
869 // Local nudges for non-throttled types will trigger a sync.
870 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
871 .WillRepeatedly(DoAll(Invoke(test_util::SimulateNormalSuccess),
872 RecordSyncShare(&times, true)));
873 scheduler()->ScheduleLocalNudge(unthrottled_types, FROM_HERE);
874 RunLoop();
875 Mock::VerifyAndClearExpectations(syncer());
876
877 StopSyncScheduler();
878 }
879
880 // Test nudges / polls don't run in config mode and config tasks do.
881 TEST_F(SyncSchedulerTest, ConfigurationMode) {
882 TimeDelta poll(TimeDelta::FromMilliseconds(15));
883 SyncShareTimes times;
884 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
885
886 StartSyncConfiguration();
887
888 const ModelTypeSet nudge_types(TYPED_URLS);
889 scheduler()->ScheduleLocalNudge(nudge_types, FROM_HERE);
890 scheduler()->ScheduleLocalNudge(nudge_types, FROM_HERE);
891
892 const ModelTypeSet config_types(THEMES);
893
894 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
895 .WillOnce(DoAll(Invoke(test_util::SimulateConfigureSuccess),
896 RecordSyncShare(&times, true)))
897 .RetiresOnSaturation();
898 CallbackCounter ready_counter;
899 CallbackCounter retry_counter;
900 ConfigurationParams params(
901 GetUpdatesCallerInfo::RECONFIGURATION, config_types,
902 TypesToRoutingInfo(config_types),
903 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
904 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
905 scheduler()->ScheduleConfiguration(params);
906 RunLoop();
907 ASSERT_EQ(1, ready_counter.times_called());
908 ASSERT_EQ(0, retry_counter.times_called());
909
910 Mock::VerifyAndClearExpectations(syncer());
911
912 // Switch to NORMAL_MODE to ensure NUDGES were properly saved and run.
913 scheduler()->OnReceivedLongPollIntervalUpdate(TimeDelta::FromDays(1));
914 SyncShareTimes times2;
915 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
916 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess),
917 RecordSyncShare(&times2, true)));
918
919 // TODO(tim): Figure out how to remove this dangerous need to reset
920 // routing info between mode switches.
921 context()->SetRoutingInfo(routing_info());
922 StartSyncScheduler(base::Time());
923
924 RunLoop();
925 Mock::VerifyAndClearExpectations(syncer());
926 }
927
928 class BackoffTriggersSyncSchedulerTest : public SyncSchedulerTest {
929 void SetUp() override {
930 SyncSchedulerTest::SetUp();
931 UseMockDelayProvider();
932 EXPECT_CALL(*delay(), GetDelay(_))
933 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(10)));
934 }
935
936 void TearDown() override {
937 StopSyncScheduler();
938 SyncSchedulerTest::TearDown();
939 }
940 };
941
942 // Have the syncer fail during commit. Expect that the scheduler enters
943 // backoff.
944 TEST_F(BackoffTriggersSyncSchedulerTest, FailCommitOnce) {
945 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
946 .WillOnce(DoAll(Invoke(test_util::SimulateCommitFailed),
947 QuitLoopNowAction(false)));
948 EXPECT_TRUE(RunAndGetBackoff());
949 }
950
951 // Have the syncer fail during download updates and succeed on the first
952 // retry. Expect that this clears the backoff state.
953 TEST_F(BackoffTriggersSyncSchedulerTest, FailDownloadOnceThenSucceed) {
954 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
955 .WillOnce(DoAll(Invoke(test_util::SimulateDownloadUpdatesFailed),
956 Return(false)))
957 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess),
958 QuitLoopNowAction(true)));
959 EXPECT_FALSE(RunAndGetBackoff());
960 }
961
962 // Have the syncer fail during commit and succeed on the first retry. Expect
963 // that this clears the backoff state.
964 TEST_F(BackoffTriggersSyncSchedulerTest, FailCommitOnceThenSucceed) {
965 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
966 .WillOnce(DoAll(Invoke(test_util::SimulateCommitFailed), Return(false)))
967 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess),
968 QuitLoopNowAction(true)));
969 EXPECT_FALSE(RunAndGetBackoff());
970 }
971
972 // Have the syncer fail to download updates and fail again on the retry.
973 // Expect this will leave the scheduler in backoff.
974 TEST_F(BackoffTriggersSyncSchedulerTest, FailDownloadTwice) {
975 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
976 .WillOnce(DoAll(Invoke(test_util::SimulateDownloadUpdatesFailed),
977 Return(false)))
978 .WillRepeatedly(DoAll(Invoke(test_util::SimulateDownloadUpdatesFailed),
979 QuitLoopNowAction(false)));
980 EXPECT_TRUE(RunAndGetBackoff());
981 }
982
983 // Have the syncer fail to get the encryption key yet succeed in downloading
984 // updates. Expect this will leave the scheduler in backoff.
985 TEST_F(BackoffTriggersSyncSchedulerTest, FailGetEncryptionKey) {
986 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
987 .WillOnce(DoAll(Invoke(test_util::SimulateGetEncryptionKeyFailed),
988 Return(false)))
989 .WillRepeatedly(DoAll(Invoke(test_util::SimulateGetEncryptionKeyFailed),
990 QuitLoopNowAction(false)));
991 StartSyncConfiguration();
992
993 ModelTypeSet types(THEMES);
994 CallbackCounter ready_counter;
995 CallbackCounter retry_counter;
996 ConfigurationParams params(
997 GetUpdatesCallerInfo::RECONFIGURATION, types, TypesToRoutingInfo(types),
998 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
999 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
1000 scheduler()->ScheduleConfiguration(params);
1001 RunLoop();
1002
1003 EXPECT_TRUE(scheduler()->IsBackingOff());
1004 }
1005
1006 // Test that no polls or extraneous nudges occur when in backoff.
1007 TEST_F(SyncSchedulerTest, BackoffDropsJobs) {
1008 SyncShareTimes times;
1009 TimeDelta poll(TimeDelta::FromMilliseconds(10));
1010 const ModelTypeSet types(THEMES);
1011 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
1012 UseMockDelayProvider();
1013
1014 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1015 .WillOnce(DoAll(Invoke(test_util::SimulateCommitFailed),
1016 RecordSyncShareMultiple(&times, 1U, false)));
1017 EXPECT_CALL(*delay(), GetDelay(_))
1018 .WillRepeatedly(Return(TimeDelta::FromDays(1)));
1019
1020 StartSyncScheduler(base::Time());
1021
1022 // This nudge should fail and put us into backoff. Thanks to our mock
1023 // GetDelay() setup above, this will be a long backoff.
1024 scheduler()->ScheduleLocalNudge(types, FROM_HERE);
1025 RunLoop();
1026
1027 // From this point forward, no SyncShare functions should be invoked.
1028 Mock::VerifyAndClearExpectations(syncer());
1029
1030 // Wait a while (10x poll interval) so a few poll jobs will be attempted.
1031 PumpLoopFor(poll * 10);
1032
1033 // Try (and fail) to schedule a nudge.
1034 scheduler()->ScheduleLocalNudge(types, FROM_HERE);
1035
1036 Mock::VerifyAndClearExpectations(syncer());
1037 Mock::VerifyAndClearExpectations(delay());
1038
1039 EXPECT_CALL(*delay(), GetDelay(_)).Times(0);
1040
1041 StartSyncConfiguration();
1042
1043 CallbackCounter ready_counter;
1044 CallbackCounter retry_counter;
1045 ConfigurationParams params(
1046 GetUpdatesCallerInfo::RECONFIGURATION, types, TypesToRoutingInfo(types),
1047 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
1048 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
1049 scheduler()->ScheduleConfiguration(params);
1050 PumpLoop();
1051 ASSERT_EQ(0, ready_counter.times_called());
1052 ASSERT_EQ(1, retry_counter.times_called());
1053 }
1054
1055 // Test that backoff is shaping traffic properly with consecutive errors.
1056 TEST_F(SyncSchedulerTest, BackoffElevation) {
1057 SyncShareTimes times;
1058 UseMockDelayProvider();
1059
1060 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1061 .Times(kMinNumSamples)
1062 .WillRepeatedly(
1063 DoAll(Invoke(test_util::SimulateCommitFailed),
1064 RecordSyncShareMultiple(&times, kMinNumSamples, false)));
1065
1066 const TimeDelta first = TimeDelta::FromSeconds(kInitialBackoffRetrySeconds);
1067 const TimeDelta second = TimeDelta::FromMilliseconds(20);
1068 const TimeDelta third = TimeDelta::FromMilliseconds(30);
1069 const TimeDelta fourth = TimeDelta::FromMilliseconds(40);
1070 const TimeDelta fifth = TimeDelta::FromMilliseconds(50);
1071 const TimeDelta sixth = TimeDelta::FromDays(1);
1072
1073 EXPECT_CALL(*delay(), GetDelay(first))
1074 .WillOnce(Return(second))
1075 .RetiresOnSaturation();
1076 EXPECT_CALL(*delay(), GetDelay(second))
1077 .WillOnce(Return(third))
1078 .RetiresOnSaturation();
1079 EXPECT_CALL(*delay(), GetDelay(third))
1080 .WillOnce(Return(fourth))
1081 .RetiresOnSaturation();
1082 EXPECT_CALL(*delay(), GetDelay(fourth))
1083 .WillOnce(Return(fifth))
1084 .RetiresOnSaturation();
1085 EXPECT_CALL(*delay(), GetDelay(fifth)).WillOnce(Return(sixth));
1086
1087 StartSyncScheduler(base::Time());
1088
1089 // Run again with a nudge.
1090 scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE);
1091 RunLoop();
1092
1093 ASSERT_EQ(kMinNumSamples, times.size());
1094 EXPECT_GE(times[1] - times[0], second);
1095 EXPECT_GE(times[2] - times[1], third);
1096 EXPECT_GE(times[3] - times[2], fourth);
1097 EXPECT_GE(times[4] - times[3], fifth);
1098 }
1099
1100 // Test that things go back to normal once a retry makes forward progress.
1101 TEST_F(SyncSchedulerTest, BackoffRelief) {
1102 SyncShareTimes times;
1103 UseMockDelayProvider();
1104
1105 const TimeDelta backoff = TimeDelta::FromMilliseconds(10);
1106 EXPECT_CALL(*delay(), GetDelay(_)).WillOnce(Return(backoff));
1107
1108 // Optimal start for the post-backoff poll party.
1109 TimeTicks optimal_start = TimeTicks::Now();
1110 StartSyncScheduler(base::Time());
1111
1112 // Kick off the test with a failed nudge.
1113 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1114 .WillOnce(DoAll(Invoke(test_util::SimulateCommitFailed),
1115 RecordSyncShare(&times, false)));
1116 scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE);
1117 RunLoop();
1118 Mock::VerifyAndClearExpectations(syncer());
1119 TimeTicks optimal_job_time = optimal_start;
1120 ASSERT_EQ(1U, times.size());
1121 EXPECT_GE(times[0], optimal_job_time);
1122
1123 // The retry succeeds.
1124 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1125 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess),
1126 RecordSyncShare(&times, true)));
1127 RunLoop();
1128 Mock::VerifyAndClearExpectations(syncer());
1129 optimal_job_time = optimal_job_time + backoff;
1130 ASSERT_EQ(2U, times.size());
1131 EXPECT_GE(times[1], optimal_job_time);
1132
1133 // Now let the Poll timer do its thing.
1134 EXPECT_CALL(*syncer(), PollSyncShare(_, _))
1135 .WillRepeatedly(
1136 DoAll(Invoke(test_util::SimulatePollSuccess),
1137 RecordSyncShareMultiple(&times, kMinNumSamples, true)));
1138 const TimeDelta poll(TimeDelta::FromMilliseconds(10));
1139 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
1140
1141 // The new optimal time is now, since the desired poll should have happened
1142 // in the past.
1143 optimal_job_time = base::TimeTicks::Now();
1144 RunLoop();
1145 Mock::VerifyAndClearExpectations(syncer());
1146 ASSERT_EQ(kMinNumSamples, times.size());
1147 for (size_t i = 2; i < times.size(); i++) {
1148 SCOPED_TRACE(testing::Message() << "SyncShare # (" << i << ")");
1149 EXPECT_GE(times[i], optimal_job_time);
1150 optimal_job_time = optimal_job_time + poll;
1151 }
1152
1153 StopSyncScheduler();
1154 }
1155
1156 // Test that poll failures are treated like any other failure. They should
1157 // result in retry with backoff.
1158 TEST_F(SyncSchedulerTest, TransientPollFailure) {
1159 SyncShareTimes times;
1160 const TimeDelta poll_interval(TimeDelta::FromMilliseconds(10));
1161 scheduler()->OnReceivedLongPollIntervalUpdate(poll_interval);
1162 UseMockDelayProvider(); // Will cause test failure if backoff is initiated.
1163 EXPECT_CALL(*delay(), GetDelay(_))
1164 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(0)));
1165
1166 EXPECT_CALL(*syncer(), PollSyncShare(_, _))
1167 .WillOnce(DoAll(Invoke(test_util::SimulatePollFailed),
1168 RecordSyncShare(&times, false)))
1169 .WillOnce(DoAll(Invoke(test_util::SimulatePollSuccess),
1170 RecordSyncShare(&times, true)));
1171
1172 StartSyncScheduler(base::Time());
1173
1174 // Run the unsuccessful poll. The failed poll should not trigger backoff.
1175 RunLoop();
1176 EXPECT_TRUE(scheduler()->IsBackingOff());
1177
1178 // Run the successful poll.
1179 RunLoop();
1180 EXPECT_FALSE(scheduler()->IsBackingOff());
1181 }
1182
1183 // Test that starting the syncer thread without a valid connection doesn't
1184 // break things when a connection is detected.
1185 TEST_F(SyncSchedulerTest, StartWhenNotConnected) {
1186 connection()->SetServerNotReachable();
1187 connection()->UpdateConnectionStatus();
1188 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1189 .WillOnce(
1190 DoAll(Invoke(test_util::SimulateConnectionFailure), Return(false)))
1191 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), Return(true)));
1192 StartSyncScheduler(base::Time());
1193
1194 scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE);
1195 // Should save the nudge for until after the server is reachable.
1196 base::RunLoop().RunUntilIdle();
1197
1198 scheduler()->OnConnectionStatusChange();
1199 connection()->SetServerReachable();
1200 connection()->UpdateConnectionStatus();
1201 base::RunLoop().RunUntilIdle();
1202 }
1203
1204 TEST_F(SyncSchedulerTest, ServerConnectionChangeDuringBackoff) {
1205 UseMockDelayProvider();
1206 EXPECT_CALL(*delay(), GetDelay(_))
1207 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(0)));
1208
1209 StartSyncScheduler(base::Time());
1210 connection()->SetServerNotReachable();
1211 connection()->UpdateConnectionStatus();
1212
1213 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1214 .WillOnce(
1215 DoAll(Invoke(test_util::SimulateConnectionFailure), Return(false)))
1216 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), Return(true)));
1217
1218 scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE);
1219 PumpLoop(); // To get PerformDelayedNudge called.
1220 PumpLoop(); // Run the nudge, that will fail and schedule a quick retry.
1221 ASSERT_TRUE(scheduler()->IsBackingOff());
1222
1223 // Before we run the scheduled canary, trigger a server connection change.
1224 scheduler()->OnConnectionStatusChange();
1225 connection()->SetServerReachable();
1226 connection()->UpdateConnectionStatus();
1227 base::RunLoop().RunUntilIdle();
1228 }
1229
1230 // This was supposed to test the scenario where we receive a nudge while a
1231 // connection change canary is scheduled, but has not run yet. Since we've made
1232 // the connection change canary synchronous, this is no longer possible.
1233 TEST_F(SyncSchedulerTest, ConnectionChangeCanaryPreemptedByNudge) {
1234 UseMockDelayProvider();
1235 EXPECT_CALL(*delay(), GetDelay(_))
1236 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(0)));
1237
1238 StartSyncScheduler(base::Time());
1239 connection()->SetServerNotReachable();
1240 connection()->UpdateConnectionStatus();
1241
1242 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1243 .WillOnce(
1244 DoAll(Invoke(test_util::SimulateConnectionFailure), Return(false)))
1245 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess), Return(true)))
1246 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess),
1247 QuitLoopNowAction(true)));
1248
1249 scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE);
1250
1251 PumpLoop(); // To get PerformDelayedNudge called.
1252 PumpLoop(); // Run the nudge, that will fail and schedule a quick retry.
1253 ASSERT_TRUE(scheduler()->IsBackingOff());
1254
1255 // Before we run the scheduled canary, trigger a server connection change.
1256 scheduler()->OnConnectionStatusChange();
1257 PumpLoop();
1258 connection()->SetServerReachable();
1259 connection()->UpdateConnectionStatus();
1260 scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE);
1261 base::RunLoop().RunUntilIdle();
1262 }
1263
1264 // Tests that we don't crash trying to run two canaries at once if we receive
1265 // extra connection status change notifications. See crbug.com/190085.
1266 TEST_F(SyncSchedulerTest, DoubleCanaryInConfigure) {
1267 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
1268 .WillRepeatedly(DoAll(
1269 Invoke(test_util::SimulateConfigureConnectionFailure), Return(true)));
1270 StartSyncConfiguration();
1271 connection()->SetServerNotReachable();
1272 connection()->UpdateConnectionStatus();
1273
1274 ModelTypeSet model_types(THEMES);
1275 CallbackCounter ready_counter;
1276 CallbackCounter retry_counter;
1277 ConfigurationParams params(
1278 GetUpdatesCallerInfo::RECONFIGURATION, model_types,
1279 TypesToRoutingInfo(model_types),
1280 base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
1281 base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
1282 scheduler()->ScheduleConfiguration(params);
1283
1284 scheduler()->OnConnectionStatusChange();
1285 scheduler()->OnConnectionStatusChange();
1286
1287 PumpLoop(); // Run the nudge, that will fail and schedule a quick retry.
1288 }
1289
1290 TEST_F(SyncSchedulerTest, PollFromCanaryAfterAuthError) {
1291 SyncShareTimes times;
1292 TimeDelta poll(TimeDelta::FromMilliseconds(15));
1293 scheduler()->OnReceivedLongPollIntervalUpdate(poll);
1294
1295 ::testing::InSequence seq;
1296 EXPECT_CALL(*syncer(), PollSyncShare(_, _))
1297 .WillRepeatedly(
1298 DoAll(Invoke(test_util::SimulatePollSuccess),
1299 RecordSyncShareMultiple(&times, kMinNumSamples, true)));
1300
1301 connection()->SetServerStatus(HttpResponse::SYNC_AUTH_ERROR);
1302 StartSyncScheduler(base::Time());
1303
1304 // Run to wait for polling.
1305 RunLoop();
1306
1307 // Normally OnCredentialsUpdated calls TryCanaryJob that doesn't run Poll,
1308 // but after poll finished with auth error from poll timer it should retry
1309 // poll once more
1310 EXPECT_CALL(*syncer(), PollSyncShare(_, _))
1311 .WillOnce(DoAll(Invoke(test_util::SimulatePollSuccess),
1312 RecordSyncShare(&times, true)));
1313 scheduler()->OnCredentialsUpdated();
1314 connection()->SetServerStatus(HttpResponse::SERVER_CONNECTION_OK);
1315 RunLoop();
1316 StopSyncScheduler();
1317 }
1318
1319 TEST_F(SyncSchedulerTest, SuccessfulRetry) {
1320 StartSyncScheduler(base::Time());
1321
1322 SyncShareTimes times;
1323 base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10);
1324 scheduler()->OnReceivedGuRetryDelay(delay);
1325 EXPECT_EQ(delay, GetRetryTimerDelay());
1326
1327 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1328 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess),
1329 RecordSyncShare(&times, true)));
1330
1331 // Run to wait for retrying.
1332 RunLoop();
1333
1334 StopSyncScheduler();
1335 }
1336
1337 TEST_F(SyncSchedulerTest, FailedRetry) {
1338 SyncShareTimes times;
1339
1340 UseMockDelayProvider();
1341 EXPECT_CALL(*delay(), GetDelay(_))
1342 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(10)));
1343
1344 StartSyncScheduler(base::Time());
1345
1346 base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10);
1347 scheduler()->OnReceivedGuRetryDelay(delay);
1348
1349 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1350 .WillOnce(DoAll(Invoke(test_util::SimulateDownloadUpdatesFailed),
1351 RecordSyncShare(&times, false)));
1352
1353 // Run to wait for retrying.
1354 RunLoop();
1355
1356 EXPECT_TRUE(scheduler()->IsBackingOff());
1357 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1358 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess),
1359 RecordSyncShare(&times, true)));
1360
1361 // Run to wait for second retrying.
1362 RunLoop();
1363
1364 StopSyncScheduler();
1365 }
1366
1367 ACTION_P2(VerifyRetryTimerDelay, scheduler_test, expected_delay) {
1368 EXPECT_EQ(expected_delay, scheduler_test->GetRetryTimerDelay());
1369 }
1370
1371 TEST_F(SyncSchedulerTest, ReceiveNewRetryDelay) {
1372 StartSyncScheduler(base::Time());
1373
1374 SyncShareTimes times;
1375 base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(100);
1376 base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(200);
1377
1378 scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE);
1379 scheduler()->OnReceivedGuRetryDelay(delay1);
1380 EXPECT_EQ(delay1, GetRetryTimerDelay());
1381
1382 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1383 .WillOnce(
1384 DoAll(WithoutArgs(VerifyRetryTimerDelay(this, delay1)),
1385 WithArg<2>(test_util::SimulateGuRetryDelayCommand(delay2)),
1386 RecordSyncShare(&times, true)));
1387
1388 // Run nudge GU.
1389 RunLoop();
1390 EXPECT_EQ(delay2, GetRetryTimerDelay());
1391
1392 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1393 .WillOnce(DoAll(Invoke(test_util::SimulateNormalSuccess),
1394 RecordSyncShare(&times, true)));
1395
1396 // Run to wait for retrying.
1397 RunLoop();
1398
1399 StopSyncScheduler();
1400 }
1401
1402 TEST_F(SyncSchedulerTest, ScheduleClearServerData_Succeeds) {
1403 StartSyncConfiguration();
1404 scheduler()->Start(SyncScheduler::CLEAR_SERVER_DATA_MODE, base::Time());
1405 CallbackCounter success_counter;
1406 ClearParams params(base::Bind(&CallbackCounter::Callback,
1407 base::Unretained(&success_counter)));
1408 scheduler()->ScheduleClearServerData(params);
1409 PumpLoop();
1410 ASSERT_EQ(1, success_counter.times_called());
1411 }
1412
1413 TEST_F(SyncSchedulerTest, ScheduleClearServerData_FailsRetriesSucceeds) {
1414 UseMockDelayProvider();
1415 TimeDelta delta(TimeDelta::FromMilliseconds(20));
1416 EXPECT_CALL(*delay(), GetDelay(_)).WillRepeatedly(Return(delta));
1417
1418 StartSyncConfiguration();
1419 scheduler()->Start(SyncScheduler::CLEAR_SERVER_DATA_MODE, base::Time());
1420 CallbackCounter success_counter;
1421 ClearParams params(base::Bind(&CallbackCounter::Callback,
1422 base::Unretained(&success_counter)));
1423
1424 // Next request will fail.
1425 connection()->SetServerNotReachable();
1426 scheduler()->ScheduleClearServerData(params);
1427 PumpLoop();
1428 ASSERT_EQ(0, success_counter.times_called());
1429 ASSERT_TRUE(scheduler()->IsBackingOff());
1430
1431 // Now succeed.
1432 connection()->SetServerReachable();
1433 PumpLoopFor(2 * delta);
1434 ASSERT_EQ(1, success_counter.times_called());
1435 ASSERT_FALSE(scheduler()->IsBackingOff());
1436 }
1437
1438 } // namespace syncer
OLDNEW
« no previous file with comments | « components/sync/engine_impl/sync_scheduler_impl_unittest.cc ('k') | components/sync/engine_impl/syncer_proto_util_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698