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