sync_task_manager_unittest.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <deque>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/bind.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/memory/weak_ptr.h"
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/message_loop/message_loop.h"
12c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include "base/run_loop.h"
13c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include "chrome/browser/sync_file_system/drive_backend/sync_task.h"
14c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include "chrome/browser/sync_file_system/drive_backend/sync_task_manager.h"
15c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include "chrome/browser/sync_file_system/drive_backend/sync_task_token.h"
16c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
17c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include "testing/gtest/include/gtest/gtest.h"
18c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include "webkit/common/fileapi/file_system_util.h"
19c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#define MAKE_PATH(path)                                       \
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::FilePath(fileapi::VirtualPath::GetNormalizedFilePath( \
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::FilePath(FILE_PATH_LITERAL(path))))
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace sync_file_system {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace drive_backend {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DumbTask(SyncStatusCode status,
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              const SyncStatusCallback& callback) {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::MessageLoop::current()->PostTask(
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE, base::Bind(callback, status));
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void IncrementAndAssign(int expected_before_counter,
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        int* counter,
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        SyncStatusCode* status_out,
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        SyncStatusCode status) {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(expected_before_counter, *counter);
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ++(*counter);
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *status_out = status;
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)template <typename T>
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void IncrementAndAssignWithOwnedPointer(T* object,
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                        int* counter,
47c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                                        SyncStatusCode* status_out,
48c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                                        SyncStatusCode status) {
49c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  ++(*counter);
50c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  *status_out = status;
51c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
52c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
53c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochclass TaskManagerClient
54c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    : public SyncTaskManager::Client,
55c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      public base::SupportsWeakPtr<TaskManagerClient> {
56c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch public:
57c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  explicit TaskManagerClient(int64 maximum_background_task)
58c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      : maybe_schedule_next_task_count_(0),
59c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch        task_scheduled_count_(0),
60c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch        idle_task_scheduled_count_(0),
61c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch        last_operation_status_(SYNC_STATUS_OK) {
62c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    task_manager_.reset(new SyncTaskManager(
63c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch        AsWeakPtr(), maximum_background_task,
64c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch        base::MessageLoopProxy::current()));
65c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    task_manager_->Initialize(SYNC_STATUS_OK);
66c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    base::MessageLoop::current()->RunUntilIdle();
67c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    maybe_schedule_next_task_count_ = 0;
68c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
69c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  virtual ~TaskManagerClient() {}
70c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
71c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // DriveFileSyncManager::Client overrides.
72c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  virtual void MaybeScheduleNextTask() OVERRIDE {
73c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    ++maybe_schedule_next_task_count_;
74c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
75c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  virtual void NotifyLastOperationStatus(
76c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      SyncStatusCode last_operation_status,
77c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      bool last_operation_used_network) OVERRIDE {
78c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    last_operation_status_ = last_operation_status;
79c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
80c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
81c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  virtual void RecordTaskLog(scoped_ptr<TaskLogger::TaskLog>) OVERRIDE {}
82c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
83c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void ScheduleTask(SyncStatusCode status_to_return,
84c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                    const SyncStatusCallback& callback) {
85c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    task_manager_->ScheduleTask(
86c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch        FROM_HERE,
87c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch        base::Bind(&TaskManagerClient::DoTask, AsWeakPtr(),
88c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                   status_to_return, false /* idle */),
89c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch        SyncTaskManager::PRIORITY_MED,
90c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch        callback);
91c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
92c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
93c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void ScheduleTaskIfIdle(SyncStatusCode status_to_return) {
94c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    task_manager_->ScheduleTaskIfIdle(
95c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch        FROM_HERE,
96c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch        base::Bind(&TaskManagerClient::DoTask, AsWeakPtr(),
97c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                   status_to_return, true /* idle */),
98c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch        SyncStatusCallback());
99c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
100c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
101c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  int maybe_schedule_next_task_count() const {
102c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    return maybe_schedule_next_task_count_;
103c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
104c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  int task_scheduled_count() const { return task_scheduled_count_; }
105c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  int idle_task_scheduled_count() const { return idle_task_scheduled_count_; }
106c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  SyncStatusCode last_operation_status() const {
107c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    return last_operation_status_;
108c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
109c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
110c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch private:
111c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void DoTask(SyncStatusCode status_to_return,
112c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch              bool is_idle_task,
113c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch              const SyncStatusCallback& callback) {
114c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    ++task_scheduled_count_;
115c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    if (is_idle_task)
116c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      ++idle_task_scheduled_count_;
117c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    base::MessageLoop::current()->PostTask(
118c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch        FROM_HERE, base::Bind(callback, status_to_return));
119c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
120c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
121c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  scoped_ptr<SyncTaskManager> task_manager_;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int maybe_schedule_next_task_count_;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int task_scheduled_count_;
125  int idle_task_scheduled_count_;
126
127  SyncStatusCode last_operation_status_;
128
129  DISALLOW_COPY_AND_ASSIGN(TaskManagerClient);
130};
131
132class MultihopSyncTask : public ExclusiveTask {
133 public:
134  MultihopSyncTask(bool* task_started,
135                   bool* task_completed)
136      : task_started_(task_started),
137        task_completed_(task_completed),
138        weak_ptr_factory_(this) {
139    DCHECK(task_started_);
140    DCHECK(task_completed_);
141  }
142
143  virtual ~MultihopSyncTask() {}
144
145  virtual void RunExclusive(const SyncStatusCallback& callback) OVERRIDE {
146    DCHECK(!*task_started_);
147    *task_started_ = true;
148    base::MessageLoop::current()->PostTask(
149        FROM_HERE, base::Bind(&MultihopSyncTask::CompleteTask,
150                              weak_ptr_factory_.GetWeakPtr(), callback));
151  }
152
153 private:
154  void CompleteTask(const SyncStatusCallback& callback) {
155    DCHECK(*task_started_);
156    DCHECK(!*task_completed_);
157    *task_completed_ = true;
158    callback.Run(SYNC_STATUS_OK);
159  }
160
161  bool* task_started_;
162  bool* task_completed_;
163  base::WeakPtrFactory<MultihopSyncTask> weak_ptr_factory_;
164
165  DISALLOW_COPY_AND_ASSIGN(MultihopSyncTask);
166};
167
168class BackgroundTask : public SyncTask {
169 public:
170  struct Stats {
171    int64 running_background_task;
172    int64 finished_task;
173    int64 max_parallel_task;
174
175    Stats()
176        : running_background_task(0),
177          finished_task(0),
178          max_parallel_task(0) {}
179  };
180
181  BackgroundTask(const std::string& app_id,
182                 const base::FilePath& path,
183                 Stats* stats)
184      : app_id_(app_id),
185        path_(path),
186        stats_(stats),
187        weak_ptr_factory_(this) {
188  }
189
190  virtual ~BackgroundTask() {
191  }
192
193  virtual void RunPreflight(scoped_ptr<SyncTaskToken> token) OVERRIDE {
194    scoped_ptr<BlockingFactor> blocking_factor(new BlockingFactor);
195    blocking_factor->app_id = app_id_;
196    blocking_factor->paths.push_back(path_);
197
198    SyncTaskManager::UpdateBlockingFactor(
199        token.Pass(), blocking_factor.Pass(),
200        base::Bind(&BackgroundTask::RunAsBackgroundTask,
201                   weak_ptr_factory_.GetWeakPtr()));
202  }
203
204 private:
205  void RunAsBackgroundTask(scoped_ptr<SyncTaskToken> token) {
206    ++(stats_->running_background_task);
207    if (stats_->max_parallel_task < stats_->running_background_task)
208      stats_->max_parallel_task = stats_->running_background_task;
209
210    base::MessageLoop::current()->PostTask(
211        FROM_HERE,
212        base::Bind(&BackgroundTask::CompleteTask,
213                   weak_ptr_factory_.GetWeakPtr(),
214                   base::Passed(&token)));
215  }
216
217  void CompleteTask(scoped_ptr<SyncTaskToken> token) {
218    ++(stats_->finished_task);
219    --(stats_->running_background_task);
220    SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_OK);
221  }
222
223  std::string app_id_;
224  base::FilePath path_;
225  Stats* stats_;
226
227  base::WeakPtrFactory<BackgroundTask> weak_ptr_factory_;
228
229  DISALLOW_COPY_AND_ASSIGN(BackgroundTask);
230};
231
232class BlockerUpdateTestHelper : public SyncTask {
233 public:
234  typedef std::vector<std::string> Log;
235
236  BlockerUpdateTestHelper(const std::string& name,
237                          const std::string& app_id,
238                          const std::vector<std::string>& paths,
239                          Log* log)
240      : name_(name),
241        app_id_(app_id),
242        paths_(paths.begin(), paths.end()),
243        log_(log),
244        weak_ptr_factory_(this) {
245  }
246
247  virtual ~BlockerUpdateTestHelper() {
248  }
249
250  virtual void RunPreflight(scoped_ptr<SyncTaskToken> token) OVERRIDE {
251    UpdateBlocker(token.Pass());
252  }
253
254 private:
255  void UpdateBlocker(scoped_ptr<SyncTaskToken> token) {
256    if (paths_.empty()) {
257      log_->push_back(name_ + ": finished");
258      SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_OK);
259      return;
260    }
261
262    std::string updating_to = paths_.front();
263    paths_.pop_front();
264
265    log_->push_back(name_ + ": updating to " + updating_to);
266
267    scoped_ptr<BlockingFactor> blocking_factor(new BlockingFactor);
268    blocking_factor->app_id = app_id_;
269    blocking_factor->paths.push_back(
270        base::FilePath(fileapi::VirtualPath::GetNormalizedFilePath(
271            base::FilePath::FromUTF8Unsafe(updating_to))));
272
273    SyncTaskManager::UpdateBlockingFactor(
274        token.Pass(), blocking_factor.Pass(),
275        base::Bind(&BlockerUpdateTestHelper::UpdateBlockerSoon,
276                   weak_ptr_factory_.GetWeakPtr(),
277                   updating_to));
278  }
279
280  void UpdateBlockerSoon(const std::string& updated_to,
281                         scoped_ptr<SyncTaskToken> token) {
282    log_->push_back(name_ + ": updated to " + updated_to);
283    base::MessageLoop::current()->PostTask(
284        FROM_HERE,
285        base::Bind(&BlockerUpdateTestHelper::UpdateBlocker,
286                   weak_ptr_factory_.GetWeakPtr(), base::Passed(&token)));
287  }
288
289  std::string name_;
290  std::string app_id_;
291  std::deque<std::string> paths_;
292  Log* log_;
293
294  base::WeakPtrFactory<BlockerUpdateTestHelper> weak_ptr_factory_;
295
296  DISALLOW_COPY_AND_ASSIGN(BlockerUpdateTestHelper);
297};
298
299// Arbitrary non-default status values for testing.
300const SyncStatusCode kStatus1 = static_cast<SyncStatusCode>(-1);
301const SyncStatusCode kStatus2 = static_cast<SyncStatusCode>(-2);
302const SyncStatusCode kStatus3 = static_cast<SyncStatusCode>(-3);
303const SyncStatusCode kStatus4 = static_cast<SyncStatusCode>(-4);
304const SyncStatusCode kStatus5 = static_cast<SyncStatusCode>(-5);
305
306}  // namespace
307
308TEST(SyncTaskManagerTest, ScheduleTask) {
309  base::MessageLoop message_loop;
310  TaskManagerClient client(0 /* maximum_background_task */);
311  int callback_count = 0;
312  SyncStatusCode callback_status = SYNC_STATUS_OK;
313
314  client.ScheduleTask(kStatus1, base::Bind(&IncrementAndAssign, 0,
315                                           &callback_count,
316                                           &callback_status));
317  message_loop.RunUntilIdle();
318
319  EXPECT_EQ(kStatus1, callback_status);
320  EXPECT_EQ(kStatus1, client.last_operation_status());
321
322  EXPECT_EQ(1, callback_count);
323  EXPECT_EQ(1, client.maybe_schedule_next_task_count());
324  EXPECT_EQ(1, client.task_scheduled_count());
325  EXPECT_EQ(0, client.idle_task_scheduled_count());
326}
327
328TEST(SyncTaskManagerTest, ScheduleTwoTasks) {
329  base::MessageLoop message_loop;
330  TaskManagerClient client(0 /* maximum_background_task */);
331  int callback_count = 0;
332  SyncStatusCode callback_status = SYNC_STATUS_OK;
333
334  client.ScheduleTask(kStatus1, base::Bind(&IncrementAndAssign, 0,
335                                           &callback_count,
336                                           &callback_status));
337  client.ScheduleTask(kStatus2, base::Bind(&IncrementAndAssign, 1,
338                                           &callback_count,
339                                           &callback_status));
340  message_loop.RunUntilIdle();
341
342  EXPECT_EQ(kStatus2, callback_status);
343  EXPECT_EQ(kStatus2, client.last_operation_status());
344
345  EXPECT_EQ(2, callback_count);
346  EXPECT_EQ(1, client.maybe_schedule_next_task_count());
347  EXPECT_EQ(2, client.task_scheduled_count());
348  EXPECT_EQ(0, client.idle_task_scheduled_count());
349}
350
351TEST(SyncTaskManagerTest, ScheduleIdleTask) {
352  base::MessageLoop message_loop;
353  TaskManagerClient client(0 /* maximum_background_task */);
354
355  client.ScheduleTaskIfIdle(kStatus1);
356  message_loop.RunUntilIdle();
357
358  EXPECT_EQ(kStatus1, client.last_operation_status());
359
360  EXPECT_EQ(1, client.maybe_schedule_next_task_count());
361  EXPECT_EQ(1, client.task_scheduled_count());
362  EXPECT_EQ(1, client.idle_task_scheduled_count());
363}
364
365TEST(SyncTaskManagerTest, ScheduleIdleTaskWhileNotIdle) {
366  base::MessageLoop message_loop;
367  TaskManagerClient client(0 /* maximum_background_task */);
368  int callback_count = 0;
369  SyncStatusCode callback_status = SYNC_STATUS_OK;
370
371  client.ScheduleTask(kStatus1, base::Bind(&IncrementAndAssign, 0,
372                                           &callback_count,
373                                           &callback_status));
374  client.ScheduleTaskIfIdle(kStatus2);
375  message_loop.RunUntilIdle();
376
377  // Idle task must not have run.
378  EXPECT_EQ(kStatus1, callback_status);
379  EXPECT_EQ(kStatus1, client.last_operation_status());
380
381  EXPECT_EQ(1, callback_count);
382  EXPECT_EQ(1, client.maybe_schedule_next_task_count());
383  EXPECT_EQ(1, client.task_scheduled_count());
384  EXPECT_EQ(0, client.idle_task_scheduled_count());
385}
386
387TEST(SyncTaskManagerTest, ScheduleAndCancelSyncTask) {
388  base::MessageLoop message_loop;
389
390  int callback_count = 0;
391  SyncStatusCode status = SYNC_STATUS_UNKNOWN;
392
393  bool task_started = false;
394  bool task_completed = false;
395
396  {
397    SyncTaskManager task_manager(base::WeakPtr<SyncTaskManager::Client>(),
398                                 0 /* maximum_background_task */,
399                                 base::MessageLoopProxy::current());
400    task_manager.Initialize(SYNC_STATUS_OK);
401    message_loop.RunUntilIdle();
402    task_manager.ScheduleSyncTask(
403        FROM_HERE,
404        scoped_ptr<SyncTask>(new MultihopSyncTask(
405            &task_started, &task_completed)),
406        SyncTaskManager::PRIORITY_MED,
407        base::Bind(&IncrementAndAssign, 0, &callback_count, &status));
408  }
409  message_loop.RunUntilIdle();
410
411  EXPECT_EQ(0, callback_count);
412  EXPECT_EQ(SYNC_STATUS_UNKNOWN, status);
413  EXPECT_TRUE(task_started);
414  EXPECT_FALSE(task_completed);
415}
416
417TEST(SyncTaskManagerTest, ScheduleTaskAtPriority) {
418  base::MessageLoop message_loop;
419  SyncTaskManager task_manager(base::WeakPtr<SyncTaskManager::Client>(),
420                               0 /* maximum_background_task */,
421                               base::MessageLoopProxy::current());
422  task_manager.Initialize(SYNC_STATUS_OK);
423  message_loop.RunUntilIdle();
424
425  int callback_count = 0;
426  SyncStatusCode callback_status1 = SYNC_STATUS_OK;
427  SyncStatusCode callback_status2 = SYNC_STATUS_OK;
428  SyncStatusCode callback_status3 = SYNC_STATUS_OK;
429  SyncStatusCode callback_status4 = SYNC_STATUS_OK;
430  SyncStatusCode callback_status5 = SYNC_STATUS_OK;
431
432  // This will run first even if its priority is low, since there're no
433  // pending tasks.
434  task_manager.ScheduleTask(
435      FROM_HERE,
436      base::Bind(&DumbTask, kStatus1),
437      SyncTaskManager::PRIORITY_LOW,
438      base::Bind(&IncrementAndAssign, 0, &callback_count, &callback_status1));
439
440  // This runs last (expected counter == 4).
441  task_manager.ScheduleTask(
442      FROM_HERE,
443      base::Bind(&DumbTask, kStatus2),
444      SyncTaskManager::PRIORITY_LOW,
445      base::Bind(&IncrementAndAssign, 4, &callback_count, &callback_status2));
446
447  // This runs second (expected counter == 1).
448  task_manager.ScheduleTask(
449      FROM_HERE,
450      base::Bind(&DumbTask, kStatus3),
451      SyncTaskManager::PRIORITY_HIGH,
452      base::Bind(&IncrementAndAssign, 1, &callback_count, &callback_status3));
453
454  // This runs fourth (expected counter == 3).
455  task_manager.ScheduleTask(
456      FROM_HERE,
457      base::Bind(&DumbTask, kStatus4),
458      SyncTaskManager::PRIORITY_MED,
459      base::Bind(&IncrementAndAssign, 3, &callback_count, &callback_status4));
460
461  // This runs third (expected counter == 2).
462  task_manager.ScheduleTask(
463      FROM_HERE,
464      base::Bind(&DumbTask, kStatus5),
465      SyncTaskManager::PRIORITY_HIGH,
466      base::Bind(&IncrementAndAssign, 2, &callback_count, &callback_status5));
467
468  message_loop.RunUntilIdle();
469
470  EXPECT_EQ(kStatus1, callback_status1);
471  EXPECT_EQ(kStatus2, callback_status2);
472  EXPECT_EQ(kStatus3, callback_status3);
473  EXPECT_EQ(kStatus4, callback_status4);
474  EXPECT_EQ(kStatus5, callback_status5);
475  EXPECT_EQ(5, callback_count);
476}
477
478TEST(SyncTaskManagerTest, BackgroundTask_Sequential) {
479  base::MessageLoop message_loop;
480  SyncTaskManager task_manager(base::WeakPtr<SyncTaskManager::Client>(),
481                               10 /* maximum_background_task */,
482                               base::MessageLoopProxy::current());
483  task_manager.Initialize(SYNC_STATUS_OK);
484
485  SyncStatusCode status = SYNC_STATUS_FAILED;
486  BackgroundTask::Stats stats;
487  task_manager.ScheduleSyncTask(
488      FROM_HERE,
489      scoped_ptr<SyncTask>(new BackgroundTask(
490          "app_id", MAKE_PATH("/hoge/fuga"),
491          &stats)),
492      SyncTaskManager::PRIORITY_MED,
493      CreateResultReceiver(&status));
494
495  task_manager.ScheduleSyncTask(
496      FROM_HERE,
497      scoped_ptr<SyncTask>(new BackgroundTask(
498          "app_id", MAKE_PATH("/hoge"),
499          &stats)),
500      SyncTaskManager::PRIORITY_MED,
501      CreateResultReceiver(&status));
502
503  task_manager.ScheduleSyncTask(
504      FROM_HERE,
505      scoped_ptr<SyncTask>(new BackgroundTask(
506          "app_id", MAKE_PATH("/hoge/fuga/piyo"),
507          &stats)),
508      SyncTaskManager::PRIORITY_MED,
509      CreateResultReceiver(&status));
510
511  message_loop.RunUntilIdle();
512
513  EXPECT_EQ(SYNC_STATUS_OK, status);
514  EXPECT_EQ(0, stats.running_background_task);
515  EXPECT_EQ(3, stats.finished_task);
516  EXPECT_EQ(1, stats.max_parallel_task);
517}
518
519TEST(SyncTaskManagerTest, BackgroundTask_Parallel) {
520  base::MessageLoop message_loop;
521  SyncTaskManager task_manager(base::WeakPtr<SyncTaskManager::Client>(),
522                               10 /* maximum_background_task */,
523                               base::MessageLoopProxy::current());
524  task_manager.Initialize(SYNC_STATUS_OK);
525
526  SyncStatusCode status = SYNC_STATUS_FAILED;
527  BackgroundTask::Stats stats;
528  task_manager.ScheduleSyncTask(
529      FROM_HERE,
530      scoped_ptr<SyncTask>(new BackgroundTask(
531          "app_id", MAKE_PATH("/hoge"),
532          &stats)),
533      SyncTaskManager::PRIORITY_MED,
534      CreateResultReceiver(&status));
535
536  task_manager.ScheduleSyncTask(
537      FROM_HERE,
538      scoped_ptr<SyncTask>(new BackgroundTask(
539          "app_id", MAKE_PATH("/fuga"),
540          &stats)),
541      SyncTaskManager::PRIORITY_MED,
542      CreateResultReceiver(&status));
543
544  task_manager.ScheduleSyncTask(
545      FROM_HERE,
546      scoped_ptr<SyncTask>(new BackgroundTask(
547          "app_id", MAKE_PATH("/piyo"),
548          &stats)),
549      SyncTaskManager::PRIORITY_MED,
550      CreateResultReceiver(&status));
551
552  message_loop.RunUntilIdle();
553
554  EXPECT_EQ(SYNC_STATUS_OK, status);
555  EXPECT_EQ(0, stats.running_background_task);
556  EXPECT_EQ(3, stats.finished_task);
557  EXPECT_EQ(3, stats.max_parallel_task);
558}
559
560TEST(SyncTaskManagerTest, BackgroundTask_Throttled) {
561  base::MessageLoop message_loop;
562  SyncTaskManager task_manager(base::WeakPtr<SyncTaskManager::Client>(),
563                               2 /* maximum_background_task */,
564                               base::MessageLoopProxy::current());
565  task_manager.Initialize(SYNC_STATUS_OK);
566
567  SyncStatusCode status = SYNC_STATUS_FAILED;
568  BackgroundTask::Stats stats;
569  task_manager.ScheduleSyncTask(
570      FROM_HERE,
571      scoped_ptr<SyncTask>(new BackgroundTask(
572          "app_id", MAKE_PATH("/hoge"),
573          &stats)),
574      SyncTaskManager::PRIORITY_MED,
575      CreateResultReceiver(&status));
576
577  task_manager.ScheduleSyncTask(
578      FROM_HERE,
579      scoped_ptr<SyncTask>(new BackgroundTask(
580          "app_id", MAKE_PATH("/fuga"),
581          &stats)),
582      SyncTaskManager::PRIORITY_MED,
583      CreateResultReceiver(&status));
584
585  task_manager.ScheduleSyncTask(
586      FROM_HERE,
587      scoped_ptr<SyncTask>(new BackgroundTask(
588          "app_id", MAKE_PATH("/piyo"),
589          &stats)),
590      SyncTaskManager::PRIORITY_MED,
591      CreateResultReceiver(&status));
592
593  message_loop.RunUntilIdle();
594
595  EXPECT_EQ(SYNC_STATUS_OK, status);
596  EXPECT_EQ(0, stats.running_background_task);
597  EXPECT_EQ(3, stats.finished_task);
598  EXPECT_EQ(2, stats.max_parallel_task);
599}
600
601TEST(SyncTaskManagerTest, UpdateBlockingFactor) {
602  base::MessageLoop message_loop;
603  SyncTaskManager task_manager(base::WeakPtr<SyncTaskManager::Client>(),
604                               10 /* maximum_background_task */,
605                               base::MessageLoopProxy::current());
606  task_manager.Initialize(SYNC_STATUS_OK);
607
608  SyncStatusCode status1 = SYNC_STATUS_FAILED;
609  SyncStatusCode status2 = SYNC_STATUS_FAILED;
610  BlockerUpdateTestHelper::Log log;
611
612  {
613    std::vector<std::string> paths;
614    paths.push_back("/foo/bar");
615    paths.push_back("/foo");
616    paths.push_back("/hoge/fuga/piyo");
617    task_manager.ScheduleSyncTask(
618        FROM_HERE,
619        scoped_ptr<SyncTask>(new BlockerUpdateTestHelper(
620            "task1", "app_id", paths, &log)),
621        SyncTaskManager::PRIORITY_MED,
622        CreateResultReceiver(&status1));
623  }
624
625  {
626    std::vector<std::string> paths;
627    paths.push_back("/foo");
628    paths.push_back("/foo/bar");
629    paths.push_back("/hoge/fuga/piyo");
630    task_manager.ScheduleSyncTask(
631        FROM_HERE,
632        scoped_ptr<SyncTask>(new BlockerUpdateTestHelper(
633            "task2", "app_id", paths, &log)),
634        SyncTaskManager::PRIORITY_MED,
635        CreateResultReceiver(&status2));
636  }
637
638  message_loop.RunUntilIdle();
639
640  EXPECT_EQ(SYNC_STATUS_OK, status1);
641  EXPECT_EQ(SYNC_STATUS_OK, status2);
642
643  ASSERT_EQ(14u, log.size());
644  int i = 0;
645
646  // task1 takes "/foo/bar" first.
647  EXPECT_EQ("task1: updating to /foo/bar", log[i++]);
648
649  // task1 blocks task2. task2's update should not complete until task1 update.
650  EXPECT_EQ("task2: updating to /foo", log[i++]);
651  EXPECT_EQ("task1: updated to /foo/bar", log[i++]);
652
653  // task1 releases "/foo/bar" and tries to take "/foo". Then, pending task2
654  // takes "/foo" and blocks task1.
655  EXPECT_EQ("task1: updating to /foo", log[i++]);
656  EXPECT_EQ("task2: updated to /foo", log[i++]);
657
658  // task2 releases "/foo".
659  EXPECT_EQ("task2: updating to /foo/bar", log[i++]);
660  EXPECT_EQ("task1: updated to /foo", log[i++]);
661
662  // task1 releases "/foo".
663  EXPECT_EQ("task1: updating to /hoge/fuga/piyo", log[i++]);
664  EXPECT_EQ("task1: updated to /hoge/fuga/piyo", log[i++]);
665  EXPECT_EQ("task2: updated to /foo/bar", log[i++]);
666
667  EXPECT_EQ("task1: finished", log[i++]);
668
669  EXPECT_EQ("task2: updating to /hoge/fuga/piyo", log[i++]);
670  EXPECT_EQ("task2: updated to /hoge/fuga/piyo", log[i++]);
671  EXPECT_EQ("task2: finished", log[i++]);
672}
673
674}  // namespace drive_backend
675}  // namespace sync_file_system
676