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