sync_task_manager_unittest.cc revision effb81e5f8246d0db0270817048dc992db66e9fb
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 "base/basictypes.h" 6#include "base/bind.h" 7#include "base/memory/weak_ptr.h" 8#include "base/message_loop/message_loop.h" 9#include "chrome/browser/sync_file_system/drive_backend/sync_task_manager.h" 10#include "chrome/browser/sync_file_system/drive_backend/sync_task_token.h" 11#include "chrome/browser/sync_file_system/sync_file_system_test_util.h" 12#include "testing/gtest/include/gtest/gtest.h" 13#include "webkit/common/fileapi/file_system_util.h" 14 15#define MAKE_PATH(path) \ 16 base::FilePath(fileapi::VirtualPath::GetNormalizedFilePath( \ 17 base::FilePath(FILE_PATH_LITERAL(path)))) 18 19namespace sync_file_system { 20namespace drive_backend { 21 22namespace { 23 24void DumbTask(SyncStatusCode status, 25 const SyncStatusCallback& callback) { 26 base::MessageLoop::current()->PostTask( 27 FROM_HERE, base::Bind(callback, status)); 28} 29 30void IncrementAndAssign(int expected_before_counter, 31 int* counter, 32 SyncStatusCode* status_out, 33 SyncStatusCode status) { 34 EXPECT_EQ(expected_before_counter, *counter); 35 ++(*counter); 36 *status_out = status; 37} 38 39template <typename T> 40void IncrementAndAssignWithOwnedPointer(T* object, 41 int* counter, 42 SyncStatusCode* status_out, 43 SyncStatusCode status) { 44 ++(*counter); 45 *status_out = status; 46} 47 48class TaskManagerClient 49 : public SyncTaskManager::Client, 50 public base::SupportsWeakPtr<TaskManagerClient> { 51 public: 52 explicit TaskManagerClient(int64 maximum_background_task) 53 : maybe_schedule_next_task_count_(0), 54 task_scheduled_count_(0), 55 idle_task_scheduled_count_(0), 56 last_operation_status_(SYNC_STATUS_OK) { 57 task_manager_.reset(new SyncTaskManager( 58 AsWeakPtr(), maximum_background_task)); 59 task_manager_->Initialize(SYNC_STATUS_OK); 60 maybe_schedule_next_task_count_ = 0; 61 } 62 virtual ~TaskManagerClient() {} 63 64 // DriveFileSyncManager::Client overrides. 65 virtual void MaybeScheduleNextTask() OVERRIDE { 66 ++maybe_schedule_next_task_count_; 67 } 68 virtual void NotifyLastOperationStatus( 69 SyncStatusCode last_operation_status, 70 bool last_operation_used_network) OVERRIDE { 71 last_operation_status_ = last_operation_status; 72 } 73 74 void ScheduleTask(SyncStatusCode status_to_return, 75 const SyncStatusCallback& callback) { 76 task_manager_->ScheduleTask( 77 FROM_HERE, 78 base::Bind(&TaskManagerClient::DoTask, AsWeakPtr(), 79 status_to_return, false /* idle */), 80 SyncTaskManager::PRIORITY_MED, 81 callback); 82 } 83 84 void ScheduleTaskIfIdle(SyncStatusCode status_to_return) { 85 task_manager_->ScheduleTaskIfIdle( 86 FROM_HERE, 87 base::Bind(&TaskManagerClient::DoTask, AsWeakPtr(), 88 status_to_return, true /* idle */), 89 SyncStatusCallback()); 90 } 91 92 int maybe_schedule_next_task_count() const { 93 return maybe_schedule_next_task_count_; 94 } 95 int task_scheduled_count() const { return task_scheduled_count_; } 96 int idle_task_scheduled_count() const { return idle_task_scheduled_count_; } 97 SyncStatusCode last_operation_status() const { 98 return last_operation_status_; 99 } 100 101 private: 102 void DoTask(SyncStatusCode status_to_return, 103 bool is_idle_task, 104 const SyncStatusCallback& callback) { 105 ++task_scheduled_count_; 106 if (is_idle_task) 107 ++idle_task_scheduled_count_; 108 base::MessageLoop::current()->PostTask( 109 FROM_HERE, base::Bind(callback, status_to_return)); 110 } 111 112 scoped_ptr<SyncTaskManager> task_manager_; 113 114 int maybe_schedule_next_task_count_; 115 int task_scheduled_count_; 116 int idle_task_scheduled_count_; 117 118 SyncStatusCode last_operation_status_; 119 120 DISALLOW_COPY_AND_ASSIGN(TaskManagerClient); 121}; 122 123class MultihopSyncTask : public SequentialSyncTask { 124 public: 125 MultihopSyncTask(bool* task_started, 126 bool* task_completed) 127 : task_started_(task_started), 128 task_completed_(task_completed), 129 weak_ptr_factory_(this) { 130 DCHECK(task_started_); 131 DCHECK(task_completed_); 132 } 133 134 virtual ~MultihopSyncTask() {} 135 136 virtual void RunSequential(const SyncStatusCallback& callback) OVERRIDE { 137 DCHECK(!*task_started_); 138 *task_started_ = true; 139 base::MessageLoop::current()->PostTask( 140 FROM_HERE, base::Bind(&MultihopSyncTask::CompleteTask, 141 weak_ptr_factory_.GetWeakPtr(), callback)); 142 } 143 144 private: 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_; 155 156 DISALLOW_COPY_AND_ASSIGN(MultihopSyncTask); 157}; 158 159class BackgroundTask : public SyncTask { 160 public: 161 struct Stats { 162 int64 running_background_task; 163 int64 finished_task; 164 int64 max_parallel_task; 165 166 Stats() 167 : running_background_task(0), 168 finished_task(0), 169 max_parallel_task(0) {} 170 }; 171 172 BackgroundTask(const std::string& app_id, 173 const base::FilePath& path, 174 Stats* stats) 175 : app_id_(app_id), 176 path_(path), 177 stats_(stats), 178 weak_ptr_factory_(this) { 179 } 180 181 virtual ~BackgroundTask() { 182 } 183 184 virtual void Run(scoped_ptr<SyncTaskToken> token) OVERRIDE { 185 scoped_ptr<BlockingFactor> blocking_factor(new BlockingFactor); 186 blocking_factor->app_id = app_id_; 187 blocking_factor->paths.push_back(path_); 188 189 SyncTaskManager::MoveTaskToBackground( 190 token.Pass(), blocking_factor.Pass(), 191 base::Bind(&BackgroundTask::RunAsBackgroundTask, 192 weak_ptr_factory_.GetWeakPtr())); 193 } 194 195 private: 196 void RunAsBackgroundTask(scoped_ptr<SyncTaskToken> token) { 197 ++(stats_->running_background_task); 198 if (stats_->max_parallel_task < stats_->running_background_task) 199 stats_->max_parallel_task = stats_->running_background_task; 200 201 base::MessageLoop::current()->PostTask( 202 FROM_HERE, 203 base::Bind(&BackgroundTask::CompleteTask, 204 weak_ptr_factory_.GetWeakPtr(), 205 base::Passed(&token))); 206 } 207 208 void CompleteTask(scoped_ptr<SyncTaskToken> token) { 209 ++(stats_->finished_task); 210 --(stats_->running_background_task); 211 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_OK); 212 } 213 214 std::string app_id_; 215 base::FilePath path_; 216 Stats* stats_; 217 218 base::WeakPtrFactory<BackgroundTask> weak_ptr_factory_; 219 220 DISALLOW_COPY_AND_ASSIGN(BackgroundTask); 221}; 222 223// Arbitrary non-default status values for testing. 224const SyncStatusCode kStatus1 = static_cast<SyncStatusCode>(-1); 225const SyncStatusCode kStatus2 = static_cast<SyncStatusCode>(-2); 226const SyncStatusCode kStatus3 = static_cast<SyncStatusCode>(-3); 227const SyncStatusCode kStatus4 = static_cast<SyncStatusCode>(-4); 228const SyncStatusCode kStatus5 = static_cast<SyncStatusCode>(-5); 229 230} // namespace 231 232TEST(SyncTaskManagerTest, ScheduleTask) { 233 base::MessageLoop message_loop; 234 TaskManagerClient client(0 /* maximum_background_task */); 235 int callback_count = 0; 236 SyncStatusCode callback_status = SYNC_STATUS_OK; 237 238 client.ScheduleTask(kStatus1, base::Bind(&IncrementAndAssign, 0, 239 &callback_count, 240 &callback_status)); 241 message_loop.RunUntilIdle(); 242 243 EXPECT_EQ(kStatus1, callback_status); 244 EXPECT_EQ(kStatus1, client.last_operation_status()); 245 246 EXPECT_EQ(1, callback_count); 247 EXPECT_EQ(1, client.maybe_schedule_next_task_count()); 248 EXPECT_EQ(1, client.task_scheduled_count()); 249 EXPECT_EQ(0, client.idle_task_scheduled_count()); 250} 251 252TEST(SyncTaskManagerTest, ScheduleTwoTasks) { 253 base::MessageLoop message_loop; 254 TaskManagerClient client(0 /* maximum_background_task */); 255 int callback_count = 0; 256 SyncStatusCode callback_status = SYNC_STATUS_OK; 257 258 client.ScheduleTask(kStatus1, base::Bind(&IncrementAndAssign, 0, 259 &callback_count, 260 &callback_status)); 261 client.ScheduleTask(kStatus2, base::Bind(&IncrementAndAssign, 1, 262 &callback_count, 263 &callback_status)); 264 message_loop.RunUntilIdle(); 265 266 EXPECT_EQ(kStatus2, callback_status); 267 EXPECT_EQ(kStatus2, client.last_operation_status()); 268 269 EXPECT_EQ(2, callback_count); 270 EXPECT_EQ(1, client.maybe_schedule_next_task_count()); 271 EXPECT_EQ(2, client.task_scheduled_count()); 272 EXPECT_EQ(0, client.idle_task_scheduled_count()); 273} 274 275TEST(SyncTaskManagerTest, ScheduleIdleTask) { 276 base::MessageLoop message_loop; 277 TaskManagerClient client(0 /* maximum_background_task */); 278 279 client.ScheduleTaskIfIdle(kStatus1); 280 message_loop.RunUntilIdle(); 281 282 EXPECT_EQ(kStatus1, client.last_operation_status()); 283 284 EXPECT_EQ(1, client.maybe_schedule_next_task_count()); 285 EXPECT_EQ(1, client.task_scheduled_count()); 286 EXPECT_EQ(1, client.idle_task_scheduled_count()); 287} 288 289TEST(SyncTaskManagerTest, ScheduleIdleTaskWhileNotIdle) { 290 base::MessageLoop message_loop; 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 client.ScheduleTaskIfIdle(kStatus2); 299 message_loop.RunUntilIdle(); 300 301 // Idle task must not have run. 302 EXPECT_EQ(kStatus1, callback_status); 303 EXPECT_EQ(kStatus1, client.last_operation_status()); 304 305 EXPECT_EQ(1, callback_count); 306 EXPECT_EQ(1, client.maybe_schedule_next_task_count()); 307 EXPECT_EQ(1, client.task_scheduled_count()); 308 EXPECT_EQ(0, client.idle_task_scheduled_count()); 309} 310 311TEST(SyncTaskManagerTest, ScheduleAndCancelSyncTask) { 312 base::MessageLoop message_loop; 313 314 int callback_count = 0; 315 SyncStatusCode status = SYNC_STATUS_UNKNOWN; 316 317 bool task_started = false; 318 bool task_completed = false; 319 320 { 321 SyncTaskManager task_manager(base::WeakPtr<SyncTaskManager::Client>(), 322 0 /* maximum_background_task */); 323 task_manager.Initialize(SYNC_STATUS_OK); 324 task_manager.ScheduleSyncTask( 325 FROM_HERE, 326 scoped_ptr<SyncTask>(new MultihopSyncTask( 327 &task_started, &task_completed)), 328 SyncTaskManager::PRIORITY_MED, 329 base::Bind(&IncrementAndAssign, 0, &callback_count, &status)); 330 } 331 332 message_loop.RunUntilIdle(); 333 EXPECT_EQ(0, callback_count); 334 EXPECT_EQ(SYNC_STATUS_UNKNOWN, status); 335 EXPECT_TRUE(task_started); 336 EXPECT_FALSE(task_completed); 337} 338 339TEST(SyncTaskManagerTest, ScheduleTaskAtPriority) { 340 base::MessageLoop message_loop; 341 SyncTaskManager task_manager(base::WeakPtr<SyncTaskManager::Client>(), 342 0 /* maximum_background_task */); 343 task_manager.Initialize(SYNC_STATUS_OK); 344 345 int callback_count = 0; 346 SyncStatusCode callback_status1 = SYNC_STATUS_OK; 347 SyncStatusCode callback_status2 = SYNC_STATUS_OK; 348 SyncStatusCode callback_status3 = SYNC_STATUS_OK; 349 SyncStatusCode callback_status4 = SYNC_STATUS_OK; 350 SyncStatusCode callback_status5 = SYNC_STATUS_OK; 351 352 // This will run first even if its priority is low, since there're no 353 // pending tasks. 354 task_manager.ScheduleTask( 355 FROM_HERE, 356 base::Bind(&DumbTask, kStatus1), 357 SyncTaskManager::PRIORITY_LOW, 358 base::Bind(&IncrementAndAssign, 0, &callback_count, &callback_status1)); 359 360 // This runs last (expected counter == 4). 361 task_manager.ScheduleTask( 362 FROM_HERE, 363 base::Bind(&DumbTask, kStatus2), 364 SyncTaskManager::PRIORITY_LOW, 365 base::Bind(&IncrementAndAssign, 4, &callback_count, &callback_status2)); 366 367 // This runs second (expected counter == 1). 368 task_manager.ScheduleTask( 369 FROM_HERE, 370 base::Bind(&DumbTask, kStatus3), 371 SyncTaskManager::PRIORITY_HIGH, 372 base::Bind(&IncrementAndAssign, 1, &callback_count, &callback_status3)); 373 374 // This runs fourth (expected counter == 3). 375 task_manager.ScheduleTask( 376 FROM_HERE, 377 base::Bind(&DumbTask, kStatus4), 378 SyncTaskManager::PRIORITY_MED, 379 base::Bind(&IncrementAndAssign, 3, &callback_count, &callback_status4)); 380 381 // This runs third (expected counter == 2). 382 task_manager.ScheduleTask( 383 FROM_HERE, 384 base::Bind(&DumbTask, kStatus5), 385 SyncTaskManager::PRIORITY_HIGH, 386 base::Bind(&IncrementAndAssign, 2, &callback_count, &callback_status5)); 387 388 message_loop.RunUntilIdle(); 389 390 EXPECT_EQ(kStatus1, callback_status1); 391 EXPECT_EQ(kStatus2, callback_status2); 392 EXPECT_EQ(kStatus3, callback_status3); 393 EXPECT_EQ(kStatus4, callback_status4); 394 EXPECT_EQ(kStatus5, callback_status5); 395 EXPECT_EQ(5, callback_count); 396} 397 398TEST(SyncTaskManagerTest, BackgroundTask_Sequential) { 399 base::MessageLoop message_loop; 400 SyncTaskManager task_manager(base::WeakPtr<SyncTaskManager::Client>(), 401 10 /* maximum_background_task */); 402 task_manager.Initialize(SYNC_STATUS_OK); 403 404 SyncStatusCode status = SYNC_STATUS_FAILED; 405 BackgroundTask::Stats stats; 406 task_manager.ScheduleSyncTask( 407 FROM_HERE, 408 scoped_ptr<SyncTask>(new BackgroundTask( 409 "app_id", MAKE_PATH("/hoge/fuga"), 410 &stats)), 411 SyncTaskManager::PRIORITY_MED, 412 CreateResultReceiver(&status)); 413 414 task_manager.ScheduleSyncTask( 415 FROM_HERE, 416 scoped_ptr<SyncTask>(new BackgroundTask( 417 "app_id", MAKE_PATH("/hoge"), 418 &stats)), 419 SyncTaskManager::PRIORITY_MED, 420 CreateResultReceiver(&status)); 421 422 task_manager.ScheduleSyncTask( 423 FROM_HERE, 424 scoped_ptr<SyncTask>(new BackgroundTask( 425 "app_id", MAKE_PATH("/hoge/fuga/piyo"), 426 &stats)), 427 SyncTaskManager::PRIORITY_MED, 428 CreateResultReceiver(&status)); 429 430 message_loop.RunUntilIdle(); 431 432 EXPECT_EQ(SYNC_STATUS_OK, status); 433 EXPECT_EQ(0, stats.running_background_task); 434 EXPECT_EQ(3, stats.finished_task); 435 EXPECT_EQ(1, stats.max_parallel_task); 436} 437 438TEST(SyncTaskManagerTest, BackgroundTask_Parallel) { 439 base::MessageLoop message_loop; 440 SyncTaskManager task_manager(base::WeakPtr<SyncTaskManager::Client>(), 441 10 /* maximum_background_task */); 442 task_manager.Initialize(SYNC_STATUS_OK); 443 444 SyncStatusCode status = SYNC_STATUS_FAILED; 445 BackgroundTask::Stats stats; 446 task_manager.ScheduleSyncTask( 447 FROM_HERE, 448 scoped_ptr<SyncTask>(new BackgroundTask( 449 "app_id", MAKE_PATH("/hoge"), 450 &stats)), 451 SyncTaskManager::PRIORITY_MED, 452 CreateResultReceiver(&status)); 453 454 task_manager.ScheduleSyncTask( 455 FROM_HERE, 456 scoped_ptr<SyncTask>(new BackgroundTask( 457 "app_id", MAKE_PATH("/fuga"), 458 &stats)), 459 SyncTaskManager::PRIORITY_MED, 460 CreateResultReceiver(&status)); 461 462 task_manager.ScheduleSyncTask( 463 FROM_HERE, 464 scoped_ptr<SyncTask>(new BackgroundTask( 465 "app_id", MAKE_PATH("/piyo"), 466 &stats)), 467 SyncTaskManager::PRIORITY_MED, 468 CreateResultReceiver(&status)); 469 470 message_loop.RunUntilIdle(); 471 472 EXPECT_EQ(SYNC_STATUS_OK, status); 473 EXPECT_EQ(0, stats.running_background_task); 474 EXPECT_EQ(3, stats.finished_task); 475 EXPECT_EQ(3, stats.max_parallel_task); 476} 477 478TEST(SyncTaskManagerTest, BackgroundTask_Throttled) { 479 base::MessageLoop message_loop; 480 SyncTaskManager task_manager(base::WeakPtr<SyncTaskManager::Client>(), 481 2 /* maximum_background_task */); 482 task_manager.Initialize(SYNC_STATUS_OK); 483 484 SyncStatusCode status = SYNC_STATUS_FAILED; 485 BackgroundTask::Stats stats; 486 task_manager.ScheduleSyncTask( 487 FROM_HERE, 488 scoped_ptr<SyncTask>(new BackgroundTask( 489 "app_id", MAKE_PATH("/hoge"), 490 &stats)), 491 SyncTaskManager::PRIORITY_MED, 492 CreateResultReceiver(&status)); 493 494 task_manager.ScheduleSyncTask( 495 FROM_HERE, 496 scoped_ptr<SyncTask>(new BackgroundTask( 497 "app_id", MAKE_PATH("/fuga"), 498 &stats)), 499 SyncTaskManager::PRIORITY_MED, 500 CreateResultReceiver(&status)); 501 502 task_manager.ScheduleSyncTask( 503 FROM_HERE, 504 scoped_ptr<SyncTask>(new BackgroundTask( 505 "app_id", MAKE_PATH("/piyo"), 506 &stats)), 507 SyncTaskManager::PRIORITY_MED, 508 CreateResultReceiver(&status)); 509 510 message_loop.RunUntilIdle(); 511 512 EXPECT_EQ(SYNC_STATUS_OK, status); 513 EXPECT_EQ(0, stats.running_background_task); 514 EXPECT_EQ(3, stats.finished_task); 515 EXPECT_EQ(2, stats.max_parallel_task); 516} 517 518} // namespace drive_backend 519} // namespace sync_file_system 520