1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/test/sequenced_task_runner_test_template.h"
9 #include "base/location.h"
15 TaskEvent::TaskEvent(int i
, Type type
)
19 SequencedTaskTracker::SequencedTaskTracker()
22 task_end_cv_(&lock_
) {
25 void SequencedTaskTracker::PostWrappedNonNestableTask(
26 const scoped_refptr
<SequencedTaskRunner
>& task_runner
,
27 const Closure
& task
) {
28 AutoLock
event_lock(lock_
);
29 const int post_i
= next_post_i_
++;
30 Closure wrapped_task
= Bind(&SequencedTaskTracker::RunTask
, this,
32 task_runner
->PostNonNestableTask(FROM_HERE
, wrapped_task
);
36 void SequencedTaskTracker::PostWrappedNestableTask(
37 const scoped_refptr
<SequencedTaskRunner
>& task_runner
,
38 const Closure
& task
) {
39 AutoLock
event_lock(lock_
);
40 const int post_i
= next_post_i_
++;
41 Closure wrapped_task
= Bind(&SequencedTaskTracker::RunTask
, this,
43 task_runner
->PostTask(FROM_HERE
, wrapped_task
);
47 void SequencedTaskTracker::PostWrappedDelayedNonNestableTask(
48 const scoped_refptr
<SequencedTaskRunner
>& task_runner
,
51 AutoLock
event_lock(lock_
);
52 const int post_i
= next_post_i_
++;
53 Closure wrapped_task
= Bind(&SequencedTaskTracker::RunTask
, this,
55 task_runner
->PostNonNestableDelayedTask(FROM_HERE
, wrapped_task
, delay
);
59 void SequencedTaskTracker::PostNonNestableTasks(
60 const scoped_refptr
<SequencedTaskRunner
>& task_runner
,
62 for (int i
= 0; i
< task_count
; ++i
) {
63 PostWrappedNonNestableTask(task_runner
, Closure());
67 void SequencedTaskTracker::RunTask(const Closure
& task
, int task_i
) {
74 void SequencedTaskTracker::TaskPosted(int i
) {
75 // Caller must own |lock_|.
76 events_
.push_back(TaskEvent(i
, TaskEvent::POST
));
79 void SequencedTaskTracker::TaskStarted(int i
) {
81 events_
.push_back(TaskEvent(i
, TaskEvent::START
));
84 void SequencedTaskTracker::TaskEnded(int i
) {
86 events_
.push_back(TaskEvent(i
, TaskEvent::END
));
88 task_end_cv_
.Signal();
91 const std::vector
<TaskEvent
>&
92 SequencedTaskTracker::GetTaskEvents() const {
96 void SequencedTaskTracker::WaitForCompletedTasks(int count
) {
98 while (task_end_count_
< count
)
102 SequencedTaskTracker::~SequencedTaskTracker() {
105 void PrintTo(const TaskEvent
& event
, std::ostream
* os
) {
106 *os
<< "(i=" << event
.i
<< ", type=";
107 switch (event
.type
) {
108 case TaskEvent::POST
: *os
<< "POST"; break;
109 case TaskEvent::START
: *os
<< "START"; break;
110 case TaskEvent::END
: *os
<< "END"; break;
117 // Returns the task ordinals for the task event type |type| in the order that
118 // they were recorded.
119 std::vector
<int> GetEventTypeOrder(const std::vector
<TaskEvent
>& events
,
120 TaskEvent::Type type
) {
121 std::vector
<int> tasks
;
122 std::vector
<TaskEvent
>::const_iterator event
;
123 for (event
= events
.begin(); event
!= events
.end(); ++event
) {
124 if (event
->type
== type
)
125 tasks
.push_back(event
->i
);
130 // Returns all task events for task |task_i|.
131 std::vector
<TaskEvent::Type
> GetEventsForTask(
132 const std::vector
<TaskEvent
>& events
,
134 std::vector
<TaskEvent::Type
> task_event_orders
;
135 std::vector
<TaskEvent
>::const_iterator event
;
136 for (event
= events
.begin(); event
!= events
.end(); ++event
) {
137 if (event
->i
== task_i
)
138 task_event_orders
.push_back(event
->type
);
140 return task_event_orders
;
143 // Checks that the task events for each task in |events| occur in the order
144 // {POST, START, END}, and that there is only one instance of each event type
146 ::testing::AssertionResult
CheckEventOrdersForEachTask(
147 const std::vector
<TaskEvent
>& events
,
149 std::vector
<TaskEvent::Type
> expected_order
;
150 expected_order
.push_back(TaskEvent::POST
);
151 expected_order
.push_back(TaskEvent::START
);
152 expected_order
.push_back(TaskEvent::END
);
154 // This is O(n^2), but it runs fast enough currently so is not worth
156 for (int i
= 0; i
< task_count
; ++i
) {
157 const std::vector
<TaskEvent::Type
> task_events
=
158 GetEventsForTask(events
, i
);
159 if (task_events
!= expected_order
) {
160 return ::testing::AssertionFailure()
161 << "Events for task " << i
<< " are out of order; expected: "
162 << ::testing::PrintToString(expected_order
) << "; actual: "
163 << ::testing::PrintToString(task_events
);
166 return ::testing::AssertionSuccess();
169 // Checks that no two tasks were running at the same time. I.e. the only
170 // events allowed between the START and END of a task are the POSTs of other
172 ::testing::AssertionResult
CheckNoTaskRunsOverlap(
173 const std::vector
<TaskEvent
>& events
) {
174 // If > -1, we're currently inside a START, END pair.
175 int current_task_i
= -1;
177 std::vector
<TaskEvent
>::const_iterator event
;
178 for (event
= events
.begin(); event
!= events
.end(); ++event
) {
179 bool spurious_event_found
= false;
181 if (current_task_i
== -1) { // Not inside a START, END pair.
182 switch (event
->type
) {
183 case TaskEvent::POST
:
185 case TaskEvent::START
:
186 current_task_i
= event
->i
;
189 spurious_event_found
= true;
193 } else { // Inside a START, END pair.
194 bool interleaved_task_detected
= false;
196 switch (event
->type
) {
197 case TaskEvent::POST
:
198 if (event
->i
== current_task_i
)
199 spurious_event_found
= true;
201 case TaskEvent::START
:
202 interleaved_task_detected
= true;
205 if (event
->i
!= current_task_i
)
206 interleaved_task_detected
= true;
212 if (interleaved_task_detected
) {
213 return ::testing::AssertionFailure()
214 << "Found event " << ::testing::PrintToString(*event
)
215 << " between START and END events for task " << current_task_i
216 << "; event dump: " << ::testing::PrintToString(events
);
220 if (spurious_event_found
) {
221 const int event_i
= event
- events
.begin();
222 return ::testing::AssertionFailure()
223 << "Spurious event " << ::testing::PrintToString(*event
)
224 << " at position " << event_i
<< "; event dump: "
225 << ::testing::PrintToString(events
);
229 return ::testing::AssertionSuccess();
234 ::testing::AssertionResult
CheckNonNestableInvariants(
235 const std::vector
<TaskEvent
>& events
,
237 const std::vector
<int> post_order
=
238 GetEventTypeOrder(events
, TaskEvent::POST
);
239 const std::vector
<int> start_order
=
240 GetEventTypeOrder(events
, TaskEvent::START
);
241 const std::vector
<int> end_order
=
242 GetEventTypeOrder(events
, TaskEvent::END
);
244 if (start_order
!= post_order
) {
245 return ::testing::AssertionFailure()
246 << "Expected START order (which equals actual POST order): \n"
247 << ::testing::PrintToString(post_order
)
248 << "\n Actual START order:\n"
249 << ::testing::PrintToString(start_order
);
252 if (end_order
!= post_order
) {
253 return ::testing::AssertionFailure()
254 << "Expected END order (which equals actual POST order): \n"
255 << ::testing::PrintToString(post_order
)
256 << "\n Actual END order:\n"
257 << ::testing::PrintToString(end_order
);
260 const ::testing::AssertionResult result
=
261 CheckEventOrdersForEachTask(events
, task_count
);
265 return CheckNoTaskRunsOverlap(events
);
268 } // namespace internal