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() : next_post_i_(0) {
22 void SequencedTaskTracker::PostWrappedNonNestableTask(
23 const scoped_refptr
<SequencedTaskRunner
>& task_runner
,
24 const Closure
& task
) {
25 AutoLock
event_lock(lock_
);
26 const int post_i
= next_post_i_
++;
27 Closure wrapped_task
= Bind(&SequencedTaskTracker::RunTask
, this,
29 task_runner
->PostNonNestableTask(FROM_HERE
, wrapped_task
);
33 void SequencedTaskTracker::PostWrappedNestableTask(
34 const scoped_refptr
<SequencedTaskRunner
>& task_runner
,
35 const Closure
& task
) {
36 AutoLock
event_lock(lock_
);
37 const int post_i
= next_post_i_
++;
38 Closure wrapped_task
= Bind(&SequencedTaskTracker::RunTask
, this,
40 task_runner
->PostTask(FROM_HERE
, wrapped_task
);
44 void SequencedTaskTracker::PostWrappedDelayedNonNestableTask(
45 const scoped_refptr
<SequencedTaskRunner
>& task_runner
,
48 AutoLock
event_lock(lock_
);
49 const int post_i
= next_post_i_
++;
50 Closure wrapped_task
= Bind(&SequencedTaskTracker::RunTask
, this,
52 task_runner
->PostNonNestableDelayedTask(FROM_HERE
, wrapped_task
, delay
);
56 void SequencedTaskTracker::PostNonNestableTasks(
57 const scoped_refptr
<SequencedTaskRunner
>& task_runner
,
59 for (int i
= 0; i
< task_count
; ++i
) {
60 PostWrappedNonNestableTask(task_runner
, Closure());
64 void SequencedTaskTracker::RunTask(const Closure
& task
, int task_i
) {
71 void SequencedTaskTracker::TaskPosted(int i
) {
72 // Caller must own |lock_|.
73 events_
.push_back(TaskEvent(i
, TaskEvent::POST
));
76 void SequencedTaskTracker::TaskStarted(int i
) {
78 events_
.push_back(TaskEvent(i
, TaskEvent::START
));
81 void SequencedTaskTracker::TaskEnded(int i
) {
83 events_
.push_back(TaskEvent(i
, TaskEvent::END
));
86 const std::vector
<TaskEvent
>&
87 SequencedTaskTracker::GetTaskEvents() const {
91 SequencedTaskTracker::~SequencedTaskTracker() {
94 void PrintTo(const TaskEvent
& event
, std::ostream
* os
) {
95 *os
<< "(i=" << event
.i
<< ", type=";
97 case TaskEvent::POST
: *os
<< "POST"; break;
98 case TaskEvent::START
: *os
<< "START"; break;
99 case TaskEvent::END
: *os
<< "END"; break;
106 // Returns the task ordinals for the task event type |type| in the order that
107 // they were recorded.
108 std::vector
<int> GetEventTypeOrder(const std::vector
<TaskEvent
>& events
,
109 TaskEvent::Type type
) {
110 std::vector
<int> tasks
;
111 std::vector
<TaskEvent
>::const_iterator event
;
112 for (event
= events
.begin(); event
!= events
.end(); ++event
) {
113 if (event
->type
== type
)
114 tasks
.push_back(event
->i
);
119 // Returns all task events for task |task_i|.
120 std::vector
<TaskEvent::Type
> GetEventsForTask(
121 const std::vector
<TaskEvent
>& events
,
123 std::vector
<TaskEvent::Type
> task_event_orders
;
124 std::vector
<TaskEvent
>::const_iterator event
;
125 for (event
= events
.begin(); event
!= events
.end(); ++event
) {
126 if (event
->i
== task_i
)
127 task_event_orders
.push_back(event
->type
);
129 return task_event_orders
;
132 // Checks that the task events for each task in |events| occur in the order
133 // {POST, START, END}, and that there is only one instance of each event type
135 ::testing::AssertionResult
CheckEventOrdersForEachTask(
136 const std::vector
<TaskEvent
>& events
,
138 std::vector
<TaskEvent::Type
> expected_order
;
139 expected_order
.push_back(TaskEvent::POST
);
140 expected_order
.push_back(TaskEvent::START
);
141 expected_order
.push_back(TaskEvent::END
);
143 // This is O(n^2), but it runs fast enough currently so is not worth
145 for (int i
= 0; i
< task_count
; ++i
) {
146 const std::vector
<TaskEvent::Type
> task_events
=
147 GetEventsForTask(events
, i
);
148 if (task_events
!= expected_order
) {
149 return ::testing::AssertionFailure()
150 << "Events for task " << i
<< " are out of order; expected: "
151 << ::testing::PrintToString(expected_order
) << "; actual: "
152 << ::testing::PrintToString(task_events
);
155 return ::testing::AssertionSuccess();
158 // Checks that no two tasks were running at the same time. I.e. the only
159 // events allowed between the START and END of a task are the POSTs of other
161 ::testing::AssertionResult
CheckNoTaskRunsOverlap(
162 const std::vector
<TaskEvent
>& events
) {
163 // If > -1, we're currently inside a START, END pair.
164 int current_task_i
= -1;
166 std::vector
<TaskEvent
>::const_iterator event
;
167 for (event
= events
.begin(); event
!= events
.end(); ++event
) {
168 bool spurious_event_found
= false;
170 if (current_task_i
== -1) { // Not inside a START, END pair.
171 switch (event
->type
) {
172 case TaskEvent::POST
:
174 case TaskEvent::START
:
175 current_task_i
= event
->i
;
178 spurious_event_found
= true;
182 } else { // Inside a START, END pair.
183 bool interleaved_task_detected
= false;
185 switch (event
->type
) {
186 case TaskEvent::POST
:
187 if (event
->i
== current_task_i
)
188 spurious_event_found
= true;
190 case TaskEvent::START
:
191 interleaved_task_detected
= true;
194 if (event
->i
!= current_task_i
)
195 interleaved_task_detected
= true;
201 if (interleaved_task_detected
) {
202 return ::testing::AssertionFailure()
203 << "Found event " << ::testing::PrintToString(*event
)
204 << " between START and END events for task " << current_task_i
205 << "; event dump: " << ::testing::PrintToString(events
);
209 if (spurious_event_found
) {
210 const int event_i
= event
- events
.begin();
211 return ::testing::AssertionFailure()
212 << "Spurious event " << ::testing::PrintToString(*event
)
213 << " at position " << event_i
<< "; event dump: "
214 << ::testing::PrintToString(events
);
218 return ::testing::AssertionSuccess();
223 ::testing::AssertionResult
CheckNonNestableInvariants(
224 const std::vector
<TaskEvent
>& events
,
226 const std::vector
<int> post_order
=
227 GetEventTypeOrder(events
, TaskEvent::POST
);
228 const std::vector
<int> start_order
=
229 GetEventTypeOrder(events
, TaskEvent::START
);
230 const std::vector
<int> end_order
=
231 GetEventTypeOrder(events
, TaskEvent::END
);
233 if (start_order
!= post_order
) {
234 return ::testing::AssertionFailure()
235 << "Expected START order (which equals actual POST order): \n"
236 << ::testing::PrintToString(post_order
)
237 << "\n Actual START order:\n"
238 << ::testing::PrintToString(start_order
);
241 if (end_order
!= post_order
) {
242 return ::testing::AssertionFailure()
243 << "Expected END order (which equals actual POST order): \n"
244 << ::testing::PrintToString(post_order
)
245 << "\n Actual END order:\n"
246 << ::testing::PrintToString(end_order
);
249 const ::testing::AssertionResult result
=
250 CheckEventOrdersForEachTask(events
, task_count
);
254 return CheckNoTaskRunsOverlap(events
);
257 } // namespace internal