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 |