This source file includes following definitions.
- DumbTask
- IncrementAndAssign
- IncrementAndAssignWithOwnedPointer
- last_operation_status_
- MaybeScheduleNextTask
- NotifyLastOperationStatus
- ScheduleTask
- ScheduleTaskIfIdle
- maybe_schedule_next_task_count
- task_scheduled_count
- idle_task_scheduled_count
- last_operation_status
- DoTask
- weak_ptr_factory_
- RunExclusive
- CompleteTask
- weak_ptr_factory_
- RunPreflight
- RunAsBackgroundTask
- CompleteTask
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "chrome/browser/sync_file_system/drive_backend/sync_task_manager.h"
#include "chrome/browser/sync_file_system/drive_backend/sync_task_token.h"
#include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/common/fileapi/file_system_util.h"
#define MAKE_PATH(path) \
base::FilePath(fileapi::VirtualPath::GetNormalizedFilePath( \
base::FilePath(FILE_PATH_LITERAL(path))))
namespace sync_file_system {
namespace drive_backend {
namespace {
void DumbTask(SyncStatusCode status,
const SyncStatusCallback& callback) {
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(callback, status));
}
void IncrementAndAssign(int expected_before_counter,
int* counter,
SyncStatusCode* status_out,
SyncStatusCode status) {
EXPECT_EQ(expected_before_counter, *counter);
++(*counter);
*status_out = status;
}
template <typename T>
void IncrementAndAssignWithOwnedPointer(T* object,
int* counter,
SyncStatusCode* status_out,
SyncStatusCode status) {
++(*counter);
*status_out = status;
}
class TaskManagerClient
: public SyncTaskManager::Client,
public base::SupportsWeakPtr<TaskManagerClient> {
public:
explicit TaskManagerClient(int64 maximum_background_task)
: maybe_schedule_next_task_count_(0),
task_scheduled_count_(0),
idle_task_scheduled_count_(0),
last_operation_status_(SYNC_STATUS_OK) {
task_manager_.reset(new SyncTaskManager(
AsWeakPtr(), maximum_background_task));
task_manager_->Initialize(SYNC_STATUS_OK);
maybe_schedule_next_task_count_ = 0;
}
virtual ~TaskManagerClient() {}
virtual void MaybeScheduleNextTask() OVERRIDE {
++maybe_schedule_next_task_count_;
}
virtual void NotifyLastOperationStatus(
SyncStatusCode last_operation_status,
bool last_operation_used_network) OVERRIDE {
last_operation_status_ = last_operation_status;
}
void ScheduleTask(SyncStatusCode status_to_return,
const SyncStatusCallback& callback) {
task_manager_->ScheduleTask(
FROM_HERE,
base::Bind(&TaskManagerClient::DoTask, AsWeakPtr(),
status_to_return, false ),
SyncTaskManager::PRIORITY_MED,
callback);
}
void ScheduleTaskIfIdle(SyncStatusCode status_to_return) {
task_manager_->ScheduleTaskIfIdle(
FROM_HERE,
base::Bind(&TaskManagerClient::DoTask, AsWeakPtr(),
status_to_return, true ),
SyncStatusCallback());
}
int maybe_schedule_next_task_count() const {
return maybe_schedule_next_task_count_;
}
int task_scheduled_count() const { return task_scheduled_count_; }
int idle_task_scheduled_count() const { return idle_task_scheduled_count_; }
SyncStatusCode last_operation_status() const {
return last_operation_status_;
}
private:
void DoTask(SyncStatusCode status_to_return,
bool is_idle_task,
const SyncStatusCallback& callback) {
++task_scheduled_count_;
if (is_idle_task)
++idle_task_scheduled_count_;
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(callback, status_to_return));
}
scoped_ptr<SyncTaskManager> task_manager_;
int maybe_schedule_next_task_count_;
int task_scheduled_count_;
int idle_task_scheduled_count_;
SyncStatusCode last_operation_status_;
DISALLOW_COPY_AND_ASSIGN(TaskManagerClient);
};
class MultihopSyncTask : public ExclusiveTask {
public:
MultihopSyncTask(bool* task_started,
bool* task_completed)
: task_started_(task_started),
task_completed_(task_completed),
weak_ptr_factory_(this) {
DCHECK(task_started_);
DCHECK(task_completed_);
}
virtual ~MultihopSyncTask() {}
virtual void RunExclusive(const SyncStatusCallback& callback) OVERRIDE {
DCHECK(!*task_started_);
*task_started_ = true;
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(&MultihopSyncTask::CompleteTask,
weak_ptr_factory_.GetWeakPtr(), callback));
}
private:
void CompleteTask(const SyncStatusCallback& callback) {
DCHECK(*task_started_);
DCHECK(!*task_completed_);
*task_completed_ = true;
callback.Run(SYNC_STATUS_OK);
}
bool* task_started_;
bool* task_completed_;
base::WeakPtrFactory<MultihopSyncTask> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(MultihopSyncTask);
};
class BackgroundTask : public SyncTask {
public:
struct Stats {
int64 running_background_task;
int64 finished_task;
int64 max_parallel_task;
Stats()
: running_background_task(0),
finished_task(0),
max_parallel_task(0) {}
};
BackgroundTask(const std::string& app_id,
const base::FilePath& path,
Stats* stats)
: app_id_(app_id),
path_(path),
stats_(stats),
weak_ptr_factory_(this) {
}
virtual ~BackgroundTask() {
}
virtual void RunPreflight(scoped_ptr<SyncTaskToken> token) OVERRIDE {
scoped_ptr<BlockingFactor> blocking_factor(new BlockingFactor);
blocking_factor->app_id = app_id_;
blocking_factor->paths.push_back(path_);
SyncTaskManager::MoveTaskToBackground(
token.Pass(), blocking_factor.Pass(),
base::Bind(&BackgroundTask::RunAsBackgroundTask,
weak_ptr_factory_.GetWeakPtr()));
}
private:
void RunAsBackgroundTask(scoped_ptr<SyncTaskToken> token) {
++(stats_->running_background_task);
if (stats_->max_parallel_task < stats_->running_background_task)
stats_->max_parallel_task = stats_->running_background_task;
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&BackgroundTask::CompleteTask,
weak_ptr_factory_.GetWeakPtr(),
base::Passed(&token)));
}
void CompleteTask(scoped_ptr<SyncTaskToken> token) {
++(stats_->finished_task);
--(stats_->running_background_task);
SyncTaskManager::NotifyTaskDone(token.Pass(), SYNC_STATUS_OK);
}
std::string app_id_;
base::FilePath path_;
Stats* stats_;
base::WeakPtrFactory<BackgroundTask> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(BackgroundTask);
};
const SyncStatusCode kStatus1 = static_cast<SyncStatusCode>(-1);
const SyncStatusCode kStatus2 = static_cast<SyncStatusCode>(-2);
const SyncStatusCode kStatus3 = static_cast<SyncStatusCode>(-3);
const SyncStatusCode kStatus4 = static_cast<SyncStatusCode>(-4);
const SyncStatusCode kStatus5 = static_cast<SyncStatusCode>(-5);
}
TEST(SyncTaskManagerTest, ScheduleTask) {
base::MessageLoop message_loop;
TaskManagerClient client(0 );
int callback_count = 0;
SyncStatusCode callback_status = SYNC_STATUS_OK;
client.ScheduleTask(kStatus1, base::Bind(&IncrementAndAssign, 0,
&callback_count,
&callback_status));
message_loop.RunUntilIdle();
EXPECT_EQ(kStatus1, callback_status);
EXPECT_EQ(kStatus1, client.last_operation_status());
EXPECT_EQ(1, callback_count);
EXPECT_EQ(1, client.maybe_schedule_next_task_count());
EXPECT_EQ(1, client.task_scheduled_count());
EXPECT_EQ(0, client.idle_task_scheduled_count());
}
TEST(SyncTaskManagerTest, ScheduleTwoTasks) {
base::MessageLoop message_loop;
TaskManagerClient client(0 );
int callback_count = 0;
SyncStatusCode callback_status = SYNC_STATUS_OK;
client.ScheduleTask(kStatus1, base::Bind(&IncrementAndAssign, 0,
&callback_count,
&callback_status));
client.ScheduleTask(kStatus2, base::Bind(&IncrementAndAssign, 1,
&callback_count,
&callback_status));
message_loop.RunUntilIdle();
EXPECT_EQ(kStatus2, callback_status);
EXPECT_EQ(kStatus2, client.last_operation_status());
EXPECT_EQ(2, callback_count);
EXPECT_EQ(1, client.maybe_schedule_next_task_count());
EXPECT_EQ(2, client.task_scheduled_count());
EXPECT_EQ(0, client.idle_task_scheduled_count());
}
TEST(SyncTaskManagerTest, ScheduleIdleTask) {
base::MessageLoop message_loop;
TaskManagerClient client(0 );
client.ScheduleTaskIfIdle(kStatus1);
message_loop.RunUntilIdle();
EXPECT_EQ(kStatus1, client.last_operation_status());
EXPECT_EQ(1, client.maybe_schedule_next_task_count());
EXPECT_EQ(1, client.task_scheduled_count());
EXPECT_EQ(1, client.idle_task_scheduled_count());
}
TEST(SyncTaskManagerTest, ScheduleIdleTaskWhileNotIdle) {
base::MessageLoop message_loop;
TaskManagerClient client(0 );
int callback_count = 0;
SyncStatusCode callback_status = SYNC_STATUS_OK;
client.ScheduleTask(kStatus1, base::Bind(&IncrementAndAssign, 0,
&callback_count,
&callback_status));
client.ScheduleTaskIfIdle(kStatus2);
message_loop.RunUntilIdle();
EXPECT_EQ(kStatus1, callback_status);
EXPECT_EQ(kStatus1, client.last_operation_status());
EXPECT_EQ(1, callback_count);
EXPECT_EQ(1, client.maybe_schedule_next_task_count());
EXPECT_EQ(1, client.task_scheduled_count());
EXPECT_EQ(0, client.idle_task_scheduled_count());
}
TEST(SyncTaskManagerTest, ScheduleAndCancelSyncTask) {
base::MessageLoop message_loop;
int callback_count = 0;
SyncStatusCode status = SYNC_STATUS_UNKNOWN;
bool task_started = false;
bool task_completed = false;
{
SyncTaskManager task_manager(base::WeakPtr<SyncTaskManager::Client>(),
0 );
task_manager.Initialize(SYNC_STATUS_OK);
task_manager.ScheduleSyncTask(
FROM_HERE,
scoped_ptr<SyncTask>(new MultihopSyncTask(
&task_started, &task_completed)),
SyncTaskManager::PRIORITY_MED,
base::Bind(&IncrementAndAssign, 0, &callback_count, &status));
}
message_loop.RunUntilIdle();
EXPECT_EQ(0, callback_count);
EXPECT_EQ(SYNC_STATUS_UNKNOWN, status);
EXPECT_TRUE(task_started);
EXPECT_FALSE(task_completed);
}
TEST(SyncTaskManagerTest, ScheduleTaskAtPriority) {
base::MessageLoop message_loop;
SyncTaskManager task_manager(base::WeakPtr<SyncTaskManager::Client>(),
0 );
task_manager.Initialize(SYNC_STATUS_OK);
int callback_count = 0;
SyncStatusCode callback_status1 = SYNC_STATUS_OK;
SyncStatusCode callback_status2 = SYNC_STATUS_OK;
SyncStatusCode callback_status3 = SYNC_STATUS_OK;
SyncStatusCode callback_status4 = SYNC_STATUS_OK;
SyncStatusCode callback_status5 = SYNC_STATUS_OK;
task_manager.ScheduleTask(
FROM_HERE,
base::Bind(&DumbTask, kStatus1),
SyncTaskManager::PRIORITY_LOW,
base::Bind(&IncrementAndAssign, 0, &callback_count, &callback_status1));
task_manager.ScheduleTask(
FROM_HERE,
base::Bind(&DumbTask, kStatus2),
SyncTaskManager::PRIORITY_LOW,
base::Bind(&IncrementAndAssign, 4, &callback_count, &callback_status2));
task_manager.ScheduleTask(
FROM_HERE,
base::Bind(&DumbTask, kStatus3),
SyncTaskManager::PRIORITY_HIGH,
base::Bind(&IncrementAndAssign, 1, &callback_count, &callback_status3));
task_manager.ScheduleTask(
FROM_HERE,
base::Bind(&DumbTask, kStatus4),
SyncTaskManager::PRIORITY_MED,
base::Bind(&IncrementAndAssign, 3, &callback_count, &callback_status4));
task_manager.ScheduleTask(
FROM_HERE,
base::Bind(&DumbTask, kStatus5),
SyncTaskManager::PRIORITY_HIGH,
base::Bind(&IncrementAndAssign, 2, &callback_count, &callback_status5));
message_loop.RunUntilIdle();
EXPECT_EQ(kStatus1, callback_status1);
EXPECT_EQ(kStatus2, callback_status2);
EXPECT_EQ(kStatus3, callback_status3);
EXPECT_EQ(kStatus4, callback_status4);
EXPECT_EQ(kStatus5, callback_status5);
EXPECT_EQ(5, callback_count);
}
TEST(SyncTaskManagerTest, BackgroundTask_Sequential) {
base::MessageLoop message_loop;
SyncTaskManager task_manager(base::WeakPtr<SyncTaskManager::Client>(),
10 );
task_manager.Initialize(SYNC_STATUS_OK);
SyncStatusCode status = SYNC_STATUS_FAILED;
BackgroundTask::Stats stats;
task_manager.ScheduleSyncTask(
FROM_HERE,
scoped_ptr<SyncTask>(new BackgroundTask(
"app_id", MAKE_PATH("/hoge/fuga"),
&stats)),
SyncTaskManager::PRIORITY_MED,
CreateResultReceiver(&status));
task_manager.ScheduleSyncTask(
FROM_HERE,
scoped_ptr<SyncTask>(new BackgroundTask(
"app_id", MAKE_PATH("/hoge"),
&stats)),
SyncTaskManager::PRIORITY_MED,
CreateResultReceiver(&status));
task_manager.ScheduleSyncTask(
FROM_HERE,
scoped_ptr<SyncTask>(new BackgroundTask(
"app_id", MAKE_PATH("/hoge/fuga/piyo"),
&stats)),
SyncTaskManager::PRIORITY_MED,
CreateResultReceiver(&status));
message_loop.RunUntilIdle();
EXPECT_EQ(SYNC_STATUS_OK, status);
EXPECT_EQ(0, stats.running_background_task);
EXPECT_EQ(3, stats.finished_task);
EXPECT_EQ(1, stats.max_parallel_task);
}
TEST(SyncTaskManagerTest, BackgroundTask_Parallel) {
base::MessageLoop message_loop;
SyncTaskManager task_manager(base::WeakPtr<SyncTaskManager::Client>(),
10 );
task_manager.Initialize(SYNC_STATUS_OK);
SyncStatusCode status = SYNC_STATUS_FAILED;
BackgroundTask::Stats stats;
task_manager.ScheduleSyncTask(
FROM_HERE,
scoped_ptr<SyncTask>(new BackgroundTask(
"app_id", MAKE_PATH("/hoge"),
&stats)),
SyncTaskManager::PRIORITY_MED,
CreateResultReceiver(&status));
task_manager.ScheduleSyncTask(
FROM_HERE,
scoped_ptr<SyncTask>(new BackgroundTask(
"app_id", MAKE_PATH("/fuga"),
&stats)),
SyncTaskManager::PRIORITY_MED,
CreateResultReceiver(&status));
task_manager.ScheduleSyncTask(
FROM_HERE,
scoped_ptr<SyncTask>(new BackgroundTask(
"app_id", MAKE_PATH("/piyo"),
&stats)),
SyncTaskManager::PRIORITY_MED,
CreateResultReceiver(&status));
message_loop.RunUntilIdle();
EXPECT_EQ(SYNC_STATUS_OK, status);
EXPECT_EQ(0, stats.running_background_task);
EXPECT_EQ(3, stats.finished_task);
EXPECT_EQ(3, stats.max_parallel_task);
}
TEST(SyncTaskManagerTest, BackgroundTask_Throttled) {
base::MessageLoop message_loop;
SyncTaskManager task_manager(base::WeakPtr<SyncTaskManager::Client>(),
2 );
task_manager.Initialize(SYNC_STATUS_OK);
SyncStatusCode status = SYNC_STATUS_FAILED;
BackgroundTask::Stats stats;
task_manager.ScheduleSyncTask(
FROM_HERE,
scoped_ptr<SyncTask>(new BackgroundTask(
"app_id", MAKE_PATH("/hoge"),
&stats)),
SyncTaskManager::PRIORITY_MED,
CreateResultReceiver(&status));
task_manager.ScheduleSyncTask(
FROM_HERE,
scoped_ptr<SyncTask>(new BackgroundTask(
"app_id", MAKE_PATH("/fuga"),
&stats)),
SyncTaskManager::PRIORITY_MED,
CreateResultReceiver(&status));
task_manager.ScheduleSyncTask(
FROM_HERE,
scoped_ptr<SyncTask>(new BackgroundTask(
"app_id", MAKE_PATH("/piyo"),
&stats)),
SyncTaskManager::PRIORITY_MED,
CreateResultReceiver(&status));
message_loop.RunUntilIdle();
EXPECT_EQ(SYNC_STATUS_OK, status);
EXPECT_EQ(0, stats.running_background_task);
EXPECT_EQ(3, stats.finished_task);
EXPECT_EQ(2, stats.max_parallel_task);
}
}
}