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,299 @@ |
+// 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 <vector> |
+ |
+#include "base/basictypes.h" |
+#include "base/bind.h" |
+#include "base/memory/ref_counted.h" |
+#include "base/synchronization/lock.h" |
+#include "base/sequenced_task_runner.h" |
+#include "base/tracked_objects.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace base { |
+ |
+// Utility class used in the tests below. |
+class SeqTaskTracker : public RefCountedThreadSafe<SeqTaskTracker> { |
akalin
2012/03/13 07:27:11
SeqTaskTracker -> SequencedTaskTracker (abbreviati
akalin
2012/03/13 07:27:11
put this class in the base::internal namespace
(y
Francois
2012/03/14 15:43:31
Done.
Francois
2012/03/14 15:43:31
Done.
|
+ public: |
+ // Keeps track of a task's run status. I.e. whether it has run to completion |
+ // and whether its predecessor had run to completion by the time it started |
+ // running. |
+ class TaskStatus { |
akalin
2012/03/13 07:27:11
Hmm I think this class may be overkill. I was thi
akalin
2012/03/13 20:00:10
Actually a few corrections. WrapTask should *not*
Francois
2012/03/14 15:43:31
I like your model because it mirrors the task hier
|
+ public: |
+ TaskStatus(); |
+ TaskStatus(const TaskStatus& ts); |
+ TaskStatus& operator=(const TaskStatus& ts); |
+ bool operator==(const TaskStatus& ts) const; |
+ |
+ // Claims ownership of this task status for a task. |
+ bool Claim(); |
+ // Whether the owning task has run to completion yet. |
+ bool Completed() const; |
+ // Whether the previous task (the one which owns the preceding position in |
+ // the task status vector) had finished by the time this one started. |
+ bool PrevCompletedBefore() const; |
+ // Declares that the owning task has run to completion. |
+ void SetCompleted(); |
+ // Declares that the previous task had run to completion by the time the |
+ // owning task started. |
+ void SetPrevCompletedBefore(const bool b); |
+ |
+ private: |
+ mutable Lock lock_; |
+ // Whether this status slot has been claimed by a task yet. |
+ bool claimed_; |
+ bool completed_; |
+ // Whether the owning task has set the "completed" flag. |
+ bool completed_set_; |
+ bool prev_completed_; |
+ // Whether the owning task has set the "previous completed" flag. |
+ bool prev_completed_set_; |
+ }; |
+ |
+ typedef std::vector<TaskStatus> TaskStatuses; |
+ |
+ SeqTaskTracker(); |
+ |
+ // Pre-allocates memory for the non-nestable task statuses. |
+ void SetNonNestableTaskCount(const std::size_t task_count); |
akalin
2012/03/13 07:27:11
remove const (doesn't make sense for value paramet
Francois
2012/03/14 15:43:31
Done. But it does make sense to me :) If something
|
+ |
+ // Pre-allocates memory for the nestable task statuses. |
+ void SetNestableTaskCount(const std::size_t task_count); |
+ |
+ const TaskStatuses& GetNonNestableTaskStatuses() const; |
+ const TaskStatuses& GetNestableTaskStatuses() const; |
+ |
+ // A fast, non-nestable task. |
+ void FastNonNestableTask(int base_status_i); |
+ |
+ // A fast, nestable task. |
+ void FastNestableTask(int parent_task_status_slot); |
+ |
+ // A slow, non-nestable task (sleeps for 1 second). |
+ void SlowNonNestableTask(int base_status_i); |
+ |
+ // Posts a fast, non-nestable task from a slow, non-nestable one. |
+ void PostFastNonNestableFromSlowNonNestable( |
+ scoped_refptr<SequencedTaskRunner> tr, |
akalin
2012/03/13 07:27:11
tr -> task_runner (abbreviations are discouraged)
Francois
2012/03/14 15:43:31
Done.
|
+ const int base_status_i, |
+ const int child_count); |
+ |
+ // Posts a fast, nestable task from a slow, non-nestable one. |
+ void PostFastNestableFromSlowNonNestable( |
+ scoped_refptr<SequencedTaskRunner> tr, |
+ const int base_status_i, |
+ const int child_count); |
+ |
+ private: |
+ friend class RefCountedThreadSafe<SeqTaskTracker>; |
+ |
+ ~SeqTaskTracker(); |
+ |
+ // Finds the lowest-numbered non-nestable task status object, beginning at |
+ // position |search_from|, which has not yet been claimed. |
+ int ClaimNonNestableTaskStatus(const int search_from = 0); |
akalin
2012/03/13 07:27:11
default arguments are prohibited by style guide
Francois
2012/03/14 15:43:31
Done.
|
+ |
+ // Finds the lowest-numbered nestable task status object, beginning at |
+ // position |search_from|, which has not yet been claimed. |
+ int ClaimNestableTaskStatus(const int search_from = 0); |
akalin
2012/03/13 07:27:11
here too
Francois
2012/03/14 15:43:31
Done.
|
+ |
+ TaskStatuses nestable_statuses_; |
+ TaskStatuses non_nestable_statuses_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SeqTaskTracker); |
+}; |
+ |
+std::ostream& operator<<(std::ostream& os, |
akalin
2012/03/13 07:27:11
a ToString() member function is preferred to overl
Francois
2012/03/14 15:43:31
OK, but I added this to customise the output of EX
|
+ const SeqTaskTracker::TaskStatus& ts); |
+ |
+template <typename TaskRunnerTestDelegate> |
+class SequencedTaskRunnerTest : public testing::Test { |
+ protected: |
+ SequencedTaskRunnerTest() : task_tracker_(new SeqTaskTracker()) { |
+ good_task_status_prototype_.SetPrevCompletedBefore(true); |
+ good_task_status_prototype_.SetCompleted(); |
+ } |
+ |
+ const scoped_refptr<SeqTaskTracker> task_tracker_; |
+ TaskRunnerTestDelegate delegate_; |
+ SeqTaskTracker::TaskStatus good_task_status_prototype_; |
+}; |
+ |
+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->task_tracker_->SetNonNestableTaskCount(task_count); |
+ SeqTaskTracker::TaskStatuses expected_statuses( |
+ task_count, |
+ this->good_task_status_prototype_); |
+ |
+ 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(&SeqTaskTracker::SlowNonNestableTask, |
+ this->task_tracker_, i); |
+ } else { |
+ task = Bind(&SeqTaskTracker::FastNonNestableTask, |
+ this->task_tracker_, i); |
+ } |
+ task_runner->PostNonNestableTask(FROM_HERE, task); |
+ } |
+ |
+ this->delegate_.StopTaskRunner(); |
+ |
+ EXPECT_EQ(expected_statuses, |
+ this->task_tracker_->GetNonNestableTaskStatuses()); |
+} |
+ |
+// 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; |
akalin
2012/03/13 07:27:11
if you change the logs in PostDelayed...Task to us
Francois
2012/03/14 15:43:31
Done.
|
+ const int delay_increment_ms = 50; |
+ |
+ this->task_tracker_->SetNonNestableTaskCount(task_count); |
+ SeqTaskTracker::TaskStatuses expected_statuses( |
+ task_count, |
+ this->good_task_status_prototype_); |
+ |
+ this->delegate_.StartTaskRunner(); |
+ scoped_refptr<SequencedTaskRunner> task_runner = |
+ this->delegate_.GetTaskRunner(); |
+ |
+ for (int i = 0; i < task_count; ++i) { |
+ Closure task = Bind(&SeqTaskTracker::FastNonNestableTask, |
+ this->task_tracker_, i); |
+ task_runner->PostNonNestableDelayedTask( |
+ FROM_HERE, |
+ task, |
+ TimeDelta::FromMilliseconds(delay_increment_ms * i)); |
+ } |
+ |
+ this->delegate_.StopTaskRunner(); |
+ |
+ EXPECT_EQ(expected_statuses, |
+ this->task_tracker_->GetNonNestableTaskStatuses()); |
+} |
+ |
+// 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; |
+ const int task_count = parent_count * (children_per_parent + 1); |
+ |
+ this->task_tracker_->SetNonNestableTaskCount(task_count); |
+ SeqTaskTracker::TaskStatuses expected_statuses( |
+ task_count, |
+ this->good_task_status_prototype_); |
+ |
+ this->delegate_.StartTaskRunner(); |
+ scoped_refptr<SequencedTaskRunner> task_runner = |
+ this->delegate_.GetTaskRunner(); |
+ |
+ const int end = parent_count; |
+ for (int i = 0; i < end; ++i) { |
+ Closure task = Bind( |
+ &SeqTaskTracker::PostFastNonNestableFromSlowNonNestable, |
+ this->task_tracker_, |
+ task_runner, |
+ i, |
+ children_per_parent); |
+ DLOG(INFO) << "XXX Posted parent task " << i; |
+ task_runner->PostNonNestableTask(FROM_HERE, task); |
+ } |
+ |
+ this->delegate_.StopTaskRunner(); |
+ |
+ EXPECT_EQ(expected_statuses, |
+ this->task_tracker_->GetNonNestableTaskStatuses()); |
+} |
+ |
+// This test posts a number of fast, nestable tasks from within each of a |
+// number of slow, non-nestable tasks and checks that the non-nestable ones |
+// all run in the sequence they were posted in and that there is no execution |
+// overlap whatsoever. |
+TYPED_TEST_P(SequencedTaskRunnerTest, |
+ NestablePostFromNonNestableTask) { |
+ const int parent_count = 500; |
+ const int children_per_parent = 2; |
+ |
+ this->task_tracker_->SetNonNestableTaskCount(parent_count); |
+ SeqTaskTracker::TaskStatuses expected_non_nestable_statuses( |
+ parent_count, |
+ this->good_task_status_prototype_); |
+ this->task_tracker_->SetNestableTaskCount(children_per_parent * parent_count); |
+ SeqTaskTracker::TaskStatuses expected_nestable_statuses( |
+ children_per_parent * parent_count, |
+ this->good_task_status_prototype_); |
+ |
+ this->delegate_.StartTaskRunner(); |
+ scoped_refptr<SequencedTaskRunner> task_runner = |
+ this->delegate_.GetTaskRunner(); |
+ |
+ const int end = parent_count; |
+ for (int i = 0; i < end; ++i) { |
+ Closure task = Bind( |
+ &SeqTaskTracker::PostFastNestableFromSlowNonNestable, |
+ this->task_tracker_, |
+ task_runner, |
+ i, |
+ children_per_parent); |
+ task_runner->PostNonNestableTask(FROM_HERE, task); |
+ } |
+ |
+ this->delegate_.StopTaskRunner(); |
+ |
+ EXPECT_EQ(expected_non_nestable_statuses, |
+ this->task_tracker_->GetNonNestableTaskStatuses()); |
+ EXPECT_EQ(expected_nestable_statuses, |
+ this->task_tracker_->GetNestableTaskStatuses()); |
+} |
+ |
akalin
2012/03/13 07:27:11
Add a TODO for a test similar to the above, but ha
Francois
2012/03/14 15:43:31
Done.
|
+REGISTER_TYPED_TEST_CASE_P(SequencedTaskRunnerTest, |
+ SequentialNonNestable, |
+ SequentialDelayedNonNestable, |
+ NonNestablePostFromNonNestableTask, |
+ NestablePostFromNonNestableTask); |
+ |
+} // namespace base |
+ |
+#endif //#define BASE_TASK_RUNNER_TEST_TEMPLATE_H_ |
akalin
2012/03/13 07:27:11
no '#define' in comment
Francois
2012/03/14 15:43:31
Done.
|
Property changes on: base/test/sequenced_task_runner_test_template.h |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |