Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(73)

Side by Side Diff: webrtc/test/single_threaded_task_queue_unittest.cc

Issue 2998923002: Use SingleThreadedTaskQueue in DirectTransport (Closed)
Patch Set: Appease win_msvc_rel. Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "webrtc/test/single_threaded_task_queue.h"
12
13 #include <atomic>
14 #include <memory>
15 #include <vector>
16
17 #include "webrtc/rtc_base/event.h"
18 #include "webrtc/rtc_base/ptr_util.h"
19 #include "webrtc/test/gtest.h"
20
21 namespace webrtc {
22 namespace test {
23
24 namespace {
25
26 using TaskId = SingleThreadedTaskQueueForTesting::TaskId;
27
28 // Test should not rely on the object under test not being faulty. If the task
29 // queue ever blocks forever, we want the tests to fail, rather than hang.
30 constexpr int kMaxWaitTimeMs = 10000;
31
32 TEST(SingleThreadedTaskQueueForTestingTest, SanityConstructionDestruction) {
33 SingleThreadedTaskQueueForTesting task_queue("task_queue");
34 }
35
36 TEST(SingleThreadedTaskQueueForTestingTest, ExecutesPostedTasks) {
37 SingleThreadedTaskQueueForTesting task_queue("task_queue");
38
39 std::atomic<bool> executed(false);
40 rtc::Event done(true, false);
41
42 task_queue.PostTask([&executed, &done]() {
43 executed.store(true);
44 done.Set();
45 });
46 ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
47
48 EXPECT_TRUE(executed.load());
49 }
50
51 TEST(SingleThreadedTaskQueueForTestingTest,
52 PostMultipleTasksFromSameExternalThread) {
53 SingleThreadedTaskQueueForTesting task_queue("task_queue");
54
55 constexpr size_t kCount = 3;
56 std::atomic<bool> executed[kCount];
57 for (std::atomic<bool>& exec : executed) {
58 exec.store(false);
59 }
60
61 std::vector<std::unique_ptr<rtc::Event>> done_events;
62 for (size_t i = 0; i < kCount; i++) {
63 done_events.emplace_back(rtc::MakeUnique<rtc::Event>(false, false));
64 }
65
66 // To avoid the tasks which comprise the actual test from running before they
67 // have all be posted, which could result in only one task ever being in the
68 // queue at any given time, post one waiting task that would block the
69 // task-queue, and unblock only after all tasks have been posted.
70 rtc::Event rendezvous(true, false);
71 task_queue.PostTask([&rendezvous]() {
72 ASSERT_TRUE(rendezvous.Wait(kMaxWaitTimeMs));
73 });
74
75 // Post the tasks which comprise the test.
76 for (size_t i = 0; i < kCount; i++) {
77 task_queue.PostTask([&executed, &done_events, i]() { // |i| by value.
78 executed[i].store(true);
79 done_events[i]->Set();
80 });
81 }
82
83 rendezvous.Set(); // Release the task-queue.
84
85 // Wait until the task queue has executed all the tasks.
86 for (size_t i = 0; i < kCount; i++) {
87 ASSERT_TRUE(done_events[i]->Wait(kMaxWaitTimeMs));
88 }
89
90 for (size_t i = 0; i < kCount; i++) {
91 EXPECT_TRUE(executed[i].load());
92 }
93 }
94
95 TEST(SingleThreadedTaskQueueForTestingTest, PostToTaskQueueFromOwnThread) {
96 SingleThreadedTaskQueueForTesting task_queue("task_queue");
97
98 std::atomic<bool> executed(false);
99 rtc::Event done(true, false);
100
101 auto internally_posted_task = [&executed, &done]() {
102 executed.store(true);
103 done.Set();
104 };
105
106 auto externally_posted_task = [&task_queue, &internally_posted_task]() {
107 task_queue.PostTask(internally_posted_task);
108 };
109
110 task_queue.PostTask(externally_posted_task);
111
112 ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
113 EXPECT_TRUE(executed.load());
114 }
115
116 TEST(SingleThreadedTaskQueueForTestingTest, TasksExecutedInSequence) {
117 SingleThreadedTaskQueueForTesting task_queue("task_queue");
118
119 // The first task would perform:
120 // accumulator = 10 * accumulator + i
121 // Where |i| is 1, 2 and 3 for the 1st, 2nd and 3rd tasks, respectively.
122 // The result would be 123 if and only iff the tasks were executed in order.
123 size_t accumulator = 0;
124 size_t expected_value = 0; // Updates to the correct value.
125
126 // Prevent the chain from being set in motion before we've had time to
127 // schedule it all, lest the queue only contain one task at a time.
128 rtc::Event rendezvous(true, false);
129 task_queue.PostTask([&rendezvous]() {
130 ASSERT_TRUE(rendezvous.Wait(kMaxWaitTimeMs));
131 });
132
133 for (size_t i = 0; i < 3; i++) {
134 task_queue.PostTask([&accumulator, i]() { // |i| passed by value.
135 accumulator = 10 * accumulator + i;
136 });
137 expected_value = 10 * expected_value + i;
138 }
139
140 // The test will wait for the task-queue to finish.
141 rtc::Event done(true, false);
142 task_queue.PostTask([&done]() {
143 done.Set();
144 });
145
146 rendezvous.Set(); // Set the chain in motion.
147
148 ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
149
150 EXPECT_EQ(accumulator, expected_value);
151 }
152
153 TEST(SingleThreadedTaskQueueForTestingTest, ExecutesPostedDelayedTask) {
154 SingleThreadedTaskQueueForTesting task_queue("task_queue");
155
156 std::atomic<bool> executed(false);
157 rtc::Event done(true, false);
158
159 constexpr int64_t delay_ms = 20;
160 static_assert(delay_ms < kMaxWaitTimeMs / 2, "Delay too long for tests.");
161
162 task_queue.PostDelayedTask([&executed, &done]() {
163 executed.store(true);
164 done.Set();
165 }, delay_ms);
166 ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
167
168 EXPECT_TRUE(executed.load());
169 }
170
171 TEST(SingleThreadedTaskQueueForTestingTest, DoesNotExecuteDelayedTaskTooSoon) {
172 SingleThreadedTaskQueueForTesting task_queue("task_queue");
173
174 std::atomic<bool> executed(false);
175
176 constexpr int64_t delay_ms = 2000;
177 static_assert(delay_ms < kMaxWaitTimeMs / 2, "Delay too long for tests.");
178
179 task_queue.PostDelayedTask([&executed]() {
180 executed.store(true);
181 }, delay_ms);
182
183 // Wait less than is enough, make sure the task was not yet executed.
184 rtc::Event not_done(true, false);
185 ASSERT_FALSE(not_done.Wait(delay_ms / 2));
186 EXPECT_FALSE(executed.load());
187 }
188
189 TEST(SingleThreadedTaskQueueForTestingTest,
190 TaskWithLesserDelayPostedAfterFirstDelayedTaskExectuedBeforeFirst) {
191 SingleThreadedTaskQueueForTesting task_queue("task_queue");
192
193 std::atomic<bool> earlier_executed(false);
194 constexpr int64_t earlier_delay_ms = 500;
195
196 std::atomic<bool> later_executed(false);
197 constexpr int64_t later_delay_ms = 1000;
198
199 static_assert(earlier_delay_ms + later_delay_ms < kMaxWaitTimeMs / 2,
200 "Delay too long for tests.");
201
202 rtc::Event done(true, false);
203
204 auto earlier_task = [&earlier_executed, &later_executed]() {
205 EXPECT_FALSE(later_executed.load());
206 earlier_executed.store(true);
207 };
208
209 auto later_task = [&earlier_executed, &later_executed, &done]() {
210 EXPECT_TRUE(earlier_executed.load());
211 later_executed.store(true);
212 done.Set();
213 };
214
215 task_queue.PostDelayedTask(later_task, later_delay_ms);
216 task_queue.PostDelayedTask(earlier_task, earlier_delay_ms);
217
218 ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
219 ASSERT_TRUE(earlier_executed);
220 ASSERT_TRUE(later_executed);
221 }
222
223 TEST(SingleThreadedTaskQueueForTestingTest,
224 TaskWithGreaterDelayPostedAfterFirstDelayedTaskExectuedAfterFirst) {
225 SingleThreadedTaskQueueForTesting task_queue("task_queue");
226
227 std::atomic<bool> earlier_executed(false);
228 constexpr int64_t earlier_delay_ms = 500;
229
230 std::atomic<bool> later_executed(false);
231 constexpr int64_t later_delay_ms = 1000;
232
233 static_assert(earlier_delay_ms + later_delay_ms < kMaxWaitTimeMs / 2,
234 "Delay too long for tests.");
235
236 rtc::Event done(true, false);
237
238 auto earlier_task = [&earlier_executed, &later_executed]() {
239 EXPECT_FALSE(later_executed.load());
240 earlier_executed.store(true);
241 };
242
243 auto later_task = [&earlier_executed, &later_executed, &done]() {
244 EXPECT_TRUE(earlier_executed.load());
245 later_executed.store(true);
246 done.Set();
247 };
248
249 task_queue.PostDelayedTask(earlier_task, earlier_delay_ms);
250 task_queue.PostDelayedTask(later_task, later_delay_ms);
251
252 ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
253 ASSERT_TRUE(earlier_executed);
254 ASSERT_TRUE(later_executed);
255 }
256
257 TEST(SingleThreadedTaskQueueForTestingTest, ExternalThreadCancelsTask) {
258 SingleThreadedTaskQueueForTesting task_queue("task_queue");
259
260 rtc::Event done(true, false);
261
262 // Prevent the to-be-cancelled task from being executed before we've had
263 // time to cancel it.
264 rtc::Event rendezvous(true, false);
265 task_queue.PostTask([&rendezvous]() {
266 ASSERT_TRUE(rendezvous.Wait(kMaxWaitTimeMs));
267 });
268
269 TaskId cancelled_task_id = task_queue.PostTask([]() {
270 EXPECT_TRUE(false);
271 });
272 task_queue.PostTask([&done]() {
273 done.Set();
274 });
275
276 task_queue.CancelTask(cancelled_task_id);
277
278 // Set the tasks in motion; the cancelled task does not run (otherwise the
279 // test would fail). The last task ends the test, showing that the queue
280 // progressed beyond the cancelled task.
281 rendezvous.Set();
282 ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
283 }
284
285 // In this test, we'll set off a chain where the first task cancels the second
286 // task, then a third task runs (showing that we really cancelled the task,
287 // rather than just halted the task-queue).
288 TEST(SingleThreadedTaskQueueForTestingTest, InternalThreadCancelsTask) {
289 SingleThreadedTaskQueueForTesting task_queue("task_queue");
290
291 rtc::Event done(true, false);
292
293 // Prevent the chain from being set-off before we've set everything up.
294 rtc::Event rendezvous(true, false);
295 task_queue.PostTask([&rendezvous]() {
296 ASSERT_TRUE(rendezvous.Wait(kMaxWaitTimeMs));
297 });
298
299 // This is the canceller-task. It takes cancelled_task_id by reference,
300 // because the ID will only become known after the cancelled task is
301 // scheduled.
302 TaskId cancelled_task_id;
303 auto canceller_task = [&task_queue, &cancelled_task_id]() {
304 task_queue.CancelTask(cancelled_task_id);
305 };
306 task_queue.PostTask(canceller_task);
307
308 // This task will be cancelled by the task before it.
309 auto cancelled_task = []() {
310 EXPECT_TRUE(false);
311 };
312 cancelled_task_id = task_queue.PostTask(cancelled_task);
313
314 // When this task runs, it will allow the test to be finished.
315 auto completion_marker_task = [&done]() {
316 done.Set();
317 };
318 task_queue.PostTask(completion_marker_task);
319
320 rendezvous.Set(); // Set the chain in motion.
321
322 ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
323 }
324
325 TEST(SingleThreadedTaskQueueForTestingTest, SendTask) {
326 SingleThreadedTaskQueueForTesting task_queue("task_queue");
327
328 std::atomic<bool> executed(false);
329
330 task_queue.SendTask([&executed]() {
331 // Intentionally delay, so that if SendTask didn't block, the sender thread
332 // would have time to read |executed|.
333 rtc::Event delay(true, false);
334 ASSERT_FALSE(delay.Wait(1000));
335 executed.store(true);
336 });
337
338 EXPECT_TRUE(executed);
339 }
340
341 TEST(SingleThreadedTaskQueueForTestingTest,
342 DestructTaskQueueWhileTasksPending) {
343 auto task_queue =
344 rtc::MakeUnique<SingleThreadedTaskQueueForTesting>("task_queue");
345
346 std::atomic<size_t> counter(0);
347
348 constexpr size_t tasks = 10;
349 for (size_t i = 0; i < tasks; i++) {
350 task_queue->PostTask([&counter]() {
351 std::atomic_fetch_add(&counter, static_cast<size_t>(1));
352 rtc::Event delay(true, false);
353 ASSERT_FALSE(delay.Wait(500));
354 });
355 }
356
357 task_queue.reset();
358
359 EXPECT_LT(counter, tasks);
360 }
361
362 } // namespace
363 } // namespace test
364 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698