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 virtual ~FakeClient() {}
21 virtual SyncServiceState
GetSyncServiceState() OVERRIDE
{
22 return service_state_
;
25 virtual SyncFileSystemService
* GetSyncService() OVERRIDE
{
29 void set_service_state(SyncServiceState service_state
) {
30 service_state_
= service_state
;
34 SyncServiceState service_state_
;
36 DISALLOW_COPY_AND_ASSIGN(FakeClient
);
39 class FakeTimerHelper
: public SyncProcessRunner::TimerHelper
{
42 virtual ~FakeTimerHelper() {}
44 virtual bool IsRunning() OVERRIDE
{
45 return !timer_task_
.is_null();
48 virtual void Start(const tracked_objects::Location
& from_here
,
49 const base::TimeDelta
& delay
,
50 const base::Closure
& closure
) OVERRIDE
{
51 scheduled_time_
= current_time_
+ delay
;
52 timer_task_
= closure
;
55 virtual base::TimeTicks
Now() const OVERRIDE
{
59 void SetCurrentTime(const base::TimeTicks
& current_time
) {
60 current_time_
= current_time
;
61 if (current_time_
< scheduled_time_
|| timer_task_
.is_null())
64 base::Closure task
= timer_task_
;
69 void AdvanceToScheduledTime() {
70 SetCurrentTime(scheduled_time_
);
73 int64
GetCurrentDelay() {
74 EXPECT_FALSE(timer_task_
.is_null());
75 return (scheduled_time_
- current_time_
).InMilliseconds();
79 base::TimeTicks current_time_
;
80 base::TimeTicks scheduled_time_
;
81 base::Closure timer_task_
;
83 DISALLOW_COPY_AND_ASSIGN(FakeTimerHelper
);
86 class FakeSyncProcessRunner
: public SyncProcessRunner
{
88 FakeSyncProcessRunner(SyncProcessRunner::Client
* client
,
89 scoped_ptr
<TimerHelper
> timer_helper
,
90 size_t max_parallel_task
)
91 : SyncProcessRunner("FakeSyncProcess",
92 client
, timer_helper
.Pass(),
94 max_parallel_task_(max_parallel_task
) {
97 virtual void StartSync(const SyncStatusCallback
& callback
) OVERRIDE
{
98 EXPECT_LT(running_tasks_
.size(), max_parallel_task_
);
99 running_tasks_
.push(callback
);
102 virtual ~FakeSyncProcessRunner() {
105 void UpdateChanges(int num_changes
) {
106 OnChangesUpdated(num_changes
);
109 void CompleteTask(SyncStatusCode status
) {
110 ASSERT_FALSE(running_tasks_
.empty());
111 SyncStatusCallback task
= running_tasks_
.front();
112 running_tasks_
.pop();
116 bool HasRunningTask() const {
117 return !running_tasks_
.empty();
121 size_t max_parallel_task_
;
122 std::queue
<SyncStatusCallback
> running_tasks_
;
124 DISALLOW_COPY_AND_ASSIGN(FakeSyncProcessRunner
);
129 TEST(SyncProcessRunnerTest
, SingleTaskBasicTest
) {
130 FakeClient fake_client
;
131 FakeTimerHelper
* fake_timer
= new FakeTimerHelper();
132 FakeSyncProcessRunner
fake_runner(
134 scoped_ptr
<SyncProcessRunner::TimerHelper
>(fake_timer
),
135 1 /* max_parallel_task */);
137 base::TimeTicks base_time
= base::TimeTicks::Now();
138 fake_timer
->SetCurrentTime(base_time
);
140 // SyncProcessRunner is expected not to run a task initially.
141 EXPECT_FALSE(fake_timer
->IsRunning());
143 // As soon as SyncProcessRunner gets a new update, it should start running
144 // the timer to run a synchronization task.
145 fake_runner
.UpdateChanges(100);
146 EXPECT_TRUE(fake_timer
->IsRunning());
147 EXPECT_EQ(SyncProcessRunner::kSyncDelayFastInMilliseconds
,
148 fake_timer
->GetCurrentDelay());
150 // When the time has come, the timer should fire the scheduled task.
151 fake_timer
->AdvanceToScheduledTime();
152 EXPECT_FALSE(fake_timer
->IsRunning());
153 EXPECT_TRUE(fake_runner
.HasRunningTask());
155 // Successful completion of the task fires next synchronization task.
156 fake_runner
.CompleteTask(SYNC_STATUS_OK
);
157 EXPECT_TRUE(fake_timer
->IsRunning());
158 EXPECT_FALSE(fake_runner
.HasRunningTask());
159 EXPECT_EQ(SyncProcessRunner::kSyncDelayFastInMilliseconds
,
160 fake_timer
->GetCurrentDelay());
162 // Turn |service_state| to TEMPORARY_UNAVAILABLE and let the task fail.
163 // |fake_runner| should schedule following tasks with longer delay.
164 fake_timer
->AdvanceToScheduledTime();
165 fake_client
.set_service_state(SYNC_SERVICE_TEMPORARY_UNAVAILABLE
);
166 fake_runner
.CompleteTask(SYNC_STATUS_FAILED
);
167 EXPECT_EQ(SyncProcessRunner::kSyncDelaySlowInMilliseconds
,
168 fake_timer
->GetCurrentDelay());
170 // Repeated failure makes the task delay back off.
171 fake_timer
->AdvanceToScheduledTime();
172 fake_runner
.CompleteTask(SYNC_STATUS_FAILED
);
173 EXPECT_EQ(2 * SyncProcessRunner::kSyncDelaySlowInMilliseconds
,
174 fake_timer
->GetCurrentDelay());
176 // After |service_state| gets back to normal state, SyncProcessRunner should
177 // restart rapid task invocation.
178 fake_client
.set_service_state(SYNC_SERVICE_RUNNING
);
179 fake_timer
->AdvanceToScheduledTime();
180 fake_runner
.CompleteTask(SYNC_STATUS_OK
);
181 EXPECT_EQ(SyncProcessRunner::kSyncDelayFastInMilliseconds
,
182 fake_timer
->GetCurrentDelay());
184 // There's no item to sync anymore, SyncProcessRunner should schedules the
185 // next with the longest delay.
186 fake_runner
.UpdateChanges(0);
187 fake_timer
->AdvanceToScheduledTime();
188 fake_runner
.CompleteTask(SYNC_STATUS_OK
);
189 EXPECT_EQ(SyncProcessRunner::kSyncDelayMaxInMilliseconds
,
190 fake_timer
->GetCurrentDelay());
192 // Schedule the next with the longest delay if the client is persistently
194 fake_client
.set_service_state(SYNC_SERVICE_AUTHENTICATION_REQUIRED
);
195 fake_runner
.UpdateChanges(100);
196 EXPECT_EQ(SyncProcessRunner::kSyncDelayMaxInMilliseconds
,
197 fake_timer
->GetCurrentDelay());
200 TEST(SyncProcessRunnerTest
, MultiTaskBasicTest
) {
201 FakeClient fake_client
;
202 FakeTimerHelper
* fake_timer
= new FakeTimerHelper();
203 FakeSyncProcessRunner
fake_runner(
205 scoped_ptr
<SyncProcessRunner::TimerHelper
>(fake_timer
),
206 2 /* max_parallel_task */);
208 base::TimeTicks base_time
= base::TimeTicks::Now();
209 fake_timer
->SetCurrentTime(base_time
);
211 EXPECT_FALSE(fake_timer
->IsRunning());
213 fake_runner
.UpdateChanges(100);
214 EXPECT_TRUE(fake_timer
->IsRunning());
215 EXPECT_EQ(SyncProcessRunner::kSyncDelayFastInMilliseconds
,
216 fake_timer
->GetCurrentDelay());
218 // Even after a task starts running, SyncProcessRunner should schedule next
219 // task until the number of running task reachs the limit.
220 fake_timer
->AdvanceToScheduledTime();
221 EXPECT_TRUE(fake_timer
->IsRunning());
222 EXPECT_TRUE(fake_runner
.HasRunningTask());
223 EXPECT_EQ(SyncProcessRunner::kSyncDelayFastInMilliseconds
,
224 fake_timer
->GetCurrentDelay());
226 // After the second task starts running, SyncProcessRunner should stop
227 // scheduling a task.
228 fake_timer
->AdvanceToScheduledTime();
229 EXPECT_FALSE(fake_timer
->IsRunning());
230 EXPECT_TRUE(fake_runner
.HasRunningTask());
232 fake_runner
.CompleteTask(SYNC_STATUS_OK
);
233 EXPECT_TRUE(fake_timer
->IsRunning());
234 EXPECT_TRUE(fake_runner
.HasRunningTask());
235 fake_runner
.CompleteTask(SYNC_STATUS_OK
);
236 EXPECT_TRUE(fake_timer
->IsRunning());
237 EXPECT_FALSE(fake_runner
.HasRunningTask());
239 // Turn |service_state| to TEMPORARY_UNAVAILABLE and let the task fail.
240 // |fake_runner| should schedule following tasks with longer delay.
241 fake_timer
->AdvanceToScheduledTime();
242 fake_timer
->AdvanceToScheduledTime();
243 fake_client
.set_service_state(SYNC_SERVICE_TEMPORARY_UNAVAILABLE
);
244 fake_runner
.CompleteTask(SYNC_STATUS_FAILED
);
245 EXPECT_EQ(SyncProcessRunner::kSyncDelaySlowInMilliseconds
,
246 fake_timer
->GetCurrentDelay());
248 // Consecutive error reports shouldn't extend delay immediately.
249 fake_runner
.CompleteTask(SYNC_STATUS_FAILED
);
250 EXPECT_EQ(SyncProcessRunner::kSyncDelaySlowInMilliseconds
,
251 fake_timer
->GetCurrentDelay());
253 // The next task will run after throttle period is over.
254 // And its failure should extend the throttle period by twice.
255 fake_timer
->AdvanceToScheduledTime();
256 EXPECT_EQ(SyncProcessRunner::kSyncDelaySlowInMilliseconds
,
257 fake_timer
->GetCurrentDelay());
258 fake_runner
.CompleteTask(SYNC_STATUS_FAILED
);
259 EXPECT_EQ(2 * SyncProcessRunner::kSyncDelaySlowInMilliseconds
,
260 fake_timer
->GetCurrentDelay());
262 // Next successful task should clear the throttling.
263 fake_timer
->AdvanceToScheduledTime();
264 fake_client
.set_service_state(SYNC_SERVICE_RUNNING
);
265 fake_runner
.CompleteTask(SYNC_STATUS_OK
);
266 EXPECT_EQ(SyncProcessRunner::kSyncDelayFastInMilliseconds
,
267 fake_timer
->GetCurrentDelay());
269 // Then, following failing task should not extend throttling period.
270 fake_timer
->AdvanceToScheduledTime();
271 fake_client
.set_service_state(SYNC_SERVICE_TEMPORARY_UNAVAILABLE
);
272 fake_runner
.CompleteTask(SYNC_STATUS_FAILED
);
273 EXPECT_EQ(SyncProcessRunner::kSyncDelaySlowInMilliseconds
,
274 fake_timer
->GetCurrentDelay());
277 } // namespace sync_file_system