Home | History | Annotate | Download | only in drive_backend
      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 "storage/common/fileapi/file_system_util.h"
     19 #include "testing/gtest/include/gtest/gtest.h"
     20 
     21 #define MAKE_PATH(path)                                       \
     22   base::FilePath(storage::VirtualPath::GetNormalizedFilePath( \
     23       base::FilePath(FILE_PATH_LITERAL(path))))
     24 
     25 namespace sync_file_system {
     26 namespace drive_backend {
     27 
     28 namespace {
     29 
     30 void DumbTask(SyncStatusCode status,
     31               const SyncStatusCallback& callback) {
     32   base::MessageLoop::current()->PostTask(
     33       FROM_HERE, base::Bind(callback, status));
     34 }
     35 
     36 void 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 
     45 template <typename T>
     46 void IncrementAndAssignWithOwnedPointer(T* object,
     47                                         int* counter,
     48                                         SyncStatusCode* status_out,
     49                                         SyncStatusCode status) {
     50   ++(*counter);
     51   *status_out = status;
     52 }
     53 
     54 class 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 
    133 class 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 
    169 class 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<TaskBlocker> task_blocker(new TaskBlocker);
    196     task_blocker->app_id = app_id_;
    197     task_blocker->paths.push_back(path_);
    198 
    199     SyncTaskManager::UpdateTaskBlocker(
    200         token.Pass(), task_blocker.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 
    233 class 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<TaskBlocker> task_blocker(new TaskBlocker);
    269     task_blocker->app_id = app_id_;
    270     task_blocker->paths.push_back(
    271         base::FilePath(storage::VirtualPath::GetNormalizedFilePath(
    272             base::FilePath::FromUTF8Unsafe(updating_to))));
    273 
    274     SyncTaskManager::UpdateTaskBlocker(
    275         token.Pass(), task_blocker.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.
    301 const SyncStatusCode kStatus1 = static_cast<SyncStatusCode>(-1);
    302 const SyncStatusCode kStatus2 = static_cast<SyncStatusCode>(-2);
    303 const SyncStatusCode kStatus3 = static_cast<SyncStatusCode>(-3);
    304 const SyncStatusCode kStatus4 = static_cast<SyncStatusCode>(-4);
    305 const SyncStatusCode kStatus5 = static_cast<SyncStatusCode>(-5);
    306 
    307 }  // namespace
    308 
    309 TEST(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 
    329 TEST(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 
    352 TEST(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 
    366 TEST(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 
    388 TEST(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 
    418 TEST(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 
    479 TEST(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 
    520 TEST(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 
    561 TEST(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 
    602 TEST(SyncTaskManagerTest, UpdateTaskBlocker) {
    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