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,254 @@ |
+// 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. Here's how you use it to test your |
+// implementation. |
+// |
+// 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 <algorithm> |
+#include <vector> |
+ |
+#include "base/basictypes.h" |
+#include "base/bind.h" |
+#include "base/memory/ref_counted.h" |
+#include "base/sequenced_task_runner.h" |
+#include "base/synchronization/lock.h" |
+#include "base/tracked_objects.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace base { |
+ |
+namespace internal { |
+ |
+// Utility class used in the tests below. |
+class SequencedTaskTracker : public RefCountedThreadSafe<SequencedTaskTracker> { |
+ public: |
+ SequencedTaskTracker(); |
+ |
+ int GetNextPostOrdinal(); |
+ |
+ void TaskPosted(int i); |
+ void TaskStarted(int i); |
+ void TaskEnded(int i); |
+ |
+ const std::vector<int>& GetPostOrder() const; |
+ const std::vector<int>& GetStartOrder() const; |
+ const std::vector<int>& GetEndOrder() const; |
+ |
+ void FastTask(int i); |
+ void SlowTask(int i); |
+ |
+ // Task which posts a fast, non-nestable task. |
+ void PostFastNonNestableFromSlowNonNestable( |
+ scoped_refptr<SequencedTaskRunner> task_runner, |
+ const int base_status_i, |
+ const int child_count); |
+ |
+ private: |
+ friend class RefCountedThreadSafe<SequencedTaskTracker>; |
+ |
+ ~SequencedTaskTracker(); |
+ |
+ public: |
+ std::vector<int> post_events_; |
+ mutable Lock post_lock_; |
+ |
+ private: |
+ std::vector<int> start_events_; |
+ mutable Lock start_lock_; |
+ |
+ std::vector<int> end_events_; |
+ mutable Lock end_lock_; |
+ |
+ int next_post_i_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SequencedTaskTracker); |
+}; |
+ |
+} // 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. |
+// |
+// It checks that task0 was done by the time task1 started, and task2 only |
+// started after task1 had executed to completion, etc. |
+// |
+// The first task it starts is a slow one which runs for a second, giving the |
+// subsequent ones plenty of time to run if the implementation fails to |
+// enforce the non-nestable property. |
+TYPED_TEST_P(SequencedTaskRunnerTest, SequentialNonNestable) { |
+ const int task_count = 1000; |
+ |
+ this->delegate_.StartTaskRunner(); |
+ scoped_refptr<SequencedTaskRunner> task_runner = |
+ this->delegate_.GetTaskRunner(); |
+ |
+ for (int i = 0; i < task_count; ++i) { |
+ Closure task; |
+ if (i == 0) { |
+ task = Bind(&internal::SequencedTaskTracker::SlowTask, |
+ this->task_tracker_, i); |
+ } else { |
+ task = Bind(&internal::SequencedTaskTracker::FastTask, |
+ this->task_tracker_, i); |
+ } |
+ this->task_tracker_->TaskPosted(i); |
+ task_runner->PostNonNestableTask(FROM_HERE, task); |
+ } |
+ |
+ this->delegate_.StopTaskRunner(); |
+ |
+ EXPECT_EQ(this->task_tracker_->GetPostOrder(), |
+ this->task_tracker_->GetStartOrder()); |
+ EXPECT_EQ(this->task_tracker_->GetEndOrder(), |
+ this->task_tracker_->GetStartOrder()); |
+} |
+ |
+// This test posts N nestable tasks in sequence, and expects them to run in |
+// FIFO order; overlapping execution is allowed. |
+// |
+// It checks only that task_i had started by the time task_i+1 started, for |
+// increasing values of i. Thus it verifies the SequencedTaskRunner guarantee |
+// that nested tasks are run in FIFO order. |
+// |
+// The first task it starts is a slow one which runs for a second, giving the |
+// subsequent ones plenty of time to run in if the implementation fails to |
+// enforce the FIFO property for nestable tasks. |
+TYPED_TEST_P(SequencedTaskRunnerTest, FAILS_SequentialNestable) { |
+ const int task_count = 10; |
+ |
+ this->delegate_.StartTaskRunner(); |
+ scoped_refptr<SequencedTaskRunner> task_runner = |
+ this->delegate_.GetTaskRunner(); |
+ |
+ for (int i = 0; i < task_count; ++i) { |
+ Closure task; |
+ if (i == 0) { |
+ task = Bind(&internal::SequencedTaskTracker::SlowTask, |
+ this->task_tracker_, i); |
+ } else { |
+ task = Bind(&internal::SequencedTaskTracker::FastTask, |
+ this->task_tracker_, i); |
+ } |
+ this->task_tracker_->TaskPosted(i); |
+ task_runner->PostTask(FROM_HERE, task); |
+ } |
+ |
+ this->delegate_.StopTaskRunner(); |
+ |
+ const std::vector<int>& post_events = this->task_tracker_->GetPostOrder(); |
+ const std::vector<int>& end_events = this->task_tracker_->GetEndOrder(); |
+ |
+ EXPECT_EQ(post_events, this->task_tracker_->GetStartOrder()); |
+ |
+ // Check that all posted tasks finished. |
+ for (std::size_t i = 0; i < post_events.size(); ++i) { |
+ EXPECT_NE(std::find(end_events.begin(), end_events.end(), post_events[i]), |
+ end_events.end()); |
+ } |
+} |
+ |
+// 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. |
+// |
+// If there are 10 tasks, task1 is posted first with a delay of zero, followed |
+// by task2 with a delay of, say, 1, and so forth, until task10 is posted with |
+// a delay of 10. It then checks that task2 started after task1, and only |
+// after task1 had finished, and so forth. |
+TYPED_TEST_P(SequencedTaskRunnerTest, SequentialDelayedNonNestable) { |
+ const int task_count = 20; |
+ const int delay_increment_ms = 50; |
+ |
+ this->delegate_.StartTaskRunner(); |
+ scoped_refptr<SequencedTaskRunner> task_runner = |
+ this->delegate_.GetTaskRunner(); |
+ |
+ for (int i = 0; i < task_count; ++i) { |
+ Closure task = Bind(&internal::SequencedTaskTracker::FastTask, |
+ this->task_tracker_, i); |
+ this->task_tracker_->TaskPosted(i); |
+ task_runner->PostNonNestableDelayedTask( |
+ FROM_HERE, |
+ task, |
+ TimeDelta::FromMilliseconds(delay_increment_ms * i)); |
+ } |
+ |
+ this->delegate_.StopTaskRunner(); |
+ |
+ EXPECT_EQ(this->task_tracker_->GetPostOrder(), |
+ this->task_tracker_->GetStartOrder()); |
+ EXPECT_EQ(this->task_tracker_->GetStartOrder(), |
+ this->task_tracker_->GetEndOrder()); |
+} |
+ |
+// 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 = 1000; |
+ const int children_per_parent = 2; |
+ |
+ this->delegate_.StartTaskRunner(); |
+ scoped_refptr<SequencedTaskRunner> task_runner = |
+ this->delegate_.GetTaskRunner(); |
+ |
+ const int end = parent_count; |
+ for (int i = 0; i < end; ++i) { |
+ base::PlatformThread::YieldCurrentThread(); |
+ AutoLock post_lock(this->task_tracker_->post_lock_); |
+ const int post_i = this->task_tracker_->GetNextPostOrdinal(); |
+ Closure task = Bind( |
+ &internal::SequencedTaskTracker::PostFastNonNestableFromSlowNonNestable, |
+ this->task_tracker_, |
+ task_runner, |
+ post_i, |
+ children_per_parent); |
+ this->task_tracker_->post_events_.push_back(post_i); |
+ task_runner->PostNonNestableTask(FROM_HERE, task); |
Francois
2012/03/18 16:28:29
The loop body is messy, but I want to hear your co
|
+ } |
+ |
+ this->delegate_.StopTaskRunner(); |
+ |
+ EXPECT_EQ(this->task_tracker_->GetPostOrder(), |
+ this->task_tracker_->GetStartOrder()); |
+ EXPECT_EQ(this->task_tracker_->GetEndOrder(), |
+ this->task_tracker_->GetStartOrder()); |
+} |
+ |
+// TODO(francoisk777@gmail.com) Add a test, similiar to the above, which 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, |
+ FAILS_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 |