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