#ifndef BASE_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_
#define BASE_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_
#include <cstddef>
#include <iosfwd>
#include <vector>
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
#include "base/synchronization/lock.h"
#include "base/time.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
namespace internal {
struct TaskEvent {
enum Type { POST, START, END };
TaskEvent(int i, Type type);
int i;
Type type;
};
class SequencedTaskTracker : public RefCountedThreadSafe<SequencedTaskTracker> {
public:
SequencedTaskTracker();
void PostWrappedNonNestableTask(
const scoped_refptr<SequencedTaskRunner>& task_runner,
const Closure& task);
void PostWrappedNestableTask(
const scoped_refptr<SequencedTaskRunner>& task_runner,
const Closure& task);
void PostWrappedDelayedNonNestableTask(
const scoped_refptr<SequencedTaskRunner>& task_runner,
const Closure& task,
TimeDelta delay);
void PostNonNestableTasks(
const scoped_refptr<SequencedTaskRunner>& task_runner,
int task_count);
const std::vector<TaskEvent>& GetTaskEvents() const;
private:
friend class RefCountedThreadSafe<SequencedTaskTracker>;
~SequencedTaskTracker();
void RunTask(const Closure& task, int task_i);
void TaskPosted(int i);
void TaskStarted(int i);
void TaskEnded(int i);
Lock lock_;
std::vector<TaskEvent> events_;
int next_post_i_;
DISALLOW_COPY_AND_ASSIGN(SequencedTaskTracker);
};
void PrintTo(const TaskEvent& event, std::ostream* os);
void SleepForOneSecond();
::testing::AssertionResult CheckNonNestableInvariants(
const std::vector<TaskEvent>& events,
int task_count);
}
template <typename TaskRunnerTestDelegate>
class SequencedTaskRunnerTest : public testing::Test {
protected:
SequencedTaskRunnerTest()
: task_tracker_(new internal::SequencedTaskTracker()) {}
const scoped_refptr<internal::SequencedTaskTracker> task_tracker_;
TaskRunnerTestDelegate delegate_;
};
TYPED_TEST_CASE_P(SequencedTaskRunnerTest);
TYPED_TEST_P(SequencedTaskRunnerTest, SequentialNonNestable) {
const int task_count = 1000;
this->delegate_.StartTaskRunner();
const scoped_refptr<SequencedTaskRunner> task_runner =
this->delegate_.GetTaskRunner();
this->task_tracker_->PostWrappedNonNestableTask(
task_runner, Bind(&internal::SleepForOneSecond));
for (int i = 1; i < task_count; ++i) {
this->task_tracker_->PostWrappedNonNestableTask(task_runner, Closure());
}
this->delegate_.StopTaskRunner();
EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
task_count));
}
TYPED_TEST_P(SequencedTaskRunnerTest, SequentialNestable) {
const int task_count = 1000;
this->delegate_.StartTaskRunner();
const scoped_refptr<SequencedTaskRunner> task_runner =
this->delegate_.GetTaskRunner();
this->task_tracker_->PostWrappedNestableTask(
task_runner,
Bind(&internal::SleepForOneSecond));
for (int i = 1; i < task_count; ++i) {
this->task_tracker_->PostWrappedNestableTask(task_runner, Closure());
}
this->delegate_.StopTaskRunner();
EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
task_count));
}
TYPED_TEST_P(SequencedTaskRunnerTest, SequentialDelayedNonNestable) {
if (!this->delegate_.TaskRunnerHandlesNonZeroDelays()) {
DLOG(INFO) << "This SequencedTaskRunner doesn't handle "
"non-zero delays; skipping";
return;
}
const int task_count = 20;
const int delay_increment_ms = 50;
this->delegate_.StartTaskRunner();
const scoped_refptr<SequencedTaskRunner> task_runner =
this->delegate_.GetTaskRunner();
for (int i = 0; i < task_count; ++i) {
this->task_tracker_->PostWrappedDelayedNonNestableTask(
task_runner,
Closure(),
TimeDelta::FromMilliseconds(delay_increment_ms * i));
}
this->delegate_.StopTaskRunner();
EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
task_count));
}
TYPED_TEST_P(SequencedTaskRunnerTest, NonNestablePostFromNonNestableTask) {
const int parent_count = 10;
const int children_per_parent = 10;
this->delegate_.StartTaskRunner();
const scoped_refptr<SequencedTaskRunner> task_runner =
this->delegate_.GetTaskRunner();
for (int i = 0; i < parent_count; ++i) {
Closure task = Bind(
&internal::SequencedTaskTracker::PostNonNestableTasks,
this->task_tracker_,
task_runner,
children_per_parent);
this->task_tracker_->PostWrappedNonNestableTask(task_runner, task);
}
this->delegate_.StopTaskRunner();
EXPECT_TRUE(CheckNonNestableInvariants(
this->task_tracker_->GetTaskEvents(),
parent_count * (children_per_parent + 1)));
}
REGISTER_TYPED_TEST_CASE_P(SequencedTaskRunnerTest,
SequentialNonNestable,
SequentialNestable,
SequentialDelayedNonNestable,
NonNestablePostFromNonNestableTask);
}
#endif