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(&times, 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(&times2, 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(&times, 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(&times, 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(&times, false)))
585       .WillOnce(DoAll(Invoke(SimulateConfigureFailed),
586                       RecordSyncShare(&times, 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(&times, 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(&times, 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(&times, 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(&times, 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(&times, 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(&times, 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(&times, 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(&times, 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(&times2, 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(&times, 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(&times1, 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(&times2, 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(&times, 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(&times, 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(&times, 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(&times, 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(&times, 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(&times, 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(&times, 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(&times, 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(&times, 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(&times, 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(&times2, 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(&times, 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(&times, 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(&times, 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(&times, 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(&times, 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(&times, false)))
1603       .WillOnce(
1604           DoAll(Invoke(SimulatePollSuccess), RecordSyncShare(&times, 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(&times, 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(&times, 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(&times, 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(&times, 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(&times, 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(&times, 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(&times, 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(&times, 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(&times, 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(&times, 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