1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/sync_file_system/sync_process_runner.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "testing/gtest/include/gtest/gtest.h"
12 namespace sync_file_system
{
16 class FakeClient
: public SyncProcessRunner::Client
{
18 FakeClient() : service_state_(SYNC_SERVICE_RUNNING
) {}
19 ~FakeClient() override
{}
21 SyncServiceState
GetSyncServiceState() override
{ return service_state_
; }
23 SyncFileSystemService
* GetSyncService() override
{ return nullptr; }
25 void set_service_state(SyncServiceState service_state
) {
26 service_state_
= service_state
;
30 SyncServiceState service_state_
;
32 DISALLOW_COPY_AND_ASSIGN(FakeClient
);
35 class FakeTimerHelper
: public SyncProcessRunner::TimerHelper
{
38 ~FakeTimerHelper() override
{}
40 bool IsRunning() override
{ return !timer_task_
.is_null(); }
42 void Start(const tracked_objects::Location
& from_here
,
43 const base::TimeDelta
& delay
,
44 const base::Closure
& closure
) override
{
45 scheduled_time_
= current_time_
+ delay
;
46 timer_task_
= closure
;
49 base::TimeTicks
Now() const override
{ return current_time_
; }
51 void SetCurrentTime(const base::TimeTicks
& current_time
) {
52 current_time_
= current_time
;
53 if (current_time_
< scheduled_time_
|| timer_task_
.is_null())
56 base::Closure task
= timer_task_
;
61 void AdvanceToScheduledTime() {
62 SetCurrentTime(scheduled_time_
);
65 int64
GetCurrentDelay() {
66 EXPECT_FALSE(timer_task_
.is_null());
67 return (scheduled_time_
- current_time_
).InMilliseconds();
71 base::TimeTicks current_time_
;
72 base::TimeTicks scheduled_time_
;
73 base::Closure timer_task_
;
75 DISALLOW_COPY_AND_ASSIGN(FakeTimerHelper
);
78 class FakeSyncProcessRunner
: public SyncProcessRunner
{
80 FakeSyncProcessRunner(SyncProcessRunner::Client
* client
,
81 scoped_ptr
<TimerHelper
> timer_helper
,
82 size_t max_parallel_task
)
83 : SyncProcessRunner("FakeSyncProcess",
84 client
, timer_helper
.Pass(),
86 max_parallel_task_(max_parallel_task
) {
89 void StartSync(const SyncStatusCallback
& callback
) override
{
90 EXPECT_LT(running_tasks_
.size(), max_parallel_task_
);
91 running_tasks_
.push(callback
);
94 ~FakeSyncProcessRunner() override
{}
96 void UpdateChanges(int num_changes
) {
97 OnChangesUpdated(num_changes
);
100 void CompleteTask(SyncStatusCode status
) {
101 ASSERT_FALSE(running_tasks_
.empty());
102 SyncStatusCallback task
= running_tasks_
.front();
103 running_tasks_
.pop();
107 bool HasRunningTask() const {
108 return !running_tasks_
.empty();
112 size_t max_parallel_task_
;
113 std::queue
<SyncStatusCallback
> running_tasks_
;
115 DISALLOW_COPY_AND_ASSIGN(FakeSyncProcessRunner
);
120 TEST(SyncProcessRunnerTest
, SingleTaskBasicTest
) {
121 FakeClient fake_client
;
122 FakeTimerHelper
* fake_timer
= new FakeTimerHelper();
123 FakeSyncProcessRunner
fake_runner(
125 scoped_ptr
<SyncProcessRunner::TimerHelper
>(fake_timer
),
126 1 /* max_parallel_task */);
128 base::TimeTicks base_time
= base::TimeTicks::Now();
129 fake_timer
->SetCurrentTime(base_time
);
131 // SyncProcessRunner is expected not to run a task initially.
132 EXPECT_FALSE(fake_timer
->IsRunning());
134 // As soon as SyncProcessRunner gets a new update, it should start running
135 // the timer to run a synchronization task.
136 fake_runner
.UpdateChanges(100);
137 EXPECT_TRUE(fake_timer
->IsRunning());
138 EXPECT_EQ(SyncProcessRunner::kSyncDelayFastInMilliseconds
,
139 fake_timer
->GetCurrentDelay());
141 // When the time has come, the timer should fire the scheduled task.
142 fake_timer
->AdvanceToScheduledTime();
143 EXPECT_FALSE(fake_timer
->IsRunning());
144 EXPECT_TRUE(fake_runner
.HasRunningTask());
146 // Successful completion of the task fires next synchronization task.
147 fake_runner
.CompleteTask(SYNC_STATUS_OK
);
148 EXPECT_TRUE(fake_timer
->IsRunning());
149 EXPECT_FALSE(fake_runner
.HasRunningTask());
150 EXPECT_EQ(SyncProcessRunner::kSyncDelayFastInMilliseconds
,
151 fake_timer
->GetCurrentDelay());
153 // Turn |service_state| to TEMPORARY_UNAVAILABLE and let the task fail.
154 // |fake_runner| should schedule following tasks with longer delay.
155 fake_timer
->AdvanceToScheduledTime();
156 fake_client
.set_service_state(SYNC_SERVICE_TEMPORARY_UNAVAILABLE
);
157 fake_runner
.CompleteTask(SYNC_STATUS_FAILED
);
158 EXPECT_EQ(SyncProcessRunner::kSyncDelaySlowInMilliseconds
,
159 fake_timer
->GetCurrentDelay());
161 // Repeated failure makes the task delay back off.
162 fake_timer
->AdvanceToScheduledTime();
163 fake_runner
.CompleteTask(SYNC_STATUS_FAILED
);
164 EXPECT_EQ(2 * SyncProcessRunner::kSyncDelaySlowInMilliseconds
,
165 fake_timer
->GetCurrentDelay());
167 // After |service_state| gets back to normal state, SyncProcessRunner should
168 // restart rapid task invocation.
169 fake_client
.set_service_state(SYNC_SERVICE_RUNNING
);
170 fake_timer
->AdvanceToScheduledTime();
171 fake_runner
.CompleteTask(SYNC_STATUS_OK
);
172 EXPECT_EQ(SyncProcessRunner::kSyncDelayFastInMilliseconds
,
173 fake_timer
->GetCurrentDelay());
175 // There's no item to sync anymore, SyncProcessRunner should schedules the
176 // next with the longest delay.
177 fake_runner
.UpdateChanges(0);
178 fake_timer
->AdvanceToScheduledTime();
179 fake_runner
.CompleteTask(SYNC_STATUS_OK
);
180 EXPECT_EQ(SyncProcessRunner::kSyncDelayMaxInMilliseconds
,
181 fake_timer
->GetCurrentDelay());
183 // Schedule the next with the longest delay if the client is persistently
185 fake_client
.set_service_state(SYNC_SERVICE_AUTHENTICATION_REQUIRED
);
186 fake_runner
.UpdateChanges(100);
187 EXPECT_EQ(SyncProcessRunner::kSyncDelayMaxInMilliseconds
,
188 fake_timer
->GetCurrentDelay());
191 TEST(SyncProcessRunnerTest
, MultiTaskBasicTest
) {
192 FakeClient fake_client
;
193 FakeTimerHelper
* fake_timer
= new FakeTimerHelper();
194 FakeSyncProcessRunner
fake_runner(
196 scoped_ptr
<SyncProcessRunner::TimerHelper
>(fake_timer
),
197 2 /* max_parallel_task */);
199 base::TimeTicks base_time
= base::TimeTicks::Now();
200 fake_timer
->SetCurrentTime(base_time
);
202 EXPECT_FALSE(fake_timer
->IsRunning());
204 fake_runner
.UpdateChanges(100);
205 EXPECT_TRUE(fake_timer
->IsRunning());
206 EXPECT_EQ(SyncProcessRunner::kSyncDelayFastInMilliseconds
,
207 fake_timer
->GetCurrentDelay());
209 // Even after a task starts running, SyncProcessRunner should schedule next
210 // task until the number of running task reachs the limit.
211 fake_timer
->AdvanceToScheduledTime();
212 EXPECT_TRUE(fake_timer
->IsRunning());
213 EXPECT_TRUE(fake_runner
.HasRunningTask());
214 EXPECT_EQ(SyncProcessRunner::kSyncDelayFastInMilliseconds
,
215 fake_timer
->GetCurrentDelay());
217 // After the second task starts running, SyncProcessRunner should stop
218 // scheduling a task.
219 fake_timer
->AdvanceToScheduledTime();
220 EXPECT_FALSE(fake_timer
->IsRunning());
221 EXPECT_TRUE(fake_runner
.HasRunningTask());
223 fake_runner
.CompleteTask(SYNC_STATUS_OK
);
224 EXPECT_TRUE(fake_timer
->IsRunning());
225 EXPECT_TRUE(fake_runner
.HasRunningTask());
226 fake_runner
.CompleteTask(SYNC_STATUS_OK
);
227 EXPECT_TRUE(fake_timer
->IsRunning());
228 EXPECT_FALSE(fake_runner
.HasRunningTask());
230 // Turn |service_state| to TEMPORARY_UNAVAILABLE and let the task fail.
231 // |fake_runner| should schedule following tasks with longer delay.
232 fake_timer
->AdvanceToScheduledTime();
233 fake_timer
->AdvanceToScheduledTime();
234 fake_client
.set_service_state(SYNC_SERVICE_TEMPORARY_UNAVAILABLE
);
235 fake_runner
.CompleteTask(SYNC_STATUS_FAILED
);
236 EXPECT_EQ(SyncProcessRunner::kSyncDelaySlowInMilliseconds
,
237 fake_timer
->GetCurrentDelay());
239 // Consecutive error reports shouldn't extend delay immediately.
240 fake_runner
.CompleteTask(SYNC_STATUS_FAILED
);
241 EXPECT_EQ(SyncProcessRunner::kSyncDelaySlowInMilliseconds
,
242 fake_timer
->GetCurrentDelay());
244 // The next task will run after throttle period is over.
245 // And its failure should extend the throttle period by twice.
246 fake_timer
->AdvanceToScheduledTime();
247 EXPECT_EQ(SyncProcessRunner::kSyncDelaySlowInMilliseconds
,
248 fake_timer
->GetCurrentDelay());
249 fake_runner
.CompleteTask(SYNC_STATUS_FAILED
);
250 EXPECT_EQ(2 * SyncProcessRunner::kSyncDelaySlowInMilliseconds
,
251 fake_timer
->GetCurrentDelay());
253 // Next successful task should clear the throttling.
254 fake_timer
->AdvanceToScheduledTime();
255 fake_client
.set_service_state(SYNC_SERVICE_RUNNING
);
256 fake_runner
.CompleteTask(SYNC_STATUS_OK
);
257 EXPECT_EQ(SyncProcessRunner::kSyncDelayFastInMilliseconds
,
258 fake_timer
->GetCurrentDelay());
260 // Then, following failing task should not extend throttling period.
261 fake_timer
->AdvanceToScheduledTime();
262 fake_client
.set_service_state(SYNC_SERVICE_TEMPORARY_UNAVAILABLE
);
263 fake_runner
.CompleteTask(SYNC_STATUS_FAILED
);
264 EXPECT_EQ(SyncProcessRunner::kSyncDelaySlowInMilliseconds
,
265 fake_timer
->GetCurrentDelay());
268 } // namespace sync_file_system