blob: 81eb4700ccc8741150abc6f31ae083d3245b60c6 [file] [log] [blame]
eladalon413ee9a2017-08-22 04:02:52 -07001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "test/single_threaded_task_queue.h"
eladalon413ee9a2017-08-22 04:02:52 -070012
13#include <atomic>
14#include <memory>
15#include <vector>
16
Karl Wiberg918f50c2018-07-05 11:40:33 +020017#include "absl/memory/memory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "rtc_base/event.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "test/gtest.h"
eladalon413ee9a2017-08-22 04:02:52 -070020
21namespace webrtc {
22namespace test {
23
24namespace {
25
Yves Gerey6516f762019-08-29 11:50:23 +020026using TaskId = DEPRECATED_SingleThreadedTaskQueueForTesting::TaskId;
eladalon413ee9a2017-08-22 04:02:52 -070027
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.
30constexpr int kMaxWaitTimeMs = 10000;
31
Yves Gerey6516f762019-08-29 11:50:23 +020032TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest,
33 SanityConstructionDestruction) {
34 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -070035}
36
Yves Gerey6516f762019-08-29 11:50:23 +020037TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest, ExecutesPostedTasks) {
38 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -070039
40 std::atomic<bool> executed(false);
Niels Möllerc572ff32018-11-07 08:43:50 +010041 rtc::Event done;
eladalon413ee9a2017-08-22 04:02:52 -070042
43 task_queue.PostTask([&executed, &done]() {
44 executed.store(true);
45 done.Set();
46 });
47 ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
48
49 EXPECT_TRUE(executed.load());
50}
51
Yves Gerey6516f762019-08-29 11:50:23 +020052TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest,
eladalon413ee9a2017-08-22 04:02:52 -070053 PostMultipleTasksFromSameExternalThread) {
Yves Gerey6516f762019-08-29 11:50:23 +020054 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -070055
56 constexpr size_t kCount = 3;
57 std::atomic<bool> executed[kCount];
58 for (std::atomic<bool>& exec : executed) {
59 exec.store(false);
60 }
61
62 std::vector<std::unique_ptr<rtc::Event>> done_events;
63 for (size_t i = 0; i < kCount; i++) {
Niels Möllerc572ff32018-11-07 08:43:50 +010064 done_events.emplace_back(absl::make_unique<rtc::Event>());
eladalon413ee9a2017-08-22 04:02:52 -070065 }
66
67 // To avoid the tasks which comprise the actual test from running before they
68 // have all be posted, which could result in only one task ever being in the
69 // queue at any given time, post one waiting task that would block the
70 // task-queue, and unblock only after all tasks have been posted.
Niels Möllerc572ff32018-11-07 08:43:50 +010071 rtc::Event rendezvous;
Yves Gerey665174f2018-06-19 15:03:05 +020072 task_queue.PostTask(
73 [&rendezvous]() { ASSERT_TRUE(rendezvous.Wait(kMaxWaitTimeMs)); });
eladalon413ee9a2017-08-22 04:02:52 -070074
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
Yves Gerey6516f762019-08-29 11:50:23 +020095TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest,
96 PostToTaskQueueFromOwnThread) {
97 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -070098
99 std::atomic<bool> executed(false);
Niels Möllerc572ff32018-11-07 08:43:50 +0100100 rtc::Event done;
eladalon413ee9a2017-08-22 04:02:52 -0700101
102 auto internally_posted_task = [&executed, &done]() {
103 executed.store(true);
104 done.Set();
105 };
106
107 auto externally_posted_task = [&task_queue, &internally_posted_task]() {
108 task_queue.PostTask(internally_posted_task);
109 };
110
111 task_queue.PostTask(externally_posted_task);
112
113 ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
114 EXPECT_TRUE(executed.load());
115}
116
Yves Gerey6516f762019-08-29 11:50:23 +0200117TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest,
118 TasksExecutedInSequence) {
119 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -0700120
121 // The first task would perform:
122 // accumulator = 10 * accumulator + i
123 // Where |i| is 1, 2 and 3 for the 1st, 2nd and 3rd tasks, respectively.
124 // The result would be 123 if and only iff the tasks were executed in order.
125 size_t accumulator = 0;
126 size_t expected_value = 0; // Updates to the correct value.
127
128 // Prevent the chain from being set in motion before we've had time to
129 // schedule it all, lest the queue only contain one task at a time.
Niels Möllerc572ff32018-11-07 08:43:50 +0100130 rtc::Event rendezvous;
Yves Gerey665174f2018-06-19 15:03:05 +0200131 task_queue.PostTask(
132 [&rendezvous]() { ASSERT_TRUE(rendezvous.Wait(kMaxWaitTimeMs)); });
eladalon413ee9a2017-08-22 04:02:52 -0700133
134 for (size_t i = 0; i < 3; i++) {
135 task_queue.PostTask([&accumulator, i]() { // |i| passed by value.
136 accumulator = 10 * accumulator + i;
137 });
138 expected_value = 10 * expected_value + i;
139 }
140
141 // The test will wait for the task-queue to finish.
Niels Möllerc572ff32018-11-07 08:43:50 +0100142 rtc::Event done;
Yves Gerey665174f2018-06-19 15:03:05 +0200143 task_queue.PostTask([&done]() { done.Set(); });
eladalon413ee9a2017-08-22 04:02:52 -0700144
145 rendezvous.Set(); // Set the chain in motion.
146
147 ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
148
149 EXPECT_EQ(accumulator, expected_value);
150}
151
Yves Gerey6516f762019-08-29 11:50:23 +0200152TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest,
153 ExecutesPostedDelayedTask) {
154 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -0700155
156 std::atomic<bool> executed(false);
Niels Möllerc572ff32018-11-07 08:43:50 +0100157 rtc::Event done;
eladalon413ee9a2017-08-22 04:02:52 -0700158
159 constexpr int64_t delay_ms = 20;
160 static_assert(delay_ms < kMaxWaitTimeMs / 2, "Delay too long for tests.");
161
Yves Gerey665174f2018-06-19 15:03:05 +0200162 task_queue.PostDelayedTask(
163 [&executed, &done]() {
164 executed.store(true);
165 done.Set();
166 },
167 delay_ms);
eladalon413ee9a2017-08-22 04:02:52 -0700168 ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
169
170 EXPECT_TRUE(executed.load());
171}
172
Yves Gerey6516f762019-08-29 11:50:23 +0200173TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest,
174 DoesNotExecuteDelayedTaskTooSoon) {
175 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -0700176
177 std::atomic<bool> executed(false);
178
179 constexpr int64_t delay_ms = 2000;
180 static_assert(delay_ms < kMaxWaitTimeMs / 2, "Delay too long for tests.");
181
Yves Gerey665174f2018-06-19 15:03:05 +0200182 task_queue.PostDelayedTask([&executed]() { executed.store(true); }, delay_ms);
eladalon413ee9a2017-08-22 04:02:52 -0700183
184 // Wait less than is enough, make sure the task was not yet executed.
Niels Möllerc572ff32018-11-07 08:43:50 +0100185 rtc::Event not_done;
eladalon413ee9a2017-08-22 04:02:52 -0700186 ASSERT_FALSE(not_done.Wait(delay_ms / 2));
187 EXPECT_FALSE(executed.load());
188}
189
Yves Gerey6516f762019-08-29 11:50:23 +0200190TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest,
eladalon413ee9a2017-08-22 04:02:52 -0700191 TaskWithLesserDelayPostedAfterFirstDelayedTaskExectuedBeforeFirst) {
Yves Gerey6516f762019-08-29 11:50:23 +0200192 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -0700193
194 std::atomic<bool> earlier_executed(false);
195 constexpr int64_t earlier_delay_ms = 500;
196
197 std::atomic<bool> later_executed(false);
198 constexpr int64_t later_delay_ms = 1000;
199
200 static_assert(earlier_delay_ms + later_delay_ms < kMaxWaitTimeMs / 2,
201 "Delay too long for tests.");
202
Niels Möllerc572ff32018-11-07 08:43:50 +0100203 rtc::Event done;
eladalon413ee9a2017-08-22 04:02:52 -0700204
205 auto earlier_task = [&earlier_executed, &later_executed]() {
206 EXPECT_FALSE(later_executed.load());
207 earlier_executed.store(true);
208 };
209
210 auto later_task = [&earlier_executed, &later_executed, &done]() {
211 EXPECT_TRUE(earlier_executed.load());
212 later_executed.store(true);
213 done.Set();
214 };
215
216 task_queue.PostDelayedTask(later_task, later_delay_ms);
217 task_queue.PostDelayedTask(earlier_task, earlier_delay_ms);
218
219 ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
220 ASSERT_TRUE(earlier_executed);
221 ASSERT_TRUE(later_executed);
222}
223
Yves Gerey6516f762019-08-29 11:50:23 +0200224TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest,
eladalon413ee9a2017-08-22 04:02:52 -0700225 TaskWithGreaterDelayPostedAfterFirstDelayedTaskExectuedAfterFirst) {
Yves Gerey6516f762019-08-29 11:50:23 +0200226 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -0700227
228 std::atomic<bool> earlier_executed(false);
229 constexpr int64_t earlier_delay_ms = 500;
230
231 std::atomic<bool> later_executed(false);
232 constexpr int64_t later_delay_ms = 1000;
233
234 static_assert(earlier_delay_ms + later_delay_ms < kMaxWaitTimeMs / 2,
235 "Delay too long for tests.");
236
Niels Möllerc572ff32018-11-07 08:43:50 +0100237 rtc::Event done;
eladalon413ee9a2017-08-22 04:02:52 -0700238
239 auto earlier_task = [&earlier_executed, &later_executed]() {
240 EXPECT_FALSE(later_executed.load());
241 earlier_executed.store(true);
242 };
243
244 auto later_task = [&earlier_executed, &later_executed, &done]() {
245 EXPECT_TRUE(earlier_executed.load());
246 later_executed.store(true);
247 done.Set();
248 };
249
250 task_queue.PostDelayedTask(earlier_task, earlier_delay_ms);
251 task_queue.PostDelayedTask(later_task, later_delay_ms);
252
253 ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
254 ASSERT_TRUE(earlier_executed);
255 ASSERT_TRUE(later_executed);
256}
257
Yves Gerey6516f762019-08-29 11:50:23 +0200258TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest,
259 ExternalThreadCancelsTask) {
260 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -0700261
Niels Möllerc572ff32018-11-07 08:43:50 +0100262 rtc::Event done;
eladalon413ee9a2017-08-22 04:02:52 -0700263
264 // Prevent the to-be-cancelled task from being executed before we've had
265 // time to cancel it.
Niels Möllerc572ff32018-11-07 08:43:50 +0100266 rtc::Event rendezvous;
Yves Gerey665174f2018-06-19 15:03:05 +0200267 task_queue.PostTask(
268 [&rendezvous]() { ASSERT_TRUE(rendezvous.Wait(kMaxWaitTimeMs)); });
eladalon413ee9a2017-08-22 04:02:52 -0700269
Yves Gerey665174f2018-06-19 15:03:05 +0200270 TaskId cancelled_task_id = task_queue.PostTask([]() { EXPECT_TRUE(false); });
271 task_queue.PostTask([&done]() { done.Set(); });
eladalon413ee9a2017-08-22 04:02:52 -0700272
273 task_queue.CancelTask(cancelled_task_id);
274
275 // Set the tasks in motion; the cancelled task does not run (otherwise the
276 // test would fail). The last task ends the test, showing that the queue
277 // progressed beyond the cancelled task.
278 rendezvous.Set();
279 ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
280}
281
282// In this test, we'll set off a chain where the first task cancels the second
283// task, then a third task runs (showing that we really cancelled the task,
284// rather than just halted the task-queue).
Yves Gerey6516f762019-08-29 11:50:23 +0200285TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest,
286 InternalThreadCancelsTask) {
287 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -0700288
Niels Möllerc572ff32018-11-07 08:43:50 +0100289 rtc::Event done;
eladalon413ee9a2017-08-22 04:02:52 -0700290
291 // Prevent the chain from being set-off before we've set everything up.
Niels Möllerc572ff32018-11-07 08:43:50 +0100292 rtc::Event rendezvous;
Yves Gerey665174f2018-06-19 15:03:05 +0200293 task_queue.PostTask(
294 [&rendezvous]() { ASSERT_TRUE(rendezvous.Wait(kMaxWaitTimeMs)); });
eladalon413ee9a2017-08-22 04:02:52 -0700295
296 // This is the canceller-task. It takes cancelled_task_id by reference,
297 // because the ID will only become known after the cancelled task is
298 // scheduled.
299 TaskId cancelled_task_id;
300 auto canceller_task = [&task_queue, &cancelled_task_id]() {
301 task_queue.CancelTask(cancelled_task_id);
302 };
303 task_queue.PostTask(canceller_task);
304
305 // This task will be cancelled by the task before it.
Yves Gerey665174f2018-06-19 15:03:05 +0200306 auto cancelled_task = []() { EXPECT_TRUE(false); };
eladalon413ee9a2017-08-22 04:02:52 -0700307 cancelled_task_id = task_queue.PostTask(cancelled_task);
308
309 // When this task runs, it will allow the test to be finished.
Yves Gerey665174f2018-06-19 15:03:05 +0200310 auto completion_marker_task = [&done]() { done.Set(); };
eladalon413ee9a2017-08-22 04:02:52 -0700311 task_queue.PostTask(completion_marker_task);
312
313 rendezvous.Set(); // Set the chain in motion.
314
315 ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
316}
317
Yves Gerey6516f762019-08-29 11:50:23 +0200318TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest, SendTask) {
319 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -0700320
321 std::atomic<bool> executed(false);
322
323 task_queue.SendTask([&executed]() {
324 // Intentionally delay, so that if SendTask didn't block, the sender thread
325 // would have time to read |executed|.
Niels Möllerc572ff32018-11-07 08:43:50 +0100326 rtc::Event delay;
eladalon413ee9a2017-08-22 04:02:52 -0700327 ASSERT_FALSE(delay.Wait(1000));
328 executed.store(true);
329 });
330
331 EXPECT_TRUE(executed);
332}
333
Yves Gerey6516f762019-08-29 11:50:23 +0200334TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest,
eladalon413ee9a2017-08-22 04:02:52 -0700335 DestructTaskQueueWhileTasksPending) {
336 auto task_queue =
Yves Gerey6516f762019-08-29 11:50:23 +0200337 absl::make_unique<DEPRECATED_SingleThreadedTaskQueueForTesting>(
338 "task_queue");
eladalon413ee9a2017-08-22 04:02:52 -0700339
340 std::atomic<size_t> counter(0);
341
342 constexpr size_t tasks = 10;
343 for (size_t i = 0; i < tasks; i++) {
344 task_queue->PostTask([&counter]() {
345 std::atomic_fetch_add(&counter, static_cast<size_t>(1));
Niels Möllerc572ff32018-11-07 08:43:50 +0100346 rtc::Event delay;
eladalon413ee9a2017-08-22 04:02:52 -0700347 ASSERT_FALSE(delay.Wait(500));
348 });
349 }
350
351 task_queue.reset();
352
353 EXPECT_LT(counter, tasks);
354}
355
356} // namespace
357} // namespace test
358} // namespace webrtc