| Index: base/test/sequenced_task_runner_test_template.h
|
| ===================================================================
|
| --- base/test/sequenced_task_runner_test_template.h (revision 0)
|
| +++ base/test/sequenced_task_runner_test_template.h (revision 0)
|
| @@ -0,0 +1,243 @@
|
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +// This class defines tests that implementations of SequencedTaskRunner should
|
| +// pass in order to be conformant. See task_runner_test_template.h for a
|
| +// description of how to use the constructs in this file; these work the same.
|
| +
|
| +#ifndef BASE_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_
|
| +#define BASE_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_
|
| +#pragma once
|
| +
|
| +#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;
|
| +};
|
| +
|
| +// Utility class used in the tests below.
|
| +class SequencedTaskTracker : public RefCountedThreadSafe<SequencedTaskTracker> {
|
| + public:
|
| + SequencedTaskTracker();
|
| +
|
| + // Posts the non-nestable task |task|, and records its post event.
|
| + void PostWrappedNonNestableTask(
|
| + const scoped_refptr<SequencedTaskRunner>& task_runner,
|
| + const Closure& task);
|
| +
|
| + // Posts the nestable task |task|, and records its post event.
|
| + void PostWrappedNestableTask(
|
| + const scoped_refptr<SequencedTaskRunner>& task_runner,
|
| + const Closure& task);
|
| +
|
| + // Posts the delayed non-nestable task |task|, and records its post event.
|
| + void PostWrappedDelayedNonNestableTask(
|
| + const scoped_refptr<SequencedTaskRunner>& task_runner,
|
| + const Closure& task,
|
| + TimeDelta delay);
|
| +
|
| + // Posts |task_count| non-nestable tasks.
|
| + void PostNonNestableTasks(
|
| + const scoped_refptr<SequencedTaskRunner>& task_runner,
|
| + int task_count);
|
| +
|
| + const std::vector<TaskEvent>& GetTaskEvents() const;
|
| +
|
| + private:
|
| + friend class RefCountedThreadSafe<SequencedTaskTracker>;
|
| +
|
| + ~SequencedTaskTracker();
|
| +
|
| + // A task which runs |task|, recording the start and end events.
|
| + void RunTask(const Closure& task, int task_i);
|
| +
|
| + // Records a post event for task |i|. The owner is expected to be holding
|
| + // |lock_| (unlike |TaskStarted| and |TaskEnded|).
|
| + void TaskPosted(int i);
|
| +
|
| + // Records a start event for task |i|.
|
| + void TaskStarted(int i);
|
| +
|
| + // Records a end event for task |i|.
|
| + void TaskEnded(int i);
|
| +
|
| + // Protects events_ and next_post_i_.
|
| + Lock lock_;
|
| +
|
| + // The events as they occurred for each task (protected by lock_).
|
| + std::vector<TaskEvent> events_;
|
| +
|
| + // The ordinal to be used for the next task-posting task (protected by
|
| + // lock_).
|
| + int next_post_i_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(SequencedTaskTracker);
|
| +};
|
| +
|
| +void PrintTo(const TaskEvent& event, std::ostream* os);
|
| +
|
| +void SleepForOneSecond();
|
| +
|
| +// Checks the non-nestable task invariants for all tasks in |events|.
|
| +//
|
| +// The invariants are:
|
| +// 1) Events started and ended in the same order that they were posted.
|
| +// 2) Events for an individual tasks occur in the order {POST, START, END},
|
| +// and there is only one instance of each event type for a task.
|
| +// 3) The only events between a task's START and END events are the POSTs of
|
| +// other tasks. I.e. tasks were run sequentially, not interleaved.
|
| +::testing::AssertionResult CheckNonNestableInvariants(
|
| + const std::vector<TaskEvent>& events,
|
| + int task_count);
|
| +
|
| +} // namespace internal
|
| +
|
| +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);
|
| +
|
| +// This test posts N non-nestable tasks in sequence, and expects them to run
|
| +// in FIFO order, with no part of any two tasks' execution
|
| +// overlapping. I.e. that each task starts only after the previously-posted
|
| +// one has finished.
|
| +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));
|
| +}
|
| +
|
| +// This test posts N nestable tasks in sequence. It has the same expectations
|
| +// as SequentialNonNestable because even though the tasks are nestable, they
|
| +// will not be run nestedly in this case.
|
| +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));
|
| +}
|
| +
|
| +// This test posts non-nestable tasks in order of increasing delay, and checks
|
| +// that that the tasks are run in FIFO order and that there is no execution
|
| +// overlap whatsoever between any two tasks.
|
| +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));
|
| +}
|
| +
|
| +// This test posts a fast, non-nestable task from within each of a number of
|
| +// slow, non-nestable tasks and checks that they all run in the sequence they
|
| +// were posted in and that there is no execution overlap whatsoever.
|
| +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)));
|
| +}
|
| +
|
| +// TODO(francoisk777@gmail.com) Add a test, similiar to the above, which runs
|
| +// some tasked nestedly (which should be implemented in the test
|
| +// delegate). Also add, to the the test delegate, a predicate which checks
|
| +// whether the implementation supports nested tasks.
|
| +//
|
| +
|
| +REGISTER_TYPED_TEST_CASE_P(SequencedTaskRunnerTest,
|
| + SequentialNonNestable,
|
| + SequentialNestable,
|
| + SequentialDelayedNonNestable,
|
| + NonNestablePostFromNonNestableTask);
|
| +
|
| +} // namespace base
|
| +
|
| +#endif // BASE_TASK_RUNNER_TEST_TEMPLATE_H_
|
|
|
| Property changes on: base/test/sequenced_task_runner_test_template.h
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|