|
OLD | NEW |
---|---|
(Empty) | |
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. | |
4 | |
5 #include "base/test/sequenced_task_runner_test_template.h" | |
6 | |
7 #include <ostream> | |
Francois
2012/03/26 09:33:21
For SequencedTaskTracker::TaskEvent::PrintTo, whic
| |
8 | |
9 #include "base/tracked_objects.h" | |
akalin
2012/03/26 18:44:08
looks like this should be base/location.h (this ch
Francois
2012/03/28 14:32:42
Done.
| |
10 | |
11 namespace base { | |
12 | |
13 namespace internal { | |
14 | |
15 SequencedTaskTracker::TaskEvent::TaskEvent(int i_in, Type type_in) | |
akalin
2012/03/26 18:44:08
don't use _in, just name them the same; C++'s vari
Francois
2012/03/28 14:32:42
Done.
| |
16 : i(i_in), type(type_in) { | |
17 } | |
18 | |
19 SequencedTaskTracker::SequencedTaskTracker() : next_post_i_(0) { | |
20 } | |
21 | |
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, | |
28 task, post_i); | |
29 task_runner->PostNonNestableTask(FROM_HERE, wrapped_task); | |
30 TaskPosted(post_i); | |
31 } | |
32 | |
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, | |
39 task, post_i); | |
40 task_runner->PostTask(FROM_HERE, wrapped_task); | |
41 TaskPosted(post_i); | |
42 } | |
43 | |
44 void SequencedTaskTracker::PostWrappedDelayedNonNestableTask( | |
45 const scoped_refptr<SequencedTaskRunner>& task_runner, | |
46 const Closure& task, | |
47 TimeDelta delay) { | |
48 AutoLock event_lock(lock_); | |
49 const int post_i = next_post_i_++; | |
50 Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this, | |
51 task, post_i); | |
52 task_runner->PostNonNestableDelayedTask(FROM_HERE, wrapped_task, delay); | |
53 TaskPosted(post_i); | |
54 } | |
55 | |
56 void SequencedTaskTracker::PostNonNestableTasks( | |
57 const scoped_refptr<SequencedTaskRunner>& task_runner, | |
58 int task_count) { | |
59 for (int i = 0; i < task_count; ++i) { | |
60 PostWrappedNonNestableTask(task_runner, Closure()); | |
61 } | |
62 } | |
63 | |
64 void SequencedTaskTracker::RunTask(const Closure& task, int task_i) { | |
65 TaskStarted(task_i); | |
66 if (!task.is_null()) | |
67 task.Run(); | |
68 TaskEnded(task_i); | |
69 } | |
70 | |
71 void SequencedTaskTracker::TaskPosted(int i) { | |
72 // Caller must own |lock_|. | |
73 events_.push_back(TaskEvent(i, TaskEvent::POST)); | |
74 } | |
75 | |
76 void SequencedTaskTracker::TaskStarted(int i) { | |
77 AutoLock lock(lock_); | |
78 events_.push_back(TaskEvent(i, TaskEvent::START)); | |
79 } | |
80 | |
81 void SequencedTaskTracker::TaskEnded(int i) { | |
82 AutoLock lock(lock_); | |
83 events_.push_back(TaskEvent(i, TaskEvent::END)); | |
84 } | |
85 | |
86 const std::vector<SequencedTaskTracker::TaskEvent>& | |
87 SequencedTaskTracker::GetTaskEvents() const { | |
88 return events_; | |
89 } | |
90 | |
91 SequencedTaskTracker::~SequencedTaskTracker() { | |
92 } | |
93 | |
94 void PrintTo(const SequencedTaskTracker::TaskEvent& event, std::ostream* os) { | |
95 *os << "(i=" << event.i << ", type="; | |
96 switch (event.type) { | |
97 case SequencedTaskTracker::TaskEvent::POST: *os << "POST"; break; | |
98 case SequencedTaskTracker::TaskEvent::START: *os << "START"; break; | |
99 case SequencedTaskTracker::TaskEvent::END: *os << "END"; break; | |
100 } | |
101 *os << ")"; | |
102 } | |
103 | |
104 void SleepForOneSecond() { | |
105 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); | |
106 } | |
107 | |
108 typedef SequencedTaskTracker::TaskEvent TaskEvent; | |
109 | |
110 namespace { | |
111 | |
112 // Returns the task ordinals for the task event type |type| in the order that | |
113 // they were recorded. | |
114 std::vector<int> GetEventTypeOrder(const std::vector<TaskEvent>& events, | |
115 TaskEvent::Type type) { | |
116 std::vector<int> tasks; | |
117 std::vector<TaskEvent>::const_iterator event; | |
118 for (event = events.begin(); event != events.end(); ++event) { | |
119 if (event->type == type) | |
120 tasks.push_back(event->i); | |
121 } | |
122 return tasks; | |
123 } | |
124 | |
125 // Returns all task events for task |task_i|. | |
126 std::vector<TaskEvent::Type> GetEventsForTask( | |
127 const std::vector<TaskEvent>& events, | |
128 int task_i) { | |
129 std::vector<TaskEvent::Type> task_event_orders; | |
130 std::vector<TaskEvent>::const_iterator event; | |
131 for (event = events.begin(); event != events.end(); ++event) { | |
132 if (event->i == task_i) | |
133 task_event_orders.push_back(event->type); | |
134 } | |
135 return task_event_orders; | |
136 } | |
137 | |
138 // Checks that the task events for each task in |events| occur in the order | |
139 // {POST, START, END}, and that there is only one instance of each event type | |
140 // per task. | |
141 ::testing::AssertionResult CheckEventOrdersForEachTask( | |
142 const std::vector<TaskEvent>& events, | |
143 int task_count) { | |
144 std::vector<TaskEvent::Type> expected_order; | |
145 expected_order.push_back(TaskEvent::POST); | |
146 expected_order.push_back(TaskEvent::START); | |
147 expected_order.push_back(TaskEvent::END); | |
148 | |
149 for (int i = 0; i < task_count; ++i) { | |
akalin
2012/03/26 18:44:08
This takes n^2 time, which isn't great but probabl
Francois
2012/03/28 14:32:42
Done.
| |
150 const std::vector<TaskEvent::Type> task_events = | |
151 GetEventsForTask(events, i); | |
152 if (task_events != expected_order) { | |
153 return ::testing::AssertionFailure() | |
154 << "Events for task " << i << " are out of order; expected: " | |
155 << ::testing::PrintToString(expected_order) << "; actual: " | |
156 << ::testing::PrintToString(task_events); | |
157 } | |
158 } | |
159 return ::testing::AssertionSuccess(); | |
160 } | |
161 | |
162 // Checks that no two tasks were running at the same time. I.e. the only | |
163 // events allowed between the START and END of a task are the POSTs of other | |
164 // tasks. | |
165 ::testing::AssertionResult CheckNoTaskRunsOverlap( | |
166 const std::vector<TaskEvent>& events) { | |
167 // If > -1, we're currently inside a START, END pair. | |
168 int current_task_i = -1; | |
169 | |
170 std::vector<TaskEvent>::const_iterator event; | |
171 for (event = events.begin(); event != events.end(); ++event) { | |
172 bool spurious_event_found = false; | |
173 | |
174 if (current_task_i == -1) { // Not inside a START, END pair. | |
175 switch (event->type) { | |
176 case TaskEvent::POST: | |
177 break; | |
178 case TaskEvent::START: | |
179 current_task_i = event->i; | |
180 break; | |
181 case TaskEvent::END: | |
182 spurious_event_found = true; | |
183 break; | |
184 } | |
185 | |
186 } else { // Inside a START, END pair. | |
187 bool interleaved_task_detected = false; | |
188 | |
189 switch (event->type) { | |
190 case TaskEvent::POST: | |
191 if (event->i == current_task_i) | |
192 spurious_event_found = true; | |
193 break; | |
194 case TaskEvent::START: | |
195 interleaved_task_detected = true; | |
196 break; | |
197 case TaskEvent::END: | |
198 if (event->i != current_task_i) | |
199 interleaved_task_detected = true; | |
200 else | |
201 current_task_i = -1; | |
202 break; | |
203 } | |
204 | |
205 if (interleaved_task_detected) { | |
206 return ::testing::AssertionFailure() | |
207 << "Found event " << ::testing::PrintToString(*event) | |
208 << " between START and END events for task " << current_task_i | |
209 << "; event dump: " << ::testing::PrintToString(events); | |
210 } | |
211 } | |
212 | |
213 if (spurious_event_found) { | |
214 const int event_i = event - events.begin(); | |
215 return ::testing::AssertionFailure() | |
216 << "Spurious event " << ::testing::PrintToString(*event) | |
217 << " at position " << event_i << "; event dump: " | |
218 << ::testing::PrintToString(events); | |
219 } | |
220 } | |
221 | |
222 return ::testing::AssertionSuccess(); | |
223 } | |
224 | |
225 } // namespace | |
226 | |
227 ::testing::AssertionResult CheckNonNestableInvariants( | |
228 const std::vector<TaskEvent>& events, | |
229 int task_count) { | |
230 const std::vector<int> post_order = | |
231 GetEventTypeOrder(events, TaskEvent::POST); | |
232 const std::vector<int> start_order = | |
233 GetEventTypeOrder(events, TaskEvent::START); | |
234 const std::vector<int> end_order = | |
235 GetEventTypeOrder(events, TaskEvent::END); | |
236 | |
237 if (start_order != post_order) { | |
238 return ::testing::AssertionFailure() | |
239 << "Expected START order (which equals actual POST order): \n" | |
240 << ::testing::PrintToString(post_order) | |
241 << "\n Actual START order:\n" | |
242 << ::testing::PrintToString(start_order); | |
243 } | |
244 | |
245 if (end_order != post_order) { | |
246 return ::testing::AssertionFailure() | |
247 << "Expected END order (which equals actual POST order): \n" | |
248 << ::testing::PrintToString(post_order) | |
249 << "\n Actual END order:\n" | |
250 << ::testing::PrintToString(end_order); | |
251 } | |
252 | |
253 const ::testing::AssertionResult result = | |
254 CheckEventOrdersForEachTask(events, task_count); | |
255 if (!result) | |
256 return result; | |
257 | |
258 return CheckNoTaskRunsOverlap(events); | |
259 } | |
260 | |
261 } // namespace internal | |
262 | |
263 } // namespace base | |
OLD | NEW |