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