sync_task_manager_unittest.cc revision 23730a6e56a168d1879203e4b3819bb36e3d8f1f
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 TaskManagerClient() 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(AsWeakPtr())); 58 task_manager_->Initialize(SYNC_STATUS_OK); 59 maybe_schedule_next_task_count_ = 0; 60 } 61 virtual ~TaskManagerClient() {} 62 63 // DriveFileSyncManager::Client overrides. 64 virtual void MaybeScheduleNextTask() OVERRIDE { 65 ++maybe_schedule_next_task_count_; 66 } 67 virtual void NotifyLastOperationStatus( 68 SyncStatusCode last_operation_status, 69 bool last_operation_used_network) OVERRIDE { 70 last_operation_status_ = last_operation_status; 71 } 72 73 void ScheduleTask(SyncStatusCode status_to_return, 74 const SyncStatusCallback& callback) { 75 task_manager_->ScheduleTask( 76 FROM_HERE, 77 base::Bind(&TaskManagerClient::DoTask, AsWeakPtr(), 78 status_to_return, false /* idle */), 79 SyncTaskManager::PRIORITY_MED, 80 callback); 81 } 82 83 void ScheduleTaskIfIdle(SyncStatusCode status_to_return) { 84 task_manager_->ScheduleTaskIfIdle( 85 FROM_HERE, 86 base::Bind(&TaskManagerClient::DoTask, AsWeakPtr(), 87 status_to_return, true /* idle */), 88 SyncStatusCallback()); 89 } 90 91 int maybe_schedule_next_task_count() const { 92 return maybe_schedule_next_task_count_; 93 } 94 int task_scheduled_count() const { return task_scheduled_count_; } 95 int idle_task_scheduled_count() const { return idle_task_scheduled_count_; } 96 SyncStatusCode last_operation_status() const { 97 return last_operation_status_; 98 } 99 100 private: 101 void DoTask(SyncStatusCode status_to_return, 102 bool is_idle_task, 103 const SyncStatusCallback& callback) { 104 ++task_scheduled_count_; 105 if (is_idle_task) 106 ++idle_task_scheduled_count_; 107 base::MessageLoop::current()->PostTask( 108 FROM_HERE, base::Bind(callback, status_to_return)); 109 } 110 111 scoped_ptr<SyncTaskManager> task_manager_; 112 113 int maybe_schedule_next_task_count_; 114 int task_scheduled_count_; 115 int idle_task_scheduled_count_; 116 117 SyncStatusCode last_operation_status_; 118 119 DISALLOW_COPY_AND_ASSIGN(TaskManagerClient); 120}; 121 122class MultihopSyncTask : public SequentialSyncTask { 123 public: 124 MultihopSyncTask(bool* task_started, 125 bool* task_completed) 126 : task_started_(task_started), 127 task_completed_(task_completed), 128 weak_ptr_factory_(this) { 129 DCHECK(task_started_); 130 DCHECK(task_completed_); 131 } 132 133 virtual ~MultihopSyncTask() {} 134 135 virtual void RunSequential(const SyncStatusCallback& callback) OVERRIDE { 136 DCHECK(!*task_started_); 137 *task_started_ = true; 138 base::MessageLoop::current()->PostTask( 139 FROM_HERE, base::Bind(&MultihopSyncTask::CompleteTask, 140 weak_ptr_factory_.GetWeakPtr(), callback)); 141 } 142 143 private: 144 void CompleteTask(const SyncStatusCallback& callback) { 145 DCHECK(*task_started_); 146 DCHECK(!*task_completed_); 147 *task_completed_ = true; 148 callback.Run(SYNC_STATUS_OK); 149 } 150 151 bool* task_started_; 152 bool* task_completed_; 153 base::WeakPtrFactory<MultihopSyncTask> weak_ptr_factory_; 154 155 DISALLOW_COPY_AND_ASSIGN(MultihopSyncTask); 156}; 157 158class BackgroundTask : public SyncTask { 159 public: 160 struct Stats { 161 int64 running_background_task; 162 int64 finished_task; 163 int64 max_parallel_task; 164 165 Stats() 166 : running_background_task(0), 167 finished_task(0), 168 max_parallel_task(0) {} 169 }; 170 171 BackgroundTask(const std::string& app_id, 172 const base::FilePath& path, 173 Stats* stats) 174 : app_id_(app_id), 175 path_(path), 176 stats_(stats), 177 weak_ptr_factory_(this) { 178 } 179 180 virtual ~BackgroundTask() { 181 } 182 183 virtual void Run(scoped_ptr<SyncTaskToken> token) OVERRIDE { 184 scoped_ptr<BlockingFactor> blocking_factor(new BlockingFactor); 185 blocking_factor->app_id = app_id_; 186 blocking_factor->paths.push_back(path_); 187 188 SyncTaskManager::MoveTaskToBackground( 189 token.Pass(), blocking_factor.Pass(), 190 base::Bind(&BackgroundTask::RunAsBackgroundTask, 191 weak_ptr_factory_.GetWeakPtr())); 192 } 193 194 private: 195 void RunAsBackgroundTask(scoped_ptr<SyncTaskToken> token) { 196 ++(stats_->running_background_task); 197 if (stats_->max_parallel_task < stats_->running_background_task) 198 stats_->max_parallel_task = stats_->running_background_task; 199 200 base::MessageLoop::current()->PostTask( 201 FROM_HERE, 202 base::Bind(&BackgroundTask::CompleteTask, 203 weak_ptr_factory_.GetWeakPtr(), 204 base::Passed(&token))); 205 } 206 207 void CompleteTask(scoped_ptr<SyncTaskToken> token) { 208 ++(stats_->finished_task); 209 --(stats_->running_background_task); 210 SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_OK); 211 } 212 213 std::string app_id_; 214 base::FilePath path_; 215 Stats* stats_; 216 217 base::WeakPtrFactory<BackgroundTask> weak_ptr_factory_; 218 219 DISALLOW_COPY_AND_ASSIGN(BackgroundTask); 220}; 221 222// Arbitrary non-default status values for testing. 223const SyncStatusCode kStatus1 = static_cast<SyncStatusCode>(-1); 224const SyncStatusCode kStatus2 = static_cast<SyncStatusCode>(-2); 225const SyncStatusCode kStatus3 = static_cast<SyncStatusCode>(-3); 226const SyncStatusCode kStatus4 = static_cast<SyncStatusCode>(-4); 227const SyncStatusCode kStatus5 = static_cast<SyncStatusCode>(-5); 228 229} // namespace 230 231TEST(SyncTaskManagerTest, ScheduleTask) { 232 base::MessageLoop message_loop; 233 TaskManagerClient client; 234 int callback_count = 0; 235 SyncStatusCode callback_status = SYNC_STATUS_OK; 236 237 client.ScheduleTask(kStatus1, base::Bind(&IncrementAndAssign, 0, 238 &callback_count, 239 &callback_status)); 240 message_loop.RunUntilIdle(); 241 242 EXPECT_EQ(kStatus1, callback_status); 243 EXPECT_EQ(kStatus1, client.last_operation_status()); 244 245 EXPECT_EQ(1, callback_count); 246 EXPECT_EQ(1, client.maybe_schedule_next_task_count()); 247 EXPECT_EQ(1, client.task_scheduled_count()); 248 EXPECT_EQ(0, client.idle_task_scheduled_count()); 249} 250 251TEST(SyncTaskManagerTest, ScheduleTwoTasks) { 252 base::MessageLoop message_loop; 253 TaskManagerClient client; 254 int callback_count = 0; 255 SyncStatusCode callback_status = SYNC_STATUS_OK; 256 257 client.ScheduleTask(kStatus1, base::Bind(&IncrementAndAssign, 0, 258 &callback_count, 259 &callback_status)); 260 client.ScheduleTask(kStatus2, base::Bind(&IncrementAndAssign, 1, 261 &callback_count, 262 &callback_status)); 263 message_loop.RunUntilIdle(); 264 265 EXPECT_EQ(kStatus2, callback_status); 266 EXPECT_EQ(kStatus2, client.last_operation_status()); 267 268 EXPECT_EQ(2, callback_count); 269 EXPECT_EQ(1, client.maybe_schedule_next_task_count()); 270 EXPECT_EQ(2, client.task_scheduled_count()); 271 EXPECT_EQ(0, client.idle_task_scheduled_count()); 272} 273 274TEST(SyncTaskManagerTest, ScheduleIdleTask) { 275 base::MessageLoop message_loop; 276 TaskManagerClient client; 277 278 client.ScheduleTaskIfIdle(kStatus1); 279 message_loop.RunUntilIdle(); 280 281 EXPECT_EQ(kStatus1, client.last_operation_status()); 282 283 EXPECT_EQ(1, client.maybe_schedule_next_task_count()); 284 EXPECT_EQ(1, client.task_scheduled_count()); 285 EXPECT_EQ(1, client.idle_task_scheduled_count()); 286} 287 288TEST(SyncTaskManagerTest, ScheduleIdleTaskWhileNotIdle) { 289 base::MessageLoop message_loop; 290 TaskManagerClient client; 291 int callback_count = 0; 292 SyncStatusCode callback_status = SYNC_STATUS_OK; 293 294 client.ScheduleTask(kStatus1, base::Bind(&IncrementAndAssign, 0, 295 &callback_count, 296 &callback_status)); 297 client.ScheduleTaskIfIdle(kStatus2); 298 message_loop.RunUntilIdle(); 299 300 // Idle task must not have run. 301 EXPECT_EQ(kStatus1, callback_status); 302 EXPECT_EQ(kStatus1, client.last_operation_status()); 303 304 EXPECT_EQ(1, callback_count); 305 EXPECT_EQ(1, client.maybe_schedule_next_task_count()); 306 EXPECT_EQ(1, client.task_scheduled_count()); 307 EXPECT_EQ(0, client.idle_task_scheduled_count()); 308} 309 310TEST(SyncTaskManagerTest, ScheduleAndCancelSyncTask) { 311 base::MessageLoop message_loop; 312 313 int callback_count = 0; 314 SyncStatusCode status = SYNC_STATUS_UNKNOWN; 315 316 bool task_started = false; 317 bool task_completed = false; 318 319 { 320 SyncTaskManager task_manager((base::WeakPtr<SyncTaskManager::Client>())); 321 task_manager.Initialize(SYNC_STATUS_OK); 322 task_manager.ScheduleSyncTask( 323 FROM_HERE, 324 scoped_ptr<SyncTask>(new MultihopSyncTask( 325 &task_started, &task_completed)), 326 SyncTaskManager::PRIORITY_MED, 327 base::Bind(&IncrementAndAssign, 0, &callback_count, &status)); 328 } 329 330 message_loop.RunUntilIdle(); 331 EXPECT_EQ(0, callback_count); 332 EXPECT_EQ(SYNC_STATUS_UNKNOWN, status); 333 EXPECT_TRUE(task_started); 334 EXPECT_FALSE(task_completed); 335} 336 337TEST(SyncTaskManagerTest, ScheduleTaskAtPriority) { 338 base::MessageLoop message_loop; 339 SyncTaskManager task_manager((base::WeakPtr<SyncTaskManager::Client>())); 340 task_manager.Initialize(SYNC_STATUS_OK); 341 342 int callback_count = 0; 343 SyncStatusCode callback_status1 = SYNC_STATUS_OK; 344 SyncStatusCode callback_status2 = SYNC_STATUS_OK; 345 SyncStatusCode callback_status3 = SYNC_STATUS_OK; 346 SyncStatusCode callback_status4 = SYNC_STATUS_OK; 347 SyncStatusCode callback_status5 = SYNC_STATUS_OK; 348 349 // This will run first even if its priority is low, since there're no 350 // pending tasks. 351 task_manager.ScheduleTask( 352 FROM_HERE, 353 base::Bind(&DumbTask, kStatus1), 354 SyncTaskManager::PRIORITY_LOW, 355 base::Bind(&IncrementAndAssign, 0, &callback_count, &callback_status1)); 356 357 // This runs last (expected counter == 4). 358 task_manager.ScheduleTask( 359 FROM_HERE, 360 base::Bind(&DumbTask, kStatus2), 361 SyncTaskManager::PRIORITY_LOW, 362 base::Bind(&IncrementAndAssign, 4, &callback_count, &callback_status2)); 363 364 // This runs second (expected counter == 1). 365 task_manager.ScheduleTask( 366 FROM_HERE, 367 base::Bind(&DumbTask, kStatus3), 368 SyncTaskManager::PRIORITY_HIGH, 369 base::Bind(&IncrementAndAssign, 1, &callback_count, &callback_status3)); 370 371 // This runs fourth (expected counter == 3). 372 task_manager.ScheduleTask( 373 FROM_HERE, 374 base::Bind(&DumbTask, kStatus4), 375 SyncTaskManager::PRIORITY_MED, 376 base::Bind(&IncrementAndAssign, 3, &callback_count, &callback_status4)); 377 378 // This runs third (expected counter == 2). 379 task_manager.ScheduleTask( 380 FROM_HERE, 381 base::Bind(&DumbTask, kStatus5), 382 SyncTaskManager::PRIORITY_HIGH, 383 base::Bind(&IncrementAndAssign, 2, &callback_count, &callback_status5)); 384 385 message_loop.RunUntilIdle(); 386 387 EXPECT_EQ(kStatus1, callback_status1); 388 EXPECT_EQ(kStatus2, callback_status2); 389 EXPECT_EQ(kStatus3, callback_status3); 390 EXPECT_EQ(kStatus4, callback_status4); 391 EXPECT_EQ(kStatus5, callback_status5); 392 EXPECT_EQ(5, callback_count); 393} 394 395TEST(SyncTaskManagerTest, BackgroundTask_Sequential) { 396 base::MessageLoop message_loop; 397 SyncTaskManager task_manager((base::WeakPtr<SyncTaskManager::Client>())); 398 task_manager.Initialize(SYNC_STATUS_OK); 399 400 SyncStatusCode status = SYNC_STATUS_FAILED; 401 BackgroundTask::Stats stats; 402 task_manager.ScheduleSyncTask( 403 FROM_HERE, 404 scoped_ptr<SyncTask>(new BackgroundTask( 405 "app_id", MAKE_PATH("/hoge/fuga"), 406 &stats)), 407 SyncTaskManager::PRIORITY_MED, 408 CreateResultReceiver(&status)); 409 410 task_manager.ScheduleSyncTask( 411 FROM_HERE, 412 scoped_ptr<SyncTask>(new BackgroundTask( 413 "app_id", MAKE_PATH("/hoge"), 414 &stats)), 415 SyncTaskManager::PRIORITY_MED, 416 CreateResultReceiver(&status)); 417 418 task_manager.ScheduleSyncTask( 419 FROM_HERE, 420 scoped_ptr<SyncTask>(new BackgroundTask( 421 "app_id", MAKE_PATH("/hoge/fuga/piyo"), 422 &stats)), 423 SyncTaskManager::PRIORITY_MED, 424 CreateResultReceiver(&status)); 425 426 message_loop.RunUntilIdle(); 427 428 EXPECT_EQ(SYNC_STATUS_OK, status); 429 EXPECT_EQ(0, stats.running_background_task); 430 EXPECT_EQ(3, stats.finished_task); 431 EXPECT_EQ(1, stats.max_parallel_task); 432} 433 434TEST(SyncTaskManagerTest, BackgroundTask_Parallel) { 435 base::MessageLoop message_loop; 436 SyncTaskManager task_manager((base::WeakPtr<SyncTaskManager::Client>())); 437 task_manager.Initialize(SYNC_STATUS_OK); 438 439 SyncStatusCode status = SYNC_STATUS_FAILED; 440 BackgroundTask::Stats stats; 441 task_manager.ScheduleSyncTask( 442 FROM_HERE, 443 scoped_ptr<SyncTask>(new BackgroundTask( 444 "app_id", MAKE_PATH("/hoge"), 445 &stats)), 446 SyncTaskManager::PRIORITY_MED, 447 CreateResultReceiver(&status)); 448 449 task_manager.ScheduleSyncTask( 450 FROM_HERE, 451 scoped_ptr<SyncTask>(new BackgroundTask( 452 "app_id", MAKE_PATH("/fuga"), 453 &stats)), 454 SyncTaskManager::PRIORITY_MED, 455 CreateResultReceiver(&status)); 456 457 task_manager.ScheduleSyncTask( 458 FROM_HERE, 459 scoped_ptr<SyncTask>(new BackgroundTask( 460 "app_id", MAKE_PATH("/piyo"), 461 &stats)), 462 SyncTaskManager::PRIORITY_MED, 463 CreateResultReceiver(&status)); 464 465 message_loop.RunUntilIdle(); 466 467 EXPECT_EQ(SYNC_STATUS_OK, status); 468 EXPECT_EQ(0, stats.running_background_task); 469 EXPECT_EQ(3, stats.finished_task); 470 EXPECT_EQ(3, stats.max_parallel_task); 471} 472 473} // namespace drive_backend 474} // namespace sync_file_system 475