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 "components/sync/engine_impl/sync_scheduler_impl.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <utility>
11 #include <vector>
12
13 #include "base/bind.h"
14 #include "base/location.h"
15 #include "base/run_loop.h"
16 #include "base/sequenced_task_runner.h"
17 #include "base/test/scoped_feature_list.h"
18 #include "base/test/task_environment.h"
19 #include "base/test/test_timeouts.h"
20 #include "base/threading/sequenced_task_runner_handle.h"
21 #include "components/sync/base/extensions_activity.h"
22 #include "components/sync/base/model_type_test_util.h"
23 #include "components/sync/engine/data_type_activation_response.h"
24 #include "components/sync/engine/fake_model_type_processor.h"
25 #include "components/sync/engine/sync_engine_switches.h"
26 #include "components/sync/engine_impl/backoff_delay_provider.h"
27 #include "components/sync/engine_impl/cancelation_signal.h"
28 #include "components/sync/test/callback_counter.h"
29 #include "components/sync/test/engine/mock_connection_manager.h"
30 #include "components/sync/test/engine/mock_nudge_handler.h"
31 #include "components/sync/test/fake_sync_encryption_handler.h"
32 #include "components/sync/test/mock_invalidation.h"
33 #include "net/base/net_errors.h"
34 #include "net/http/http_status_code.h"
35 #include "testing/gmock/include/gmock/gmock.h"
36 #include "testing/gtest/include/gtest/gtest.h"
37
38 using base::TimeDelta;
39 using base::TimeTicks;
40 using testing::_;
41 using testing::AtLeast;
42 using testing::DoAll;
43 using testing::Eq;
44 using testing::Ge;
45 using testing::Gt;
46 using testing::Invoke;
47 using testing::Lt;
48 using testing::Mock;
49 using testing::Return;
50 using testing::SaveArg;
51 using testing::WithArg;
52 using testing::WithArgs;
53 using testing::WithoutArgs;
54
55 namespace syncer {
56
57 namespace {
58
SimulatePollSuccess(ModelTypeSet requested_types,SyncCycle * cycle)59 void SimulatePollSuccess(ModelTypeSet requested_types, SyncCycle* cycle) {
60 cycle->mutable_status_controller()->set_last_download_updates_result(
61 SyncerError(SyncerError::SYNCER_OK));
62 }
63
SimulatePollFailed(ModelTypeSet requested_types,SyncCycle * cycle)64 void SimulatePollFailed(ModelTypeSet requested_types, SyncCycle* cycle) {
65 cycle->mutable_status_controller()->set_last_download_updates_result(
66 SyncerError(SyncerError::SERVER_RETURN_TRANSIENT_ERROR));
67 }
68
ACTION_P(SimulateThrottled,throttle)69 ACTION_P(SimulateThrottled, throttle) {
70 SyncCycle* cycle = arg0;
71 cycle->mutable_status_controller()->set_last_download_updates_result(
72 SyncerError(SyncerError::SERVER_RETURN_THROTTLED));
73 cycle->delegate()->OnThrottled(throttle);
74 }
75
ACTION_P2(SimulateTypesThrottled,types,throttle)76 ACTION_P2(SimulateTypesThrottled, types, throttle) {
77 SyncCycle* cycle = arg0;
78 cycle->mutable_status_controller()->set_commit_result(
79 SyncerError(SyncerError::SYNCER_OK));
80 cycle->delegate()->OnTypesThrottled(types, throttle);
81 }
82
ACTION_P(SimulatePartialFailure,types)83 ACTION_P(SimulatePartialFailure, types) {
84 SyncCycle* cycle = arg0;
85 cycle->mutable_status_controller()->set_commit_result(
86 SyncerError(SyncerError::SYNCER_OK));
87 cycle->delegate()->OnTypesBackedOff(types);
88 }
89
ACTION_P(SimulatePollIntervalUpdate,new_poll)90 ACTION_P(SimulatePollIntervalUpdate, new_poll) {
91 const ModelTypeSet requested_types = arg0;
92 SyncCycle* cycle = arg1;
93 SimulatePollSuccess(requested_types, cycle);
94 cycle->delegate()->OnReceivedPollIntervalUpdate(new_poll);
95 }
96
ACTION_P(SimulateGuRetryDelayCommand,delay)97 ACTION_P(SimulateGuRetryDelayCommand, delay) {
98 SyncCycle* cycle = arg0;
99 cycle->mutable_status_controller()->set_last_download_updates_result(
100 SyncerError(SyncerError::SYNCER_OK));
101 cycle->delegate()->OnReceivedGuRetryDelay(delay);
102 }
103
SimulateGetEncryptionKeyFailed(ModelTypeSet requsted_types,sync_pb::SyncEnums::GetUpdatesOrigin origin,SyncCycle * cycle)104 void SimulateGetEncryptionKeyFailed(ModelTypeSet requsted_types,
105 sync_pb::SyncEnums::GetUpdatesOrigin origin,
106 SyncCycle* cycle) {
107 cycle->mutable_status_controller()->set_last_get_key_result(
108 SyncerError(SyncerError::SERVER_RESPONSE_VALIDATION_FAILED));
109 cycle->mutable_status_controller()->set_last_download_updates_result(
110 SyncerError(SyncerError::SYNCER_OK));
111 }
112
SimulateConfigureSuccess(ModelTypeSet requsted_types,sync_pb::SyncEnums::GetUpdatesOrigin origin,SyncCycle * cycle)113 void SimulateConfigureSuccess(ModelTypeSet requsted_types,
114 sync_pb::SyncEnums::GetUpdatesOrigin origin,
115 SyncCycle* cycle) {
116 cycle->mutable_status_controller()->set_last_get_key_result(
117 SyncerError(SyncerError::SYNCER_OK));
118 cycle->mutable_status_controller()->set_last_download_updates_result(
119 SyncerError(SyncerError::SYNCER_OK));
120 }
121
SimulateConfigureFailed(ModelTypeSet requsted_types,sync_pb::SyncEnums::GetUpdatesOrigin origin,SyncCycle * cycle)122 void SimulateConfigureFailed(ModelTypeSet requsted_types,
123 sync_pb::SyncEnums::GetUpdatesOrigin origin,
124 SyncCycle* cycle) {
125 cycle->mutable_status_controller()->set_last_get_key_result(
126 SyncerError(SyncerError::SYNCER_OK));
127 cycle->mutable_status_controller()->set_last_download_updates_result(
128 SyncerError(SyncerError::SERVER_RETURN_TRANSIENT_ERROR));
129 }
130
SimulateConfigureConnectionFailure(ModelTypeSet requsted_types,sync_pb::SyncEnums::GetUpdatesOrigin origin,SyncCycle * cycle)131 void SimulateConfigureConnectionFailure(
132 ModelTypeSet requsted_types,
133 sync_pb::SyncEnums::GetUpdatesOrigin origin,
134 SyncCycle* cycle) {
135 cycle->mutable_status_controller()->set_last_get_key_result(
136 SyncerError(SyncerError::SYNCER_OK));
137 cycle->mutable_status_controller()->set_last_download_updates_result(
138 SyncerError::NetworkConnectionUnavailable(net::ERR_FAILED));
139 }
140
SimulateNormalSuccess(ModelTypeSet requested_types,NudgeTracker * nudge_tracker,SyncCycle * cycle)141 void SimulateNormalSuccess(ModelTypeSet requested_types,
142 NudgeTracker* nudge_tracker,
143 SyncCycle* cycle) {
144 cycle->mutable_status_controller()->set_commit_result(
145 SyncerError(SyncerError::SYNCER_OK));
146 cycle->mutable_status_controller()->set_last_download_updates_result(
147 SyncerError(SyncerError::SYNCER_OK));
148 }
149
SimulateDownloadUpdatesFailed(ModelTypeSet requested_types,NudgeTracker * nudge_tracker,SyncCycle * cycle)150 void SimulateDownloadUpdatesFailed(ModelTypeSet requested_types,
151 NudgeTracker* nudge_tracker,
152 SyncCycle* cycle) {
153 cycle->mutable_status_controller()->set_last_download_updates_result(
154 SyncerError(SyncerError::SERVER_RETURN_TRANSIENT_ERROR));
155 }
156
SimulateCommitFailed(ModelTypeSet requested_types,NudgeTracker * nudge_tracker,SyncCycle * cycle)157 void SimulateCommitFailed(ModelTypeSet requested_types,
158 NudgeTracker* nudge_tracker,
159 SyncCycle* cycle) {
160 cycle->mutable_status_controller()->set_last_get_key_result(
161 SyncerError(SyncerError::SYNCER_OK));
162 cycle->mutable_status_controller()->set_last_download_updates_result(
163 SyncerError(SyncerError::SYNCER_OK));
164 cycle->mutable_status_controller()->set_commit_result(
165 SyncerError(SyncerError::SERVER_RETURN_TRANSIENT_ERROR));
166 }
167
SimulateConnectionFailure(ModelTypeSet requested_types,NudgeTracker * nudge_tracker,SyncCycle * cycle)168 void SimulateConnectionFailure(ModelTypeSet requested_types,
169 NudgeTracker* nudge_tracker,
170 SyncCycle* cycle) {
171 cycle->mutable_status_controller()->set_last_download_updates_result(
172 SyncerError::NetworkConnectionUnavailable(net::ERR_FAILED));
173 }
174
175 class MockSyncer : public Syncer {
176 public:
177 MockSyncer();
178 MOCK_METHOD(bool,
179 NormalSyncShare,
180 (ModelTypeSet, NudgeTracker*, SyncCycle*),
181 (override));
182 MOCK_METHOD(bool,
183 ConfigureSyncShare,
184 (const ModelTypeSet&,
185 sync_pb::SyncEnums::GetUpdatesOrigin,
186 SyncCycle*),
187 (override));
188 MOCK_METHOD(bool, PollSyncShare, (ModelTypeSet, SyncCycle*), (override));
189 };
190
MakeFakeActivationResponse(ModelType model_type)191 std::unique_ptr<DataTypeActivationResponse> MakeFakeActivationResponse(
192 ModelType model_type) {
193 auto response = std::make_unique<DataTypeActivationResponse>();
194 response->type_processor = std::make_unique<FakeModelTypeProcessor>();
195 response->model_type_state.mutable_progress_marker()->set_data_type_id(
196 GetSpecificsFieldNumberFromModelType(model_type));
197 return response;
198 }
199
MockSyncer()200 MockSyncer::MockSyncer() : Syncer(nullptr) {}
201
202 using SyncShareTimes = std::vector<TimeTicks>;
203
QuitLoopNow()204 void QuitLoopNow() {
205 // We use QuitNow() instead of Quit() as the latter may get stalled
206 // indefinitely in the presence of repeated timers with low delays
207 // and a slow test (e.g., ThrottlingDoesThrottle [which has a poll
208 // delay of 5ms] run under TSAN on the trybots).
209 base::RunLoop::QuitCurrentDeprecated();
210 }
211
RunLoop()212 void RunLoop() {
213 base::RunLoop().Run();
214 }
215
PumpLoop()216 void PumpLoop() {
217 // Do it this way instead of RunAllPending to pump loop exactly once
218 // (necessary in the presence of timers; see comment in
219 // QuitLoopNow).
220 base::SequencedTaskRunnerHandle::Get()->PostTask(
221 FROM_HERE, base::BindOnce(&QuitLoopNow));
222 RunLoop();
223 }
224
225 static const size_t kMinNumSamples = 5;
226
227 } // namespace
228
229 // Test harness for the SyncScheduler. Test the delays and backoff timers used
230 // in response to various events. Mock time is used to avoid flakes.
231 class SyncSchedulerImplTest : public testing::Test {
232 public:
SyncSchedulerImplTest()233 SyncSchedulerImplTest()
234 : task_environment_(
235 base::test::SingleThreadTaskEnvironment::ThreadPoolExecutionMode::
236 ASYNC,
237 base::test::SingleThreadTaskEnvironment::TimeSource::MOCK_TIME),
238 syncer_(nullptr),
239 delay_(nullptr) {}
240
241 class MockDelayProvider : public BackoffDelayProvider {
242 public:
MockDelayProvider()243 MockDelayProvider()
244 : BackoffDelayProvider(
245 TimeDelta::FromSeconds(kInitialBackoffRetrySeconds),
246 TimeDelta::FromSeconds(kInitialBackoffImmediateRetrySeconds)) {}
247 MOCK_METHOD(TimeDelta, GetDelay, (const TimeDelta&), (override));
248 };
249
SetUp()250 void SetUp() override {
251 delay_ = nullptr;
252 extensions_activity_ = new ExtensionsActivity();
253
254 connection_ = std::make_unique<MockConnectionManager>();
255 connection_->SetServerReachable();
256
257 model_type_registry_ = std::make_unique<ModelTypeRegistry>(
258 &mock_nudge_handler_, &cancelation_signal_, &encryption_handler_);
259 model_type_registry_->ConnectDataType(
260 HISTORY_DELETE_DIRECTIVES,
261 MakeFakeActivationResponse(HISTORY_DELETE_DIRECTIVES));
262 model_type_registry_->ConnectDataType(NIGORI,
263 MakeFakeActivationResponse(NIGORI));
264 model_type_registry_->ConnectDataType(THEMES,
265 MakeFakeActivationResponse(THEMES));
266 model_type_registry_->ConnectDataType(
267 TYPED_URLS, MakeFakeActivationResponse(TYPED_URLS));
268
269 context_ = std::make_unique<SyncCycleContext>(
270 connection_.get(), extensions_activity_.get(),
271 std::vector<SyncEngineEventListener*>(), nullptr,
272 model_type_registry_.get(), "fake_invalidator_client_id",
273 "fake_cache_guid", "fake_birthday", "fake_bag_of_chips",
274 /*poll_interval=*/base::TimeDelta::FromMinutes(30));
275 context_->set_notifications_enabled(true);
276 context_->set_account_name("Test");
277 RebuildScheduler();
278 }
279
DisconnectDataType(ModelType type)280 void DisconnectDataType(ModelType type) {
281 model_type_registry_->DisconnectDataType(type);
282 }
283
RebuildScheduler()284 void RebuildScheduler() {
285 // The old syncer is destroyed with the scheduler that owns it.
286 syncer_ = new testing::StrictMock<MockSyncer>();
287 scheduler_ = std::make_unique<SyncSchedulerImpl>(
288 "TestSyncScheduler", BackoffDelayProvider::FromDefaults(), context(),
289 syncer_, false);
290 scheduler_->nudge_tracker_.SetDefaultNudgeDelay(default_delay());
291 }
292
scheduler()293 SyncSchedulerImpl* scheduler() { return scheduler_.get(); }
syncer()294 MockSyncer* syncer() { return syncer_; }
delay()295 MockDelayProvider* delay() { return delay_; }
connection()296 MockConnectionManager* connection() { return connection_.get(); }
default_delay()297 TimeDelta default_delay() { return TimeDelta::FromSeconds(0); }
long_delay()298 TimeDelta long_delay() { return TimeDelta::FromSeconds(60); }
timeout()299 TimeDelta timeout() { return TestTimeouts::action_timeout(); }
300
TearDown()301 void TearDown() override {
302 PumpLoop();
303 scheduler_.reset();
304 PumpLoop();
305 }
306
AnalyzePollRun(const SyncShareTimes & times,size_t min_num_samples,const TimeTicks & optimal_start,const TimeDelta & poll_interval)307 void AnalyzePollRun(const SyncShareTimes& times,
308 size_t min_num_samples,
309 const TimeTicks& optimal_start,
310 const TimeDelta& poll_interval) {
311 EXPECT_GE(times.size(), min_num_samples);
312 for (size_t i = 0; i < times.size(); i++) {
313 SCOPED_TRACE(testing::Message() << "SyncShare # (" << i << ")");
314 TimeTicks optimal_next_sync = optimal_start + poll_interval * i;
315 EXPECT_GE(times[i], optimal_next_sync);
316 }
317 }
318
DoQuitLoopNow()319 void DoQuitLoopNow() { QuitLoopNow(); }
320
StartSyncConfiguration()321 void StartSyncConfiguration() {
322 scheduler()->Start(SyncScheduler::CONFIGURATION_MODE, base::Time());
323 }
324
StartSyncScheduler(base::Time last_poll_time)325 void StartSyncScheduler(base::Time last_poll_time) {
326 scheduler()->Start(SyncScheduler::NORMAL_MODE, last_poll_time);
327 }
328
329 // This stops the scheduler synchronously.
StopSyncScheduler()330 void StopSyncScheduler() {
331 base::SequencedTaskRunnerHandle::Get()->PostTask(
332 FROM_HERE, base::BindOnce(&SyncSchedulerImplTest::DoQuitLoopNow,
333 weak_ptr_factory_.GetWeakPtr()));
334 RunLoop();
335 }
336
RunAndGetBackoff()337 bool RunAndGetBackoff() {
338 ModelTypeSet nudge_types(THEMES);
339 StartSyncScheduler(base::Time());
340
341 scheduler()->ScheduleLocalNudge(nudge_types, FROM_HERE);
342 RunLoop();
343
344 return scheduler()->IsGlobalBackoff();
345 }
346
UseMockDelayProvider()347 void UseMockDelayProvider() {
348 delay_ = new MockDelayProvider();
349 scheduler_->delay_provider_.reset(delay_);
350 }
351
context()352 SyncCycleContext* context() { return context_.get(); }
353
GetThrottledTypes()354 ModelTypeSet GetThrottledTypes() {
355 ModelTypeSet throttled_types;
356 ModelTypeSet blocked_types = scheduler_->nudge_tracker_.GetBlockedTypes();
357 for (ModelType type : blocked_types) {
358 if (scheduler_->nudge_tracker_.GetTypeBlockingMode(type) ==
359 WaitInterval::THROTTLED) {
360 throttled_types.Put(type);
361 }
362 }
363 return throttled_types;
364 }
365
GetBackedOffTypes()366 ModelTypeSet GetBackedOffTypes() {
367 ModelTypeSet backed_off_types;
368 ModelTypeSet blocked_types = scheduler_->nudge_tracker_.GetBlockedTypes();
369 for (ModelType type : blocked_types) {
370 if (scheduler_->nudge_tracker_.GetTypeBlockingMode(type) ==
371 WaitInterval::EXPONENTIAL_BACKOFF) {
372 backed_off_types.Put(type);
373 }
374 }
375 return backed_off_types;
376 }
377
IsAnyTypeBlocked()378 bool IsAnyTypeBlocked() {
379 return scheduler_->nudge_tracker_.IsAnyTypeBlocked();
380 }
381
GetRetryTimerDelay()382 TimeDelta GetRetryTimerDelay() {
383 EXPECT_TRUE(scheduler_->retry_timer_.IsRunning());
384 return scheduler_->retry_timer_.GetCurrentDelay();
385 }
386
BuildInvalidation(int64_t version,const std::string & payload)387 static std::unique_ptr<InvalidationInterface> BuildInvalidation(
388 int64_t version,
389 const std::string& payload) {
390 return MockInvalidation::Build(version, payload);
391 }
392
GetTypeBlockingTime(ModelType type)393 TimeDelta GetTypeBlockingTime(ModelType type) {
394 NudgeTracker::TypeTrackerMap::const_iterator tracker_it =
395 scheduler_->nudge_tracker_.type_trackers_.find(type);
396 DCHECK(tracker_it != scheduler_->nudge_tracker_.type_trackers_.end());
397 DCHECK(tracker_it->second->wait_interval_);
398 return tracker_it->second->wait_interval_->length;
399 }
400
SetTypeBlockingMode(ModelType type,WaitInterval::BlockingMode mode)401 void SetTypeBlockingMode(ModelType type, WaitInterval::BlockingMode mode) {
402 NudgeTracker::TypeTrackerMap::const_iterator tracker_it =
403 scheduler_->nudge_tracker_.type_trackers_.find(type);
404 DCHECK(tracker_it != scheduler_->nudge_tracker_.type_trackers_.end());
405 DCHECK(tracker_it->second->wait_interval_);
406 tracker_it->second->wait_interval_->mode = mode;
407 }
408
NewSchedulerForLocalBackend()409 void NewSchedulerForLocalBackend() {
410 // The old syncer is destroyed with the scheduler that owns it.
411 syncer_ = new testing::StrictMock<MockSyncer>();
412 scheduler_ = std::make_unique<SyncSchedulerImpl>(
413 "TestSyncScheduler", BackoffDelayProvider::FromDefaults(), context(),
414 syncer_, true);
415 scheduler_->nudge_tracker_.SetDefaultNudgeDelay(default_delay());
416 }
417
BlockTimerIsRunning() const418 bool BlockTimerIsRunning() const {
419 return scheduler_->pending_wakeup_timer_.IsRunning();
420 }
421
GetPendingWakeupTimerDelay()422 TimeDelta GetPendingWakeupTimerDelay() {
423 EXPECT_TRUE(scheduler_->pending_wakeup_timer_.IsRunning());
424 return scheduler_->pending_wakeup_timer_.GetCurrentDelay();
425 }
426
427 // Provide access for tests to private method.
ComputeLastPollOnStart(base::Time last_poll,base::TimeDelta poll_interval,base::Time now)428 base::Time ComputeLastPollOnStart(base::Time last_poll,
429 base::TimeDelta poll_interval,
430 base::Time now) {
431 return SyncSchedulerImpl::ComputeLastPollOnStart(last_poll, poll_interval,
432 now);
433 }
434
435 protected:
436 base::test::SingleThreadTaskEnvironment task_environment_;
437
438 private:
439 static const base::TickClock* tick_clock_;
GetMockTimeTicks()440 static base::TimeTicks GetMockTimeTicks() {
441 if (!tick_clock_)
442 return base::TimeTicks();
443 return tick_clock_->NowTicks();
444 }
445
446 FakeSyncEncryptionHandler encryption_handler_;
447 CancelationSignal cancelation_signal_;
448 std::unique_ptr<MockConnectionManager> connection_;
449 std::unique_ptr<ModelTypeRegistry> model_type_registry_;
450 std::unique_ptr<SyncCycleContext> context_;
451 std::unique_ptr<SyncSchedulerImpl> scheduler_;
452 MockNudgeHandler mock_nudge_handler_;
453 MockSyncer* syncer_;
454 MockDelayProvider* delay_;
455 scoped_refptr<ExtensionsActivity> extensions_activity_;
456 base::WeakPtrFactory<SyncSchedulerImplTest> weak_ptr_factory_{this};
457 };
458
459 const base::TickClock* SyncSchedulerImplTest::tick_clock_ = nullptr;
460
RecordSyncShareImpl(SyncShareTimes * times)461 void RecordSyncShareImpl(SyncShareTimes* times) {
462 times->push_back(TimeTicks::Now());
463 }
464
ACTION_P2(RecordSyncShare,times,success)465 ACTION_P2(RecordSyncShare, times, success) {
466 RecordSyncShareImpl(times);
467 if (base::RunLoop::IsRunningOnCurrentThread())
468 QuitLoopNow();
469 return success;
470 }
471
ACTION_P3(RecordSyncShareMultiple,times,quit_after,success)472 ACTION_P3(RecordSyncShareMultiple, times, quit_after, success) {
473 RecordSyncShareImpl(times);
474 EXPECT_LE(times->size(), quit_after);
475 if (times->size() >= quit_after &&
476 base::RunLoop::IsRunningOnCurrentThread()) {
477 QuitLoopNow();
478 }
479 return success;
480 }
481
ACTION_P(StopScheduler,scheduler)482 ACTION_P(StopScheduler, scheduler) {
483 scheduler->Stop();
484 }
485
ACTION(AddFailureAndQuitLoopNow)486 ACTION(AddFailureAndQuitLoopNow) {
487 ADD_FAILURE();
488 QuitLoopNow();
489 return true;
490 }
491
ACTION_P(QuitLoopNowAction,success)492 ACTION_P(QuitLoopNowAction, success) {
493 QuitLoopNow();
494 return success;
495 }
496
497 // Test nudge scheduling.
TEST_F(SyncSchedulerImplTest,Nudge)498 TEST_F(SyncSchedulerImplTest, Nudge) {
499 SyncShareTimes times;
500 ModelTypeSet model_types(THEMES);
501
502 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
503 .WillOnce(
504 DoAll(Invoke(SimulateNormalSuccess), RecordSyncShare(×, true)))
505 .RetiresOnSaturation();
506
507 StartSyncScheduler(base::Time());
508
509 scheduler()->ScheduleLocalNudge(model_types, FROM_HERE);
510 RunLoop();
511
512 Mock::VerifyAndClearExpectations(syncer());
513
514 // Make sure a second, later, nudge is unaffected by first (no coalescing).
515 SyncShareTimes times2;
516 model_types.Remove(THEMES);
517 model_types.Put(TYPED_URLS);
518 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
519 .WillOnce(
520 DoAll(Invoke(SimulateNormalSuccess), RecordSyncShare(×2, true)));
521 scheduler()->ScheduleLocalNudge(model_types, FROM_HERE);
522 RunLoop();
523 }
524
TEST_F(SyncSchedulerImplTest,NudgeForDisabledType)525 TEST_F(SyncSchedulerImplTest, NudgeForDisabledType) {
526 ModelTypeSet model_types{THEMES, HISTORY_DELETE_DIRECTIVES};
527
528 StartSyncScheduler(base::Time());
529 scheduler()->ScheduleLocalNudge(model_types, FROM_HERE);
530
531 // The user enables a custom passphrase at this point, so
532 // HISTORY_DELETE_DIRECTIVES gets disabled.
533 DisconnectDataType(HISTORY_DELETE_DIRECTIVES);
534 ASSERT_FALSE(context()->GetEnabledTypes().Has(HISTORY_DELETE_DIRECTIVES));
535
536 // The resulting sync cycle should ask only for the remaining types.
537 SyncShareTimes times;
538 NudgeTracker* nudge_tracker = nullptr;
539 EXPECT_CALL(*syncer(), NormalSyncShare(context()->GetEnabledTypes(), _, _))
540 .WillOnce(DoAll(SaveArg<1>(&nudge_tracker), Invoke(SimulateNormalSuccess),
541 RecordSyncShare(×, true)));
542 RunLoop();
543
544 // Now no sync is required for the enabled types.
545 ASSERT_FALSE(nudge_tracker->IsSyncRequired(context()->GetEnabledTypes()));
546 // ...but HISTORY_DELETE_DIRECTIVES is not enabled, so its earlier nudge is
547 // still there.
548 EXPECT_TRUE(nudge_tracker->IsSyncRequired({HISTORY_DELETE_DIRECTIVES}));
549 }
550
551 // Make sure a regular config command is scheduled fine in the absence of any
552 // errors.
TEST_F(SyncSchedulerImplTest,Config)553 TEST_F(SyncSchedulerImplTest, Config) {
554 SyncShareTimes times;
555 const ModelTypeSet model_types(THEMES);
556
557 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
558 .WillOnce(DoAll(Invoke(SimulateConfigureSuccess),
559 RecordSyncShare(×, true)));
560
561 StartSyncConfiguration();
562
563 CallbackCounter ready_counter;
564 ConfigurationParams params(sync_pb::SyncEnums::RECONFIGURATION, model_types,
565 base::BindOnce(&CallbackCounter::Callback,
566 base::Unretained(&ready_counter)));
567 scheduler()->ScheduleConfiguration(std::move(params));
568 PumpLoop();
569 ASSERT_EQ(1, ready_counter.times_called());
570 }
571
572 // Simulate a failure and make sure the config request is retried.
TEST_F(SyncSchedulerImplTest,ConfigWithBackingOff)573 TEST_F(SyncSchedulerImplTest, ConfigWithBackingOff) {
574 UseMockDelayProvider();
575 EXPECT_CALL(*delay(), GetDelay(_))
576 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(20)));
577 SyncShareTimes times;
578 const ModelTypeSet model_types(THEMES);
579
580 StartSyncConfiguration();
581
582 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
583 .WillOnce(DoAll(Invoke(SimulateConfigureFailed),
584 RecordSyncShare(×, false)))
585 .WillOnce(DoAll(Invoke(SimulateConfigureFailed),
586 RecordSyncShare(×, false)));
587
588 CallbackCounter ready_counter;
589 ConfigurationParams params(sync_pb::SyncEnums::RECONFIGURATION, model_types,
590 base::BindOnce(&CallbackCounter::Callback,
591 base::Unretained(&ready_counter)));
592 scheduler()->ScheduleConfiguration(std::move(params));
593 RunLoop();
594 ASSERT_EQ(0, ready_counter.times_called());
595
596 // RunLoop() will trigger TryCanaryJob which will retry configuration.
597 // Since retry_task was already called it shouldn't be called again.
598 RunLoop();
599 ASSERT_EQ(0, ready_counter.times_called());
600
601 Mock::VerifyAndClearExpectations(syncer());
602
603 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
604 .WillOnce(DoAll(Invoke(SimulateConfigureSuccess),
605 RecordSyncShare(×, true)));
606 RunLoop();
607
608 ASSERT_EQ(1, ready_counter.times_called());
609 }
610
611 // Simuilate SyncSchedulerImpl::Stop being called in the middle of Configure.
612 // This can happen if server returns NOT_MY_BIRTHDAY.
TEST_F(SyncSchedulerImplTest,ConfigWithStop)613 TEST_F(SyncSchedulerImplTest, ConfigWithStop) {
614 UseMockDelayProvider();
615 EXPECT_CALL(*delay(), GetDelay(_))
616 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(20)));
617 SyncShareTimes times;
618 const ModelTypeSet model_types(THEMES);
619
620 StartSyncConfiguration();
621
622 // Make ConfigureSyncShare call scheduler->Stop(). It is not supposed to call
623 // retry_task or dereference configuration params.
624 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
625 .WillOnce(DoAll(Invoke(SimulateConfigureFailed),
626 StopScheduler(scheduler()),
627 RecordSyncShare(×, false)));
628
629 CallbackCounter ready_counter;
630 ConfigurationParams params(sync_pb::SyncEnums::RECONFIGURATION, model_types,
631 base::BindOnce(&CallbackCounter::Callback,
632 base::Unretained(&ready_counter)));
633 scheduler()->ScheduleConfiguration(std::move(params));
634 PumpLoop();
635 ASSERT_EQ(0, ready_counter.times_called());
636 }
637
638 // Verify that in the absence of valid access token the command will fail.
TEST_F(SyncSchedulerImplTest,ConfigNoAccessToken)639 TEST_F(SyncSchedulerImplTest, ConfigNoAccessToken) {
640 SyncShareTimes times;
641 const ModelTypeSet model_types(THEMES);
642
643 connection()->ResetAccessToken();
644
645 StartSyncConfiguration();
646
647 CallbackCounter ready_counter;
648 ConfigurationParams params(sync_pb::SyncEnums::RECONFIGURATION, model_types,
649 base::BindOnce(&CallbackCounter::Callback,
650 base::Unretained(&ready_counter)));
651 scheduler()->ScheduleConfiguration(std::move(params));
652 PumpLoop();
653 ASSERT_EQ(0, ready_counter.times_called());
654 }
655
656 // Verify that in the absence of valid access token the command will pass if
657 // local sync backend is used.
TEST_F(SyncSchedulerImplTest,ConfigNoAccessTokenLocalSync)658 TEST_F(SyncSchedulerImplTest, ConfigNoAccessTokenLocalSync) {
659 SyncShareTimes times;
660 const ModelTypeSet model_types(THEMES);
661
662 NewSchedulerForLocalBackend();
663 connection()->ResetAccessToken();
664
665 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
666 .WillOnce(DoAll(Invoke(SimulateConfigureSuccess),
667 RecordSyncShare(×, true)));
668
669 StartSyncConfiguration();
670
671 CallbackCounter ready_counter;
672 ConfigurationParams params(sync_pb::SyncEnums::RECONFIGURATION, model_types,
673 base::BindOnce(&CallbackCounter::Callback,
674 base::Unretained(&ready_counter)));
675 scheduler()->ScheduleConfiguration(std::move(params));
676 PumpLoop();
677 ASSERT_EQ(1, ready_counter.times_called());
678 }
679
680 // Issue a nudge when the config has failed. Make sure both the config and
681 // nudge are executed.
TEST_F(SyncSchedulerImplTest,NudgeWithConfigWithBackingOff)682 TEST_F(SyncSchedulerImplTest, NudgeWithConfigWithBackingOff) {
683 const ModelTypeSet model_types(THEMES);
684 UseMockDelayProvider();
685 EXPECT_CALL(*delay(), GetDelay(_))
686 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(50)));
687 SyncShareTimes times;
688
689 StartSyncConfiguration();
690
691 // Request a configure and make sure it fails.
692 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
693 .WillOnce(DoAll(Invoke(SimulateConfigureFailed),
694 RecordSyncShare(×, false)));
695 CallbackCounter ready_counter;
696 ConfigurationParams params(sync_pb::SyncEnums::RECONFIGURATION, model_types,
697 base::BindOnce(&CallbackCounter::Callback,
698 base::Unretained(&ready_counter)));
699 scheduler()->ScheduleConfiguration(std::move(params));
700 RunLoop();
701 ASSERT_EQ(0, ready_counter.times_called());
702 Mock::VerifyAndClearExpectations(syncer());
703
704 // Ask for a nudge while dealing with repeated configure failure.
705 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
706 .WillOnce(DoAll(Invoke(SimulateConfigureFailed),
707 RecordSyncShare(×, false)));
708 scheduler()->ScheduleLocalNudge(model_types, FROM_HERE);
709 RunLoop();
710 // Note that we're not RunLoop()ing for the NUDGE we just scheduled, but
711 // for the first retry attempt from the config job (after
712 // waiting ~+/- 50ms).
713 Mock::VerifyAndClearExpectations(syncer());
714 ASSERT_EQ(0, ready_counter.times_called());
715
716 // Let the next configure retry succeed.
717 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
718 .WillOnce(DoAll(Invoke(SimulateConfigureSuccess),
719 RecordSyncShare(×, true)));
720 RunLoop();
721
722 // Now change the mode so nudge can execute.
723 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
724 .WillOnce(
725 DoAll(Invoke(SimulateNormalSuccess), RecordSyncShare(×, true)));
726 StartSyncScheduler(base::Time());
727 PumpLoop();
728 }
729
730 // Test that nudges are coalesced.
TEST_F(SyncSchedulerImplTest,NudgeCoalescing)731 TEST_F(SyncSchedulerImplTest, NudgeCoalescing) {
732 StartSyncScheduler(base::Time());
733
734 SyncShareTimes times;
735 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
736 .WillOnce(
737 DoAll(Invoke(SimulateNormalSuccess), RecordSyncShare(×, true)));
738 const ModelTypeSet types1(THEMES), types2(TYPED_URLS), types3(THEMES);
739 TimeTicks optimal_time = TimeTicks::Now() + default_delay();
740 scheduler()->ScheduleLocalNudge(types1, FROM_HERE);
741 scheduler()->ScheduleLocalNudge(types2, FROM_HERE);
742 RunLoop();
743
744 ASSERT_EQ(1U, times.size());
745 EXPECT_GE(times[0], optimal_time);
746
747 Mock::VerifyAndClearExpectations(syncer());
748
749 SyncShareTimes times2;
750 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
751 .WillOnce(
752 DoAll(Invoke(SimulateNormalSuccess), RecordSyncShare(×2, true)));
753 scheduler()->ScheduleLocalNudge(types3, FROM_HERE);
754 RunLoop();
755 }
756
757 // Test that nudges are coalesced.
TEST_F(SyncSchedulerImplTest,NudgeCoalescingWithDifferentTimings)758 TEST_F(SyncSchedulerImplTest, NudgeCoalescingWithDifferentTimings) {
759 StartSyncScheduler(base::Time());
760
761 SyncShareTimes times;
762 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
763 .WillOnce(
764 DoAll(Invoke(SimulateNormalSuccess), RecordSyncShare(×, true)));
765 ModelTypeSet types1(THEMES), types2(TYPED_URLS), types3;
766
767 // Create a huge time delay.
768 TimeDelta delay = TimeDelta::FromDays(1);
769
770 std::map<ModelType, TimeDelta> delay_map;
771 delay_map[*(types1.begin())] = delay;
772 scheduler()->OnReceivedCustomNudgeDelays(delay_map);
773 scheduler()->ScheduleLocalNudge(types1, FROM_HERE);
774 scheduler()->ScheduleLocalNudge(types2, FROM_HERE);
775
776 TimeTicks min_time = TimeTicks::Now();
777 TimeTicks max_time = TimeTicks::Now() + delay;
778
779 RunLoop();
780 Mock::VerifyAndClearExpectations(syncer());
781
782 // Make sure the sync happened at the right time.
783 ASSERT_EQ(1U, times.size());
784 EXPECT_GE(times[0], min_time);
785 EXPECT_LE(times[0], max_time);
786 }
787
788 // Test nudge scheduling.
TEST_F(SyncSchedulerImplTest,NudgeWithStates)789 TEST_F(SyncSchedulerImplTest, NudgeWithStates) {
790 StartSyncScheduler(base::Time());
791
792 SyncShareTimes times1;
793 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
794 .WillOnce(
795 DoAll(Invoke(SimulateNormalSuccess), RecordSyncShare(×1, true)))
796 .RetiresOnSaturation();
797 scheduler()->ScheduleInvalidationNudge(THEMES, BuildInvalidation(10, "test"),
798 FROM_HERE);
799 RunLoop();
800
801 Mock::VerifyAndClearExpectations(syncer());
802
803 // Make sure a second, later, nudge is unaffected by first (no coalescing).
804 SyncShareTimes times2;
805 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
806 .WillOnce(
807 DoAll(Invoke(SimulateNormalSuccess), RecordSyncShare(×2, true)));
808 scheduler()->ScheduleInvalidationNudge(
809 TYPED_URLS, BuildInvalidation(10, "test2"), FROM_HERE);
810 RunLoop();
811 }
812
813 // Test that polling works as expected.
TEST_F(SyncSchedulerImplTest,Polling)814 TEST_F(SyncSchedulerImplTest, Polling) {
815 SyncShareTimes times;
816 TimeDelta poll_interval(TimeDelta::FromMilliseconds(30));
817 EXPECT_CALL(*syncer(), PollSyncShare(_, _))
818 .Times(AtLeast(kMinNumSamples))
819 .WillRepeatedly(
820 DoAll(Invoke(SimulatePollSuccess),
821 RecordSyncShareMultiple(×, kMinNumSamples, true)));
822
823 scheduler()->OnReceivedPollIntervalUpdate(poll_interval);
824
825 TimeTicks optimal_start = TimeTicks::Now() + poll_interval;
826 StartSyncScheduler(base::Time());
827
828 // Run again to wait for polling.
829 RunLoop();
830
831 StopSyncScheduler();
832 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll_interval);
833 }
834
835 // Test that polling gets the intervals from the provided context.
TEST_F(SyncSchedulerImplTest,ShouldUseInitialPollIntervalFromContext)836 TEST_F(SyncSchedulerImplTest, ShouldUseInitialPollIntervalFromContext) {
837 SyncShareTimes times;
838 TimeDelta poll_interval(TimeDelta::FromMilliseconds(30));
839 context()->set_poll_interval(poll_interval);
840 RebuildScheduler();
841
842 EXPECT_CALL(*syncer(), PollSyncShare(_, _))
843 .Times(AtLeast(kMinNumSamples))
844 .WillRepeatedly(
845 DoAll(Invoke(SimulatePollSuccess),
846 RecordSyncShareMultiple(×, kMinNumSamples, true)));
847
848 TimeTicks optimal_start = TimeTicks::Now() + poll_interval;
849 StartSyncScheduler(base::Time());
850
851 // Run again to wait for polling.
852 RunLoop();
853
854 StopSyncScheduler();
855 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll_interval);
856 }
857
858 // Test that we reuse the previous poll time on startup, triggering the first
859 // poll based on when the last one happened. Subsequent polls should have the
860 // normal delay.
TEST_F(SyncSchedulerImplTest,PollingPersistence)861 TEST_F(SyncSchedulerImplTest, PollingPersistence) {
862 SyncShareTimes times;
863 // Use a large poll interval that wouldn't normally get hit on its own for
864 // some time yet.
865 TimeDelta poll_interval(TimeDelta::FromMilliseconds(500));
866 EXPECT_CALL(*syncer(), PollSyncShare(_, _))
867 .Times(AtLeast(kMinNumSamples))
868 .WillRepeatedly(
869 DoAll(Invoke(SimulatePollSuccess),
870 RecordSyncShareMultiple(×, kMinNumSamples, true)));
871
872 scheduler()->OnReceivedPollIntervalUpdate(poll_interval);
873
874 // Set the start time to now, as the poll was overdue.
875 TimeTicks optimal_start = TimeTicks::Now();
876 StartSyncScheduler(base::Time::Now() - poll_interval);
877
878 // Run again to wait for polling.
879 RunLoop();
880
881 StopSyncScheduler();
882 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll_interval);
883 }
884
885 // Test that if the persisted poll is in the future, it's ignored (the case
886 // where the local time has been modified).
TEST_F(SyncSchedulerImplTest,PollingPersistenceBadClock)887 TEST_F(SyncSchedulerImplTest, PollingPersistenceBadClock) {
888 SyncShareTimes times;
889 TimeDelta poll_interval(TimeDelta::FromMilliseconds(30));
890 EXPECT_CALL(*syncer(), PollSyncShare(_, _))
891 .Times(AtLeast(kMinNumSamples))
892 .WillRepeatedly(
893 DoAll(Invoke(SimulatePollSuccess),
894 RecordSyncShareMultiple(×, kMinNumSamples, true)));
895
896 scheduler()->OnReceivedPollIntervalUpdate(poll_interval);
897
898 // Set the start time to |poll_interval| in the future.
899 TimeTicks optimal_start = TimeTicks::Now() + poll_interval;
900 StartSyncScheduler(base::Time::Now() + TimeDelta::FromMinutes(10));
901
902 // Run again to wait for polling.
903 RunLoop();
904
905 StopSyncScheduler();
906 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll_interval);
907 }
908
909 // Test that polling intervals are updated when needed.
TEST_F(SyncSchedulerImplTest,PollIntervalUpdate)910 TEST_F(SyncSchedulerImplTest, PollIntervalUpdate) {
911 SyncShareTimes times;
912 TimeDelta poll1(TimeDelta::FromMilliseconds(120));
913 TimeDelta poll2(TimeDelta::FromMilliseconds(30));
914 scheduler()->OnReceivedPollIntervalUpdate(poll1);
915 EXPECT_CALL(*syncer(), PollSyncShare(_, _))
916 .Times(AtLeast(kMinNumSamples))
917 .WillOnce(DoAll(WithArgs<0, 1>(SimulatePollIntervalUpdate(poll2)),
918 Return(true)))
919 .WillRepeatedly(DoAll(
920 Invoke(SimulatePollSuccess),
921 WithArg<1>(RecordSyncShareMultiple(×, kMinNumSamples, true))));
922
923 TimeTicks optimal_start = TimeTicks::Now() + poll1 + poll2;
924 StartSyncScheduler(base::Time());
925
926 // Run again to wait for polling.
927 RunLoop();
928
929 StopSyncScheduler();
930 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll2);
931 }
932
933 // Test that no syncing occurs when throttled.
TEST_F(SyncSchedulerImplTest,ThrottlingDoesThrottle)934 TEST_F(SyncSchedulerImplTest, ThrottlingDoesThrottle) {
935 const ModelTypeSet types(THEMES);
936 TimeDelta poll(TimeDelta::FromMilliseconds(20));
937 TimeDelta throttle(TimeDelta::FromMinutes(10));
938 scheduler()->OnReceivedPollIntervalUpdate(poll);
939
940 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
941 .WillOnce(DoAll(WithArg<2>(SimulateThrottled(throttle)), Return(false)))
942 .WillRepeatedly(AddFailureAndQuitLoopNow());
943
944 StartSyncScheduler(base::Time());
945
946 scheduler()->ScheduleLocalNudge(types, FROM_HERE);
947 PumpLoop();
948
949 StartSyncConfiguration();
950
951 CallbackCounter ready_counter;
952 ConfigurationParams params(sync_pb::SyncEnums::RECONFIGURATION, types,
953 base::BindOnce(&CallbackCounter::Callback,
954 base::Unretained(&ready_counter)));
955 scheduler()->ScheduleConfiguration(std::move(params));
956 PumpLoop();
957 ASSERT_EQ(0, ready_counter.times_called());
958 }
959
TEST_F(SyncSchedulerImplTest,ThrottlingExpiresFromPoll)960 TEST_F(SyncSchedulerImplTest, ThrottlingExpiresFromPoll) {
961 SyncShareTimes times;
962 TimeDelta poll(TimeDelta::FromMilliseconds(15));
963 TimeDelta throttle1(TimeDelta::FromMilliseconds(150));
964 scheduler()->OnReceivedPollIntervalUpdate(poll);
965
966 ::testing::InSequence seq;
967 EXPECT_CALL(*syncer(), PollSyncShare(_, _))
968 .WillOnce(DoAll(WithArg<1>(SimulateThrottled(throttle1)), Return(false)))
969 .RetiresOnSaturation();
970 EXPECT_CALL(*syncer(), PollSyncShare(_, _))
971 .WillRepeatedly(
972 DoAll(Invoke(SimulatePollSuccess),
973 RecordSyncShareMultiple(×, kMinNumSamples, true)));
974
975 TimeTicks optimal_start = TimeTicks::Now() + poll + throttle1;
976 StartSyncScheduler(base::Time());
977
978 // Run again to wait for polling.
979 RunLoop();
980
981 StopSyncScheduler();
982 AnalyzePollRun(times, kMinNumSamples, optimal_start, poll);
983 }
984
TEST_F(SyncSchedulerImplTest,ThrottlingExpiresFromNudge)985 TEST_F(SyncSchedulerImplTest, ThrottlingExpiresFromNudge) {
986 SyncShareTimes times;
987 TimeDelta poll(TimeDelta::FromDays(1));
988 TimeDelta throttle1(TimeDelta::FromMilliseconds(150));
989 scheduler()->OnReceivedPollIntervalUpdate(poll);
990
991 ::testing::InSequence seq;
992 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
993 .WillOnce(DoAll(WithArg<2>(SimulateThrottled(throttle1)), Return(false)))
994 .RetiresOnSaturation();
995 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
996 .WillOnce(DoAll(Invoke(SimulateNormalSuccess), QuitLoopNowAction(true)));
997
998 const ModelTypeSet types(THEMES);
999 StartSyncScheduler(base::Time());
1000 scheduler()->ScheduleLocalNudge(types, FROM_HERE);
1001
1002 PumpLoop(); // To get PerformDelayedNudge called.
1003 PumpLoop(); // To get TrySyncCycleJob called
1004 EXPECT_TRUE(scheduler()->IsGlobalThrottle());
1005 RunLoop();
1006 EXPECT_FALSE(scheduler()->IsGlobalThrottle());
1007
1008 StopSyncScheduler();
1009 }
1010
TEST_F(SyncSchedulerImplTest,ThrottlingExpiresFromConfigure)1011 TEST_F(SyncSchedulerImplTest, ThrottlingExpiresFromConfigure) {
1012 SyncShareTimes times;
1013 TimeDelta poll(TimeDelta::FromDays(1));
1014 TimeDelta throttle1(TimeDelta::FromMilliseconds(150));
1015 scheduler()->OnReceivedPollIntervalUpdate(poll);
1016
1017 ::testing::InSequence seq;
1018 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
1019 .WillOnce(DoAll(WithArg<2>(SimulateThrottled(throttle1)), Return(false)))
1020 .RetiresOnSaturation();
1021 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
1022 .WillOnce(
1023 DoAll(Invoke(SimulateConfigureSuccess), QuitLoopNowAction(true)));
1024
1025 const ModelTypeSet types(THEMES);
1026 StartSyncConfiguration();
1027
1028 CallbackCounter ready_counter;
1029 ConfigurationParams params(sync_pb::SyncEnums::RECONFIGURATION, types,
1030 base::BindOnce(&CallbackCounter::Callback,
1031 base::Unretained(&ready_counter)));
1032 scheduler()->ScheduleConfiguration(std::move(params));
1033 PumpLoop();
1034 EXPECT_EQ(0, ready_counter.times_called());
1035 EXPECT_TRUE(scheduler()->IsGlobalThrottle());
1036
1037 RunLoop();
1038 EXPECT_FALSE(scheduler()->IsGlobalThrottle());
1039
1040 StopSyncScheduler();
1041 }
1042
TEST_F(SyncSchedulerImplTest,TypeThrottlingBlocksNudge)1043 TEST_F(SyncSchedulerImplTest, TypeThrottlingBlocksNudge) {
1044 TimeDelta poll(TimeDelta::FromDays(1));
1045 TimeDelta throttle1(TimeDelta::FromSeconds(60));
1046 scheduler()->OnReceivedPollIntervalUpdate(poll);
1047
1048 const ModelTypeSet types(THEMES);
1049
1050 ::testing::InSequence seq;
1051 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1052 .WillOnce(DoAll(WithArg<2>(SimulateTypesThrottled(types, throttle1)),
1053 Return(true)))
1054 .RetiresOnSaturation();
1055
1056 StartSyncScheduler(base::Time());
1057 scheduler()->ScheduleLocalNudge(types, FROM_HERE);
1058 PumpLoop(); // To get PerformDelayedNudge called.
1059 PumpLoop(); // To get TrySyncCycleJob called
1060 EXPECT_TRUE(GetThrottledTypes().HasAll(types));
1061 EXPECT_FALSE(scheduler()->IsGlobalBackoff());
1062 EXPECT_FALSE(scheduler()->IsGlobalThrottle());
1063
1064 // This won't cause a sync cycle because the types are throttled.
1065 scheduler()->ScheduleLocalNudge(types, FROM_HERE);
1066 PumpLoop();
1067
1068 StopSyncScheduler();
1069 }
1070
TEST_F(SyncSchedulerImplTest,TypeBackingOffBlocksNudge)1071 TEST_F(SyncSchedulerImplTest, TypeBackingOffBlocksNudge) {
1072 UseMockDelayProvider();
1073 EXPECT_CALL(*delay(), GetDelay(_)).WillRepeatedly(Return(long_delay()));
1074
1075 TimeDelta poll(TimeDelta::FromDays(1));
1076 scheduler()->OnReceivedPollIntervalUpdate(poll);
1077
1078 const ModelTypeSet types(THEMES);
1079
1080 ::testing::InSequence seq;
1081 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1082 .WillOnce(DoAll(WithArg<2>(SimulatePartialFailure(types)), Return(true)))
1083 .RetiresOnSaturation();
1084
1085 StartSyncScheduler(base::Time());
1086 scheduler()->ScheduleLocalNudge(types, FROM_HERE);
1087 PumpLoop(); // To get PerformDelayedNudge called.
1088 PumpLoop(); // To get TrySyncCycleJob called
1089 EXPECT_TRUE(GetBackedOffTypes().HasAll(types));
1090 EXPECT_FALSE(scheduler()->IsGlobalBackoff());
1091 EXPECT_FALSE(scheduler()->IsGlobalThrottle());
1092
1093 // This won't cause a sync cycle because the types are backed off.
1094 scheduler()->ScheduleLocalNudge(types, FROM_HERE);
1095 PumpLoop();
1096
1097 StopSyncScheduler();
1098 }
1099
TEST_F(SyncSchedulerImplTest,TypeBackingOffWillExpire)1100 TEST_F(SyncSchedulerImplTest, TypeBackingOffWillExpire) {
1101 UseMockDelayProvider();
1102 EXPECT_CALL(*delay(), GetDelay(_)).WillRepeatedly(Return(default_delay()));
1103
1104 TimeDelta poll(TimeDelta::FromDays(1));
1105 scheduler()->OnReceivedPollIntervalUpdate(poll);
1106
1107 const ModelTypeSet types(THEMES);
1108
1109 ::testing::InSequence seq;
1110 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1111 .WillOnce(DoAll(WithArg<2>(SimulatePartialFailure(types)), Return(true)))
1112 .RetiresOnSaturation();
1113
1114 StartSyncScheduler(base::Time());
1115 scheduler()->ScheduleLocalNudge(types, FROM_HERE);
1116 PumpLoop(); // To get PerformDelayedNudge called.
1117 PumpLoop(); // To get TrySyncCycleJob called
1118 EXPECT_TRUE(GetBackedOffTypes().HasAll(types));
1119 EXPECT_FALSE(scheduler()->IsGlobalBackoff());
1120 EXPECT_FALSE(scheduler()->IsGlobalThrottle());
1121
1122 SyncShareTimes times;
1123 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1124 .WillRepeatedly(
1125 DoAll(Invoke(SimulateNormalSuccess), RecordSyncShare(×, true)));
1126 PumpLoop(); // To get PerformDelayedNudge called.
1127 PumpLoop(); // To get TrySyncCycleJob called
1128 EXPECT_FALSE(IsAnyTypeBlocked());
1129 EXPECT_FALSE(scheduler()->IsGlobalBackoff());
1130 EXPECT_FALSE(scheduler()->IsGlobalThrottle());
1131
1132 StopSyncScheduler();
1133 }
1134
TEST_F(SyncSchedulerImplTest,TypeBackingOffAndThrottling)1135 TEST_F(SyncSchedulerImplTest, TypeBackingOffAndThrottling) {
1136 UseMockDelayProvider();
1137 EXPECT_CALL(*delay(), GetDelay(_)).WillRepeatedly(Return(long_delay()));
1138
1139 TimeDelta poll(TimeDelta::FromDays(1));
1140 scheduler()->OnReceivedPollIntervalUpdate(poll);
1141
1142 const ModelTypeSet types(THEMES);
1143
1144 ::testing::InSequence seq;
1145 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1146 .WillOnce(DoAll(WithArg<2>(SimulatePartialFailure(types)), Return(true)))
1147 .RetiresOnSaturation();
1148
1149 StartSyncScheduler(base::Time());
1150 scheduler()->ScheduleLocalNudge(types, FROM_HERE);
1151 PumpLoop(); // To get PerformDelayedNudge called.
1152 PumpLoop(); // To get TrySyncCycleJob called
1153 EXPECT_TRUE(GetBackedOffTypes().HasAll(types));
1154 EXPECT_TRUE(BlockTimerIsRunning());
1155 EXPECT_FALSE(scheduler()->IsGlobalBackoff());
1156 EXPECT_FALSE(scheduler()->IsGlobalThrottle());
1157
1158 TimeDelta throttle1(TimeDelta::FromMilliseconds(150));
1159
1160 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1161 .WillOnce(DoAll(WithArg<2>(SimulateThrottled(throttle1)), Return(false)))
1162 .RetiresOnSaturation();
1163
1164 // Sync still can throttle.
1165 const ModelTypeSet unbacked_off_types(TYPED_URLS);
1166 scheduler()->ScheduleLocalNudge(unbacked_off_types, FROM_HERE);
1167 PumpLoop(); // TO get TypesUnblock called.
1168 PumpLoop(); // To get TrySyncCycleJob called.
1169
1170 EXPECT_TRUE(GetBackedOffTypes().HasAll(types));
1171 EXPECT_TRUE(BlockTimerIsRunning());
1172 EXPECT_FALSE(scheduler()->IsGlobalBackoff());
1173 EXPECT_TRUE(scheduler()->IsGlobalThrottle());
1174
1175 // Unthrottled client, but the backingoff datatype is still in backoff and
1176 // scheduled.
1177 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1178 .WillOnce(DoAll(Invoke(SimulateNormalSuccess), QuitLoopNowAction(true)));
1179 RunLoop();
1180 EXPECT_FALSE(scheduler()->IsGlobalThrottle());
1181 EXPECT_TRUE(GetBackedOffTypes().HasAll(types));
1182 EXPECT_TRUE(BlockTimerIsRunning());
1183
1184 StopSyncScheduler();
1185 }
1186
TEST_F(SyncSchedulerImplTest,TypeThrottlingBackingOffBlocksNudge)1187 TEST_F(SyncSchedulerImplTest, TypeThrottlingBackingOffBlocksNudge) {
1188 UseMockDelayProvider();
1189 EXPECT_CALL(*delay(), GetDelay(_)).WillRepeatedly(Return(long_delay()));
1190
1191 TimeDelta poll(TimeDelta::FromDays(1));
1192 TimeDelta throttle(TimeDelta::FromSeconds(60));
1193 scheduler()->OnReceivedPollIntervalUpdate(poll);
1194
1195 const ModelTypeSet throttled_types(THEMES);
1196
1197 ::testing::InSequence seq;
1198 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1199 .WillOnce(
1200 DoAll(WithArg<2>(SimulateTypesThrottled(throttled_types, throttle)),
1201 Return(true)))
1202 .RetiresOnSaturation();
1203
1204 StartSyncScheduler(base::Time());
1205 scheduler()->ScheduleLocalNudge(throttled_types, FROM_HERE);
1206 PumpLoop(); // To get PerformDelayedNudge called.
1207 PumpLoop(); // To get TrySyncCycleJob called
1208
1209 const ModelTypeSet backed_off_types(TYPED_URLS);
1210
1211 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1212 .WillOnce(DoAll(WithArg<2>(SimulatePartialFailure(backed_off_types)),
1213 Return(true)))
1214 .RetiresOnSaturation();
1215
1216 scheduler()->ScheduleLocalNudge(backed_off_types, FROM_HERE);
1217
1218 PumpLoop(); // To get PerformDelayedNudge called.
1219 PumpLoop(); // To get TrySyncCycleJob called
1220
1221 EXPECT_TRUE(GetThrottledTypes().HasAll(throttled_types));
1222 EXPECT_TRUE(GetBackedOffTypes().HasAll(backed_off_types));
1223 EXPECT_TRUE(BlockTimerIsRunning());
1224 EXPECT_FALSE(scheduler()->IsGlobalBackoff());
1225 EXPECT_FALSE(scheduler()->IsGlobalThrottle());
1226
1227 // This won't cause a sync cycle because the types are throttled or backed
1228 // off.
1229 scheduler()->ScheduleLocalNudge(Union(throttled_types, backed_off_types),
1230 FROM_HERE);
1231 PumpLoop();
1232
1233 StopSyncScheduler();
1234 }
1235
TEST_F(SyncSchedulerImplTest,TypeThrottlingDoesBlockOtherSources)1236 TEST_F(SyncSchedulerImplTest, TypeThrottlingDoesBlockOtherSources) {
1237 UseMockDelayProvider();
1238 EXPECT_CALL(*delay(), GetDelay(_)).WillRepeatedly(Return(default_delay()));
1239
1240 SyncShareTimes times;
1241 TimeDelta poll(TimeDelta::FromDays(1));
1242 TimeDelta throttle1(TimeDelta::FromSeconds(60));
1243 scheduler()->OnReceivedPollIntervalUpdate(poll);
1244
1245 const ModelTypeSet throttled_types(THEMES);
1246 const ModelTypeSet unthrottled_types(PREFERENCES);
1247
1248 ::testing::InSequence seq;
1249 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1250 .WillOnce(
1251 DoAll(WithArg<2>(SimulateTypesThrottled(throttled_types, throttle1)),
1252 Return(true)))
1253 .RetiresOnSaturation();
1254
1255 StartSyncScheduler(base::Time());
1256 scheduler()->ScheduleLocalNudge(throttled_types, FROM_HERE);
1257 PumpLoop(); // To get PerformDelayedNudge called.
1258 PumpLoop(); // To get TrySyncCycleJob called
1259 EXPECT_TRUE(GetThrottledTypes().HasAll(throttled_types));
1260 EXPECT_FALSE(scheduler()->IsGlobalBackoff());
1261 EXPECT_FALSE(scheduler()->IsGlobalThrottle());
1262
1263 // Ignore invalidations for throttled types.
1264 scheduler()->ScheduleInvalidationNudge(THEMES, BuildInvalidation(10, "test"),
1265 FROM_HERE);
1266 PumpLoop();
1267
1268 // Ignore refresh requests for throttled types.
1269 scheduler()->ScheduleLocalRefreshRequest(throttled_types, FROM_HERE);
1270 PumpLoop();
1271
1272 Mock::VerifyAndClearExpectations(syncer());
1273
1274 // Local nudges for non-throttled types will trigger a sync.
1275 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1276 .WillRepeatedly(
1277 DoAll(Invoke(SimulateNormalSuccess), RecordSyncShare(×, true)));
1278 scheduler()->ScheduleLocalNudge(unthrottled_types, FROM_HERE);
1279 RunLoop();
1280 Mock::VerifyAndClearExpectations(syncer());
1281
1282 StopSyncScheduler();
1283 }
1284
TEST_F(SyncSchedulerImplTest,TypeBackingOffDoesBlockOtherSources)1285 TEST_F(SyncSchedulerImplTest, TypeBackingOffDoesBlockOtherSources) {
1286 UseMockDelayProvider();
1287 EXPECT_CALL(*delay(), GetDelay(_)).WillRepeatedly(Return(long_delay()));
1288
1289 SyncShareTimes times;
1290 TimeDelta poll(TimeDelta::FromDays(1));
1291 scheduler()->OnReceivedPollIntervalUpdate(poll);
1292
1293 const ModelTypeSet backed_off_types(THEMES);
1294 const ModelTypeSet unbacked_off_types(PREFERENCES);
1295
1296 ::testing::InSequence seq;
1297 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1298 .WillOnce(DoAll(WithArg<2>(SimulatePartialFailure(backed_off_types)),
1299 Return(true)))
1300 .RetiresOnSaturation();
1301
1302 StartSyncScheduler(base::Time());
1303 scheduler()->ScheduleLocalNudge(backed_off_types, FROM_HERE);
1304 PumpLoop(); // To get PerformDelayedNudge called.
1305 PumpLoop(); // To get TrySyncCycleJob called
1306 EXPECT_TRUE(GetBackedOffTypes().HasAll(backed_off_types));
1307 EXPECT_FALSE(scheduler()->IsGlobalBackoff());
1308 EXPECT_FALSE(scheduler()->IsGlobalThrottle());
1309
1310 // Ignore invalidations for backed off types.
1311 scheduler()->ScheduleInvalidationNudge(THEMES, BuildInvalidation(10, "test"),
1312 FROM_HERE);
1313 PumpLoop();
1314
1315 // Ignore refresh requests for backed off types.
1316 scheduler()->ScheduleLocalRefreshRequest(backed_off_types, FROM_HERE);
1317 PumpLoop();
1318
1319 Mock::VerifyAndClearExpectations(syncer());
1320
1321 // Local nudges for non-backed off types will trigger a sync.
1322 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1323 .WillRepeatedly(
1324 DoAll(Invoke(SimulateNormalSuccess), RecordSyncShare(×, true)));
1325 scheduler()->ScheduleLocalNudge(unbacked_off_types, FROM_HERE);
1326 RunLoop();
1327 Mock::VerifyAndClearExpectations(syncer());
1328
1329 StopSyncScheduler();
1330 }
1331
1332 // Test nudges / polls don't run in config mode and config tasks do.
TEST_F(SyncSchedulerImplTest,ConfigurationMode)1333 TEST_F(SyncSchedulerImplTest, ConfigurationMode) {
1334 TimeDelta poll(TimeDelta::FromMilliseconds(15));
1335 SyncShareTimes times;
1336 scheduler()->OnReceivedPollIntervalUpdate(poll);
1337
1338 StartSyncConfiguration();
1339
1340 const ModelTypeSet nudge_types(TYPED_URLS);
1341 scheduler()->ScheduleLocalNudge(nudge_types, FROM_HERE);
1342 scheduler()->ScheduleLocalNudge(nudge_types, FROM_HERE);
1343
1344 const ModelTypeSet config_types(THEMES);
1345
1346 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
1347 .WillOnce(DoAll(Invoke(SimulateConfigureSuccess),
1348 RecordSyncShare(×, true)))
1349 .RetiresOnSaturation();
1350 CallbackCounter ready_counter;
1351 ConfigurationParams params(sync_pb::SyncEnums::RECONFIGURATION, config_types,
1352 base::BindOnce(&CallbackCounter::Callback,
1353 base::Unretained(&ready_counter)));
1354 scheduler()->ScheduleConfiguration(std::move(params));
1355 RunLoop();
1356 ASSERT_EQ(1, ready_counter.times_called());
1357
1358 Mock::VerifyAndClearExpectations(syncer());
1359
1360 // Switch to NORMAL_MODE to ensure NUDGES were properly saved and run.
1361 scheduler()->OnReceivedPollIntervalUpdate(TimeDelta::FromDays(1));
1362 SyncShareTimes times2;
1363 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1364 .WillOnce(
1365 DoAll(Invoke(SimulateNormalSuccess), RecordSyncShare(×2, true)));
1366
1367 StartSyncScheduler(base::Time());
1368
1369 RunLoop();
1370 Mock::VerifyAndClearExpectations(syncer());
1371 }
1372
1373 class BackoffTriggersSyncSchedulerImplTest : public SyncSchedulerImplTest {
SetUp()1374 void SetUp() override {
1375 SyncSchedulerImplTest::SetUp();
1376 UseMockDelayProvider();
1377 EXPECT_CALL(*delay(), GetDelay(_))
1378 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(10)));
1379 }
1380
TearDown()1381 void TearDown() override {
1382 StopSyncScheduler();
1383 SyncSchedulerImplTest::TearDown();
1384 }
1385 };
1386
1387 // Have the syncer fail during commit. Expect that the scheduler enters
1388 // backoff.
TEST_F(BackoffTriggersSyncSchedulerImplTest,FailCommitOnce)1389 TEST_F(BackoffTriggersSyncSchedulerImplTest, FailCommitOnce) {
1390 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1391 .WillOnce(DoAll(Invoke(SimulateCommitFailed), QuitLoopNowAction(false)));
1392 EXPECT_TRUE(RunAndGetBackoff());
1393 }
1394
1395 // Have the syncer fail during download updates and succeed on the first
1396 // retry. Expect that this clears the backoff state.
TEST_F(BackoffTriggersSyncSchedulerImplTest,FailDownloadOnceThenSucceed)1397 TEST_F(BackoffTriggersSyncSchedulerImplTest, FailDownloadOnceThenSucceed) {
1398 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1399 .WillOnce(DoAll(Invoke(SimulateDownloadUpdatesFailed), Return(false)))
1400 .WillOnce(DoAll(Invoke(SimulateNormalSuccess), QuitLoopNowAction(true)));
1401 EXPECT_FALSE(RunAndGetBackoff());
1402 }
1403
1404 // Have the syncer fail during commit and succeed on the first retry. Expect
1405 // that this clears the backoff state.
TEST_F(BackoffTriggersSyncSchedulerImplTest,FailCommitOnceThenSucceed)1406 TEST_F(BackoffTriggersSyncSchedulerImplTest, FailCommitOnceThenSucceed) {
1407 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1408 .WillOnce(DoAll(Invoke(SimulateCommitFailed), Return(false)))
1409 .WillOnce(DoAll(Invoke(SimulateNormalSuccess), QuitLoopNowAction(true)));
1410 EXPECT_FALSE(RunAndGetBackoff());
1411 }
1412
1413 // Have the syncer fail to download updates and fail again on the retry.
1414 // Expect this will leave the scheduler in backoff.
TEST_F(BackoffTriggersSyncSchedulerImplTest,FailDownloadTwice)1415 TEST_F(BackoffTriggersSyncSchedulerImplTest, FailDownloadTwice) {
1416 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1417 .WillOnce(DoAll(Invoke(SimulateDownloadUpdatesFailed), Return(false)))
1418 .WillRepeatedly(DoAll(Invoke(SimulateDownloadUpdatesFailed),
1419 QuitLoopNowAction(false)));
1420 EXPECT_TRUE(RunAndGetBackoff());
1421 }
1422
1423 // Have the syncer fail to get the encryption key yet succeed in downloading
1424 // updates. Expect this will leave the scheduler in backoff.
TEST_F(BackoffTriggersSyncSchedulerImplTest,FailGetEncryptionKey)1425 TEST_F(BackoffTriggersSyncSchedulerImplTest, FailGetEncryptionKey) {
1426 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
1427 .WillOnce(DoAll(Invoke(SimulateGetEncryptionKeyFailed), Return(false)))
1428 .WillRepeatedly(DoAll(Invoke(SimulateGetEncryptionKeyFailed),
1429 QuitLoopNowAction(false)));
1430 StartSyncConfiguration();
1431
1432 ModelTypeSet types(THEMES);
1433 CallbackCounter ready_counter;
1434 ConfigurationParams params(sync_pb::SyncEnums::RECONFIGURATION, types,
1435 base::BindOnce(&CallbackCounter::Callback,
1436 base::Unretained(&ready_counter)));
1437 scheduler()->ScheduleConfiguration(std::move(params));
1438 RunLoop();
1439
1440 EXPECT_TRUE(scheduler()->IsGlobalBackoff());
1441 }
1442
1443 // Test that no polls or extraneous nudges occur when in backoff.
TEST_F(SyncSchedulerImplTest,BackoffDropsJobs)1444 TEST_F(SyncSchedulerImplTest, BackoffDropsJobs) {
1445 SyncShareTimes times;
1446 TimeDelta poll(TimeDelta::FromMilliseconds(10));
1447 const ModelTypeSet types(THEMES);
1448 scheduler()->OnReceivedPollIntervalUpdate(poll);
1449 UseMockDelayProvider();
1450
1451 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1452 .WillOnce(DoAll(Invoke(SimulateCommitFailed),
1453 RecordSyncShareMultiple(×, 1U, false)));
1454 EXPECT_CALL(*delay(), GetDelay(_))
1455 .WillRepeatedly(Return(TimeDelta::FromDays(1)));
1456
1457 StartSyncScheduler(base::Time());
1458
1459 // This nudge should fail and put us into backoff. Thanks to our mock
1460 // GetDelay() setup above, this will be a long backoff.
1461 scheduler()->ScheduleLocalNudge(types, FROM_HERE);
1462 RunLoop();
1463
1464 // From this point forward, no SyncShare functions should be invoked.
1465 Mock::VerifyAndClearExpectations(syncer());
1466
1467 // Wait a while (10x poll interval) so a few poll jobs will be attempted.
1468 task_environment_.FastForwardBy(poll * 10);
1469
1470 // Try (and fail) to schedule a nudge.
1471 scheduler()->ScheduleLocalNudge(types, FROM_HERE);
1472
1473 Mock::VerifyAndClearExpectations(syncer());
1474 Mock::VerifyAndClearExpectations(delay());
1475
1476 EXPECT_CALL(*delay(), GetDelay(_)).Times(0);
1477
1478 StartSyncConfiguration();
1479
1480 CallbackCounter ready_counter;
1481 ConfigurationParams params(sync_pb::SyncEnums::RECONFIGURATION, types,
1482 base::BindOnce(&CallbackCounter::Callback,
1483 base::Unretained(&ready_counter)));
1484 scheduler()->ScheduleConfiguration(std::move(params));
1485 PumpLoop();
1486 ASSERT_EQ(0, ready_counter.times_called());
1487 }
1488
1489 // Test that backoff is shaping traffic properly with consecutive errors.
TEST_F(SyncSchedulerImplTest,BackoffElevation)1490 TEST_F(SyncSchedulerImplTest, BackoffElevation) {
1491 SyncShareTimes times;
1492 UseMockDelayProvider();
1493
1494 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1495 .Times(kMinNumSamples)
1496 .WillRepeatedly(
1497 DoAll(Invoke(SimulateCommitFailed),
1498 RecordSyncShareMultiple(×, kMinNumSamples, false)));
1499
1500 const TimeDelta first = TimeDelta::FromSeconds(kInitialBackoffRetrySeconds);
1501 const TimeDelta second = TimeDelta::FromMilliseconds(20);
1502 const TimeDelta third = TimeDelta::FromMilliseconds(30);
1503 const TimeDelta fourth = TimeDelta::FromMilliseconds(40);
1504 const TimeDelta fifth = TimeDelta::FromMilliseconds(50);
1505 const TimeDelta sixth = TimeDelta::FromDays(1);
1506
1507 EXPECT_CALL(*delay(), GetDelay(first))
1508 .WillOnce(Return(second))
1509 .RetiresOnSaturation();
1510 EXPECT_CALL(*delay(), GetDelay(second))
1511 .WillOnce(Return(third))
1512 .RetiresOnSaturation();
1513 EXPECT_CALL(*delay(), GetDelay(third))
1514 .WillOnce(Return(fourth))
1515 .RetiresOnSaturation();
1516 EXPECT_CALL(*delay(), GetDelay(fourth))
1517 .WillOnce(Return(fifth))
1518 .RetiresOnSaturation();
1519 EXPECT_CALL(*delay(), GetDelay(fifth)).WillOnce(Return(sixth));
1520
1521 StartSyncScheduler(base::Time());
1522
1523 // Run again with a nudge.
1524 scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE);
1525 RunLoop();
1526
1527 ASSERT_EQ(kMinNumSamples, times.size());
1528 EXPECT_GE(times[1] - times[0], second);
1529 EXPECT_GE(times[2] - times[1], third);
1530 EXPECT_GE(times[3] - times[2], fourth);
1531 EXPECT_GE(times[4] - times[3], fifth);
1532 }
1533
1534 // Test that things go back to normal once a retry makes forward progress.
TEST_F(SyncSchedulerImplTest,BackoffRelief)1535 TEST_F(SyncSchedulerImplTest, BackoffRelief) {
1536 SyncShareTimes times;
1537 UseMockDelayProvider();
1538
1539 const TimeDelta backoff = TimeDelta::FromMilliseconds(10);
1540 EXPECT_CALL(*delay(), GetDelay(_)).WillOnce(Return(backoff));
1541
1542 // Optimal start for the post-backoff poll party.
1543 TimeTicks optimal_start = TimeTicks::Now();
1544 StartSyncScheduler(base::Time());
1545
1546 // Kick off the test with a failed nudge.
1547 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1548 .WillOnce(
1549 DoAll(Invoke(SimulateCommitFailed), RecordSyncShare(×, false)));
1550 scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE);
1551 RunLoop();
1552 Mock::VerifyAndClearExpectations(syncer());
1553 TimeTicks optimal_job_time = optimal_start;
1554 ASSERT_EQ(1U, times.size());
1555 EXPECT_GE(times[0], optimal_job_time);
1556
1557 // The retry succeeds.
1558 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1559 .WillOnce(
1560 DoAll(Invoke(SimulateNormalSuccess), RecordSyncShare(×, true)));
1561 RunLoop();
1562 Mock::VerifyAndClearExpectations(syncer());
1563 optimal_job_time = optimal_job_time + backoff;
1564 ASSERT_EQ(2U, times.size());
1565 EXPECT_GE(times[1], optimal_job_time);
1566
1567 // Now let the Poll timer do its thing.
1568 EXPECT_CALL(*syncer(), PollSyncShare(_, _))
1569 .WillRepeatedly(
1570 DoAll(Invoke(SimulatePollSuccess),
1571 RecordSyncShareMultiple(×, kMinNumSamples, true)));
1572 const TimeDelta poll(TimeDelta::FromMilliseconds(10));
1573 scheduler()->OnReceivedPollIntervalUpdate(poll);
1574
1575 // The new optimal time is now, since the desired poll should have happened
1576 // in the past.
1577 optimal_job_time = TimeTicks::Now();
1578 RunLoop();
1579 Mock::VerifyAndClearExpectations(syncer());
1580 ASSERT_EQ(kMinNumSamples, times.size());
1581 for (size_t i = 2; i < times.size(); i++) {
1582 SCOPED_TRACE(testing::Message() << "SyncShare # (" << i << ")");
1583 EXPECT_GE(times[i], optimal_job_time);
1584 optimal_job_time = optimal_job_time + poll;
1585 }
1586
1587 StopSyncScheduler();
1588 }
1589
1590 // Test that poll failures are treated like any other failure. They should
1591 // result in retry with backoff.
TEST_F(SyncSchedulerImplTest,TransientPollFailure)1592 TEST_F(SyncSchedulerImplTest, TransientPollFailure) {
1593 SyncShareTimes times;
1594 const TimeDelta poll_interval(TimeDelta::FromMilliseconds(10));
1595 scheduler()->OnReceivedPollIntervalUpdate(poll_interval);
1596 UseMockDelayProvider(); // Will cause test failure if backoff is initiated.
1597 EXPECT_CALL(*delay(), GetDelay(_))
1598 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(0)));
1599
1600 EXPECT_CALL(*syncer(), PollSyncShare(_, _))
1601 .WillOnce(
1602 DoAll(Invoke(SimulatePollFailed), RecordSyncShare(×, false)))
1603 .WillOnce(
1604 DoAll(Invoke(SimulatePollSuccess), RecordSyncShare(×, true)));
1605
1606 StartSyncScheduler(base::Time());
1607
1608 // Run the unsuccessful poll. The failed poll should not trigger backoff.
1609 RunLoop();
1610 EXPECT_TRUE(scheduler()->IsGlobalBackoff());
1611
1612 // Run the successful poll.
1613 RunLoop();
1614 EXPECT_FALSE(scheduler()->IsGlobalBackoff());
1615 }
1616
1617 // Test that starting the syncer thread without a valid connection doesn't
1618 // break things when a connection is detected.
TEST_F(SyncSchedulerImplTest,StartWhenNotConnected)1619 TEST_F(SyncSchedulerImplTest, StartWhenNotConnected) {
1620 connection()->SetServerNotReachable();
1621 connection()->UpdateConnectionStatus();
1622 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1623 .WillOnce(DoAll(Invoke(SimulateConnectionFailure), Return(false)))
1624 .WillOnce(DoAll(Invoke(SimulateNormalSuccess), Return(true)));
1625 StartSyncScheduler(base::Time());
1626
1627 scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE);
1628 // Should save the nudge for until after the server is reachable.
1629 base::RunLoop().RunUntilIdle();
1630
1631 scheduler()->OnConnectionStatusChange(
1632 network::mojom::ConnectionType::CONNECTION_WIFI);
1633 connection()->SetServerReachable();
1634 connection()->UpdateConnectionStatus();
1635 base::RunLoop().RunUntilIdle();
1636 }
1637
1638 // Test that when disconnect signal (CONNECTION_NONE) is received, normal sync
1639 // share is not called.
TEST_F(SyncSchedulerImplTest,SyncShareNotCalledWhenDisconnected)1640 TEST_F(SyncSchedulerImplTest, SyncShareNotCalledWhenDisconnected) {
1641 // Set server unavailable, so SyncSchedulerImpl will try to fix connection
1642 // error upon OnConnectionStatusChange().
1643 connection()->SetServerNotReachable();
1644 connection()->UpdateConnectionStatus();
1645 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1646 .Times(1)
1647 .WillOnce(DoAll(Invoke(SimulateConnectionFailure), Return(false)));
1648 StartSyncScheduler(base::Time());
1649
1650 scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE);
1651 // The nudge fails because of the connection failure.
1652 base::RunLoop().RunUntilIdle();
1653
1654 // Simulate a disconnect signal. The scheduler should not retry the previously
1655 // failed nudge.
1656 scheduler()->OnConnectionStatusChange(
1657 network::mojom::ConnectionType::CONNECTION_NONE);
1658 base::RunLoop().RunUntilIdle();
1659 }
1660
TEST_F(SyncSchedulerImplTest,ServerConnectionChangeDuringBackoff)1661 TEST_F(SyncSchedulerImplTest, ServerConnectionChangeDuringBackoff) {
1662 UseMockDelayProvider();
1663 EXPECT_CALL(*delay(), GetDelay(_))
1664 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(0)));
1665
1666 StartSyncScheduler(base::Time());
1667 connection()->SetServerNotReachable();
1668 connection()->UpdateConnectionStatus();
1669
1670 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1671 .WillOnce(DoAll(Invoke(SimulateConnectionFailure), Return(false)))
1672 .WillOnce(DoAll(Invoke(SimulateNormalSuccess), Return(true)));
1673
1674 scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE);
1675 PumpLoop(); // To get PerformDelayedNudge called.
1676 PumpLoop(); // Run the nudge, that will fail and schedule a quick retry.
1677 ASSERT_TRUE(scheduler()->IsGlobalBackoff());
1678
1679 // Before we run the scheduled canary, trigger a server connection change.
1680 scheduler()->OnConnectionStatusChange(
1681 network::mojom::ConnectionType::CONNECTION_WIFI);
1682 connection()->SetServerReachable();
1683 connection()->UpdateConnectionStatus();
1684 base::RunLoop().RunUntilIdle();
1685 }
1686
1687 // This was supposed to test the scenario where we receive a nudge while a
1688 // connection change canary is scheduled, but has not run yet. Since we've made
1689 // the connection change canary synchronous, this is no longer possible.
TEST_F(SyncSchedulerImplTest,ConnectionChangeCanaryPreemptedByNudge)1690 TEST_F(SyncSchedulerImplTest, ConnectionChangeCanaryPreemptedByNudge) {
1691 UseMockDelayProvider();
1692 EXPECT_CALL(*delay(), GetDelay(_))
1693 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(0)));
1694
1695 StartSyncScheduler(base::Time());
1696 connection()->SetServerNotReachable();
1697 connection()->UpdateConnectionStatus();
1698
1699 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1700 .WillOnce(DoAll(Invoke(SimulateConnectionFailure), Return(false)))
1701 .WillOnce(DoAll(Invoke(SimulateNormalSuccess), Return(true)))
1702 .WillOnce(DoAll(Invoke(SimulateNormalSuccess), QuitLoopNowAction(true)));
1703
1704 scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE);
1705
1706 PumpLoop(); // To get PerformDelayedNudge called.
1707 PumpLoop(); // Run the nudge, that will fail and schedule a quick retry.
1708 ASSERT_TRUE(scheduler()->IsGlobalBackoff());
1709
1710 // Before we run the scheduled canary, trigger a server connection change.
1711 scheduler()->OnConnectionStatusChange(
1712 network::mojom::ConnectionType::CONNECTION_WIFI);
1713 PumpLoop();
1714 connection()->SetServerReachable();
1715 connection()->UpdateConnectionStatus();
1716 scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE);
1717 base::RunLoop().RunUntilIdle();
1718 }
1719
1720 // Tests that we don't crash trying to run two canaries at once if we receive
1721 // extra connection status change notifications. See crbug.com/190085.
TEST_F(SyncSchedulerImplTest,DoubleCanaryInConfigure)1722 TEST_F(SyncSchedulerImplTest, DoubleCanaryInConfigure) {
1723 EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _))
1724 .WillRepeatedly(
1725 DoAll(Invoke(SimulateConfigureConnectionFailure), Return(true)));
1726 StartSyncConfiguration();
1727 connection()->SetServerNotReachable();
1728 connection()->UpdateConnectionStatus();
1729
1730 ModelTypeSet model_types(THEMES);
1731 CallbackCounter ready_counter;
1732 ConfigurationParams params(sync_pb::SyncEnums::RECONFIGURATION, model_types,
1733 base::BindOnce(&CallbackCounter::Callback,
1734 base::Unretained(&ready_counter)));
1735 scheduler()->ScheduleConfiguration(std::move(params));
1736
1737 scheduler()->OnConnectionStatusChange(
1738 network::mojom::ConnectionType::CONNECTION_WIFI);
1739 scheduler()->OnConnectionStatusChange(
1740 network::mojom::ConnectionType::CONNECTION_WIFI);
1741
1742 PumpLoop(); // Run the nudge, that will fail and schedule a quick retry.
1743 }
1744
TEST_F(SyncSchedulerImplTest,PollFromCanaryAfterAuthError)1745 TEST_F(SyncSchedulerImplTest, PollFromCanaryAfterAuthError) {
1746 SyncShareTimes times;
1747 TimeDelta poll(TimeDelta::FromMilliseconds(15));
1748 scheduler()->OnReceivedPollIntervalUpdate(poll);
1749
1750 ::testing::InSequence seq;
1751 EXPECT_CALL(*syncer(), PollSyncShare(_, _))
1752 .WillRepeatedly(
1753 DoAll(Invoke(SimulatePollSuccess),
1754 RecordSyncShareMultiple(×, kMinNumSamples, true)));
1755
1756 connection()->SetServerResponse(
1757 HttpResponse::ForHttpStatusCode(net::HTTP_UNAUTHORIZED));
1758 StartSyncScheduler(base::Time());
1759
1760 // Run to wait for polling.
1761 RunLoop();
1762
1763 // Normally OnCredentialsUpdated calls TryCanaryJob that doesn't run Poll,
1764 // but after poll finished with auth error from poll timer it should retry
1765 // poll once more
1766 EXPECT_CALL(*syncer(), PollSyncShare(_, _))
1767 .WillOnce(
1768 DoAll(Invoke(SimulatePollSuccess), RecordSyncShare(×, true)));
1769 scheduler()->OnCredentialsUpdated();
1770 connection()->SetServerResponse(HttpResponse::ForSuccess());
1771 RunLoop();
1772 StopSyncScheduler();
1773 }
1774
TEST_F(SyncSchedulerImplTest,SuccessfulRetry)1775 TEST_F(SyncSchedulerImplTest, SuccessfulRetry) {
1776 StartSyncScheduler(base::Time());
1777
1778 SyncShareTimes times;
1779 TimeDelta delay = TimeDelta::FromMilliseconds(10);
1780 scheduler()->OnReceivedGuRetryDelay(delay);
1781 EXPECT_EQ(delay, GetRetryTimerDelay());
1782
1783 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1784 .WillOnce(
1785 DoAll(Invoke(SimulateNormalSuccess), RecordSyncShare(×, true)));
1786
1787 // Run to wait for retrying.
1788 RunLoop();
1789
1790 StopSyncScheduler();
1791 }
1792
TEST_F(SyncSchedulerImplTest,FailedRetry)1793 TEST_F(SyncSchedulerImplTest, FailedRetry) {
1794 SyncShareTimes times;
1795
1796 UseMockDelayProvider();
1797 EXPECT_CALL(*delay(), GetDelay(_))
1798 .WillRepeatedly(Return(TimeDelta::FromMilliseconds(10)));
1799
1800 StartSyncScheduler(base::Time());
1801
1802 TimeDelta delay = TimeDelta::FromMilliseconds(10);
1803 scheduler()->OnReceivedGuRetryDelay(delay);
1804
1805 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1806 .WillOnce(DoAll(Invoke(SimulateDownloadUpdatesFailed),
1807 RecordSyncShare(×, false)));
1808
1809 // Run to wait for retrying.
1810 RunLoop();
1811
1812 EXPECT_TRUE(scheduler()->IsGlobalBackoff());
1813 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1814 .WillOnce(
1815 DoAll(Invoke(SimulateNormalSuccess), RecordSyncShare(×, true)));
1816
1817 // Run to wait for second retrying.
1818 RunLoop();
1819
1820 StopSyncScheduler();
1821 }
1822
ACTION_P2(VerifyRetryTimerDelay,scheduler_test,expected_delay)1823 ACTION_P2(VerifyRetryTimerDelay, scheduler_test, expected_delay) {
1824 EXPECT_EQ(expected_delay, scheduler_test->GetRetryTimerDelay());
1825 }
1826
TEST_F(SyncSchedulerImplTest,ReceiveNewRetryDelay)1827 TEST_F(SyncSchedulerImplTest, ReceiveNewRetryDelay) {
1828 StartSyncScheduler(base::Time());
1829
1830 SyncShareTimes times;
1831 TimeDelta delay1 = TimeDelta::FromMilliseconds(100);
1832 TimeDelta delay2 = TimeDelta::FromMilliseconds(200);
1833
1834 scheduler()->ScheduleLocalNudge(ModelTypeSet(THEMES), FROM_HERE);
1835 scheduler()->OnReceivedGuRetryDelay(delay1);
1836 EXPECT_EQ(delay1, GetRetryTimerDelay());
1837
1838 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1839 .WillOnce(DoAll(WithoutArgs(VerifyRetryTimerDelay(this, delay1)),
1840 WithArg<2>(SimulateGuRetryDelayCommand(delay2)),
1841 RecordSyncShare(×, true)));
1842
1843 // Run nudge GU.
1844 RunLoop();
1845 EXPECT_EQ(delay2, GetRetryTimerDelay());
1846
1847 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1848 .WillOnce(
1849 DoAll(Invoke(SimulateNormalSuccess), RecordSyncShare(×, true)));
1850
1851 // Run to wait for retrying.
1852 RunLoop();
1853
1854 StopSyncScheduler();
1855 }
1856
TEST_F(SyncSchedulerImplTest,PartialFailureWillExponentialBackoff)1857 TEST_F(SyncSchedulerImplTest, PartialFailureWillExponentialBackoff) {
1858 TimeDelta poll(TimeDelta::FromDays(1));
1859 scheduler()->OnReceivedPollIntervalUpdate(poll);
1860
1861 const ModelTypeSet types(THEMES);
1862
1863 ::testing::InSequence seq;
1864 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1865 .WillRepeatedly(
1866 DoAll(WithArg<2>(SimulatePartialFailure(types)), Return(true)))
1867 .RetiresOnSaturation();
1868
1869 StartSyncScheduler(base::Time());
1870 scheduler()->ScheduleLocalNudge(types, FROM_HERE);
1871 PumpLoop(); // To get PerformDelayedNudge called.
1872 PumpLoop(); // To get TrySyncCycleJob called
1873 EXPECT_TRUE(GetBackedOffTypes().HasAll(types));
1874 EXPECT_FALSE(scheduler()->IsGlobalBackoff());
1875 EXPECT_FALSE(scheduler()->IsGlobalThrottle());
1876 TimeDelta first_blocking_time = GetTypeBlockingTime(THEMES);
1877
1878 SetTypeBlockingMode(THEMES, WaitInterval::EXPONENTIAL_BACKOFF_RETRYING);
1879 // This won't cause a sync cycle because the types are backed off.
1880 scheduler()->ScheduleLocalNudge(types, FROM_HERE);
1881 PumpLoop();
1882 PumpLoop();
1883 TimeDelta second_blocking_time = GetTypeBlockingTime(THEMES);
1884
1885 // The Exponential backoff should be between previous backoff 1.5 and 2.5
1886 // times.
1887 EXPECT_LE(first_blocking_time * 1.5, second_blocking_time);
1888 EXPECT_GE(first_blocking_time * 2.5, second_blocking_time);
1889
1890 StopSyncScheduler();
1891 }
1892
1893 // If a datatype is in backoff or throttling, pending_wakeup_timer_ should
1894 // schedule a delay job for OnTypesUnblocked. SyncScheduler sometimes use
1895 // pending_wakeup_timer_ to schdule PerformDelayedNudge job before
1896 // OnTypesUnblocked got run. This test will verify after ran
1897 // PerformDelayedNudge, OnTypesUnblocked will be rescheduled if any datatype is
1898 // in backoff or throttling.
TEST_F(SyncSchedulerImplTest,TypeBackoffAndSuccessfulSync)1899 TEST_F(SyncSchedulerImplTest, TypeBackoffAndSuccessfulSync) {
1900 UseMockDelayProvider();
1901 EXPECT_CALL(*delay(), GetDelay(_)).WillRepeatedly(Return(long_delay()));
1902
1903 TimeDelta poll(TimeDelta::FromDays(1));
1904 scheduler()->OnReceivedPollIntervalUpdate(poll);
1905
1906 const ModelTypeSet types(THEMES);
1907
1908 // Set backoff datatype.
1909 ::testing::InSequence seq;
1910 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1911 .WillOnce(DoAll(WithArg<2>(SimulatePartialFailure(types)), Return(true)))
1912 .RetiresOnSaturation();
1913
1914 StartSyncScheduler(base::Time());
1915 scheduler()->ScheduleLocalNudge(types, FROM_HERE);
1916 PumpLoop(); // To get PerformDelayedNudge called.
1917 PumpLoop(); // To get TrySyncCycleJob called
1918 EXPECT_TRUE(GetBackedOffTypes().HasAll(types));
1919 EXPECT_TRUE(BlockTimerIsRunning());
1920 EXPECT_FALSE(scheduler()->IsGlobalBackoff());
1921 EXPECT_FALSE(scheduler()->IsGlobalThrottle());
1922
1923 SyncShareTimes times;
1924 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1925 .WillOnce(
1926 DoAll(Invoke(SimulateNormalSuccess), RecordSyncShare(×, true)))
1927 .RetiresOnSaturation();
1928
1929 // Do a successful Sync.
1930 const ModelTypeSet unbacked_off_types(TYPED_URLS);
1931 scheduler()->ScheduleLocalNudge(unbacked_off_types, FROM_HERE);
1932 PumpLoop(); // TO get PerformDelayedNudge called.
1933 PumpLoop(); // To get TrySyncCycleJob called.
1934
1935 // Timer is still running for backoff datatype after Sync success.
1936 EXPECT_TRUE(GetBackedOffTypes().HasAll(types));
1937 EXPECT_TRUE(BlockTimerIsRunning());
1938 EXPECT_FALSE(scheduler()->IsGlobalBackoff());
1939 EXPECT_FALSE(scheduler()->IsGlobalThrottle());
1940
1941 StopSyncScheduler();
1942 }
1943
1944 // Verify that the timer is scheduled for an unblock job after one datatype is
1945 // unblocked, and there is another one still blocked.
TEST_F(SyncSchedulerImplTest,TypeBackingOffAndFailureSync)1946 TEST_F(SyncSchedulerImplTest, TypeBackingOffAndFailureSync) {
1947 UseMockDelayProvider();
1948 EXPECT_CALL(*delay(), GetDelay(_))
1949 .WillOnce(Return(long_delay()))
1950 .RetiresOnSaturation();
1951
1952 TimeDelta poll(TimeDelta::FromDays(1));
1953 scheduler()->OnReceivedPollIntervalUpdate(poll);
1954
1955 // Set a backoff datatype.
1956 const ModelTypeSet themes_types(THEMES);
1957 ::testing::InSequence seq;
1958 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1959 .WillOnce(
1960 DoAll(WithArg<2>(SimulatePartialFailure(themes_types)), Return(true)))
1961 .RetiresOnSaturation();
1962
1963 StartSyncScheduler(base::Time());
1964 scheduler()->ScheduleLocalNudge(themes_types, FROM_HERE);
1965 PumpLoop(); // To get PerformDelayedNudge called.
1966 PumpLoop(); // To get TrySyncCycleJob called
1967 EXPECT_TRUE(GetBackedOffTypes().HasAll(themes_types));
1968 EXPECT_TRUE(BlockTimerIsRunning());
1969 EXPECT_FALSE(scheduler()->IsGlobalBackoff());
1970 EXPECT_FALSE(scheduler()->IsGlobalThrottle());
1971
1972 // Set anther backoff datatype.
1973 const ModelTypeSet typed_urls_types(TYPED_URLS);
1974 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1975 .WillOnce(DoAll(WithArg<2>(SimulatePartialFailure(typed_urls_types)),
1976 Return(true)))
1977 .RetiresOnSaturation();
1978 EXPECT_CALL(*delay(), GetDelay(_))
1979 .WillOnce(Return(default_delay()))
1980 .RetiresOnSaturation();
1981
1982 scheduler()->ScheduleLocalNudge(typed_urls_types, FROM_HERE);
1983 PumpLoop(); // TO get PerformDelayedNudge called.
1984 PumpLoop(); // To get TrySyncCycleJob called.
1985
1986 EXPECT_TRUE(GetBackedOffTypes().HasAll(themes_types));
1987 EXPECT_TRUE(GetBackedOffTypes().HasAll(typed_urls_types));
1988 EXPECT_TRUE(BlockTimerIsRunning());
1989 EXPECT_FALSE(scheduler()->IsGlobalBackoff());
1990 EXPECT_FALSE(scheduler()->IsGlobalThrottle());
1991
1992 // Unblock one datatype.
1993 SyncShareTimes times;
1994 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
1995 .WillRepeatedly(
1996 DoAll(Invoke(SimulateNormalSuccess), RecordSyncShare(×, true)));
1997 EXPECT_CALL(*delay(), GetDelay(_)).WillRepeatedly(Return(long_delay()));
1998
1999 PumpLoop(); // TO get OnTypesUnblocked called.
2000 PumpLoop(); // To get TrySyncCycleJob called.
2001
2002 // Timer is still scheduled for another backoff datatype.
2003 EXPECT_TRUE(GetBackedOffTypes().HasAll(themes_types));
2004 EXPECT_FALSE(GetBackedOffTypes().HasAll(typed_urls_types));
2005 EXPECT_TRUE(BlockTimerIsRunning());
2006 EXPECT_FALSE(scheduler()->IsGlobalBackoff());
2007 EXPECT_FALSE(scheduler()->IsGlobalThrottle());
2008
2009 StopSyncScheduler();
2010 }
2011
TEST_F(SyncSchedulerImplTest,InterleavedNudgesStillRestart)2012 TEST_F(SyncSchedulerImplTest, InterleavedNudgesStillRestart) {
2013 UseMockDelayProvider();
2014 EXPECT_CALL(*delay(), GetDelay(_))
2015 .WillOnce(Return(long_delay()))
2016 .RetiresOnSaturation();
2017 TimeDelta poll(TimeDelta::FromDays(1));
2018 scheduler()->OnReceivedPollIntervalUpdate(poll);
2019
2020 StartSyncScheduler(base::Time());
2021 scheduler()->ScheduleLocalNudge({THEMES}, FROM_HERE);
2022 PumpLoop(); // To get PerformDelayedNudge called.
2023 EXPECT_FALSE(BlockTimerIsRunning());
2024 EXPECT_FALSE(scheduler()->IsGlobalBackoff());
2025
2026 // This is the tricky piece. We have a gap while the sync job is bouncing to
2027 // get onto the |pending_wakeup_timer_|, should be scheduled with no delay.
2028 scheduler()->ScheduleLocalNudge({TYPED_URLS}, FROM_HERE);
2029 EXPECT_TRUE(BlockTimerIsRunning());
2030 EXPECT_EQ(TimeDelta(), GetPendingWakeupTimerDelay());
2031 EXPECT_FALSE(scheduler()->IsGlobalBackoff());
2032
2033 // Setup mock as we're about to attempt to sync.
2034 SyncShareTimes times;
2035 EXPECT_CALL(*syncer(), NormalSyncShare(_, _, _))
2036 .WillOnce(
2037 DoAll(Invoke(SimulateCommitFailed), RecordSyncShare(×, false)));
2038 // Triggers the THEMES TrySyncCycleJobImpl(), which we've setup to fail. Its
2039 // RestartWaiting won't schedule a delayed retry, as the TYPED_URLS nudge has
2040 // a smaller delay. We verify this by making sure the delay is still zero.
2041 PumpLoop();
2042 EXPECT_TRUE(BlockTimerIsRunning());
2043 EXPECT_EQ(TimeDelta(), GetPendingWakeupTimerDelay());
2044 EXPECT_TRUE(scheduler()->IsGlobalBackoff());
2045
2046 // Triggers TYPED_URLS PerformDelayedNudge(), which should no-op, because
2047 // we're no long healthy, and normal priorities shouldn't go through, but it
2048 // does need to setup the |pending_wakeup_timer_|. The delay should be ~60
2049 // seconds, so verifying it's greater than 50 should be safe.
2050 PumpLoop();
2051 EXPECT_TRUE(BlockTimerIsRunning());
2052 EXPECT_LT(TimeDelta::FromSeconds(50), GetPendingWakeupTimerDelay());
2053 EXPECT_TRUE(scheduler()->IsGlobalBackoff());
2054 }
2055
TEST_F(SyncSchedulerImplTest,PollOnStartUpAfterLongPause)2056 TEST_F(SyncSchedulerImplTest, PollOnStartUpAfterLongPause) {
2057 base::Time now = base::Time::Now();
2058 base::TimeDelta poll_interval = base::TimeDelta::FromHours(4);
2059 base::Time last_reset = ComputeLastPollOnStart(
2060 /*last_poll=*/now - base::TimeDelta::FromDays(1), poll_interval, now);
2061 EXPECT_THAT(last_reset, Gt(now - poll_interval));
2062 // The max poll delay is 1% of the poll_interval.
2063 EXPECT_THAT(last_reset, Lt(now - 0.99 * poll_interval));
2064 }
2065
TEST_F(SyncSchedulerImplTest,PollOnStartUpAfterShortPause)2066 TEST_F(SyncSchedulerImplTest, PollOnStartUpAfterShortPause) {
2067 base::Time now = base::Time::Now();
2068 base::TimeDelta poll_interval = base::TimeDelta::FromHours(4);
2069 base::Time last_poll = now - base::TimeDelta::FromHours(2);
2070 EXPECT_THAT(ComputeLastPollOnStart(last_poll, poll_interval, now),
2071 Eq(last_poll));
2072 }
2073
2074 // Verifies that the delay is in [0, 0.01*poll_interval) and spot checks the
2075 // random number generation.
TEST_F(SyncSchedulerImplTest,PollOnStartUpWithinBoundsAfterLongPause)2076 TEST_F(SyncSchedulerImplTest, PollOnStartUpWithinBoundsAfterLongPause) {
2077 base::Time now = base::Time::Now();
2078 base::TimeDelta poll_interval = base::TimeDelta::FromHours(4);
2079 base::Time last_poll = now - base::TimeDelta::FromDays(2);
2080 bool found_delay_greater_than_5_permille = false;
2081 bool found_delay_less_or_equal_5_permille = false;
2082 for (int i = 0; i < 10000; ++i) {
2083 const base::Time result =
2084 ComputeLastPollOnStart(last_poll, poll_interval, now);
2085 const base::TimeDelta delay = result + poll_interval - now;
2086 const double fraction = delay / poll_interval;
2087 if (fraction > 0.005) {
2088 found_delay_greater_than_5_permille = true;
2089 } else {
2090 found_delay_less_or_equal_5_permille = true;
2091 }
2092 EXPECT_THAT(fraction, Ge(0));
2093 EXPECT_THAT(fraction, Lt(0.01));
2094 }
2095 EXPECT_TRUE(found_delay_greater_than_5_permille);
2096 EXPECT_TRUE(found_delay_less_or_equal_5_permille);
2097 }
2098
TEST_F(SyncSchedulerImplTest,TestResetPollIntervalOnStartFeatureFlag)2099 TEST_F(SyncSchedulerImplTest, TestResetPollIntervalOnStartFeatureFlag) {
2100 base::test::ScopedFeatureList feature_list;
2101 feature_list.InitAndEnableFeature(switches::kSyncResetPollIntervalOnStart);
2102 base::Time now = base::Time::Now();
2103 base::TimeDelta poll_interval = base::TimeDelta::FromHours(4);
2104 EXPECT_THAT(
2105 ComputeLastPollOnStart(
2106 /*last_poll=*/now - base::TimeDelta::FromDays(1), poll_interval, now),
2107 Eq(now));
2108 }
2109
2110 } // namespace syncer
2111