blob: b945bc0d98eeb54dd19b7d4d30f6df9266a769db [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "rtc_base/event.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "test/gtest.h"
eladalon413ee9a2017-08-22 04:02:52 -070019
20namespace webrtc {
21namespace test {
22
23namespace {
24
Yves Gerey6516f762019-08-29 11:50:23 +020025using TaskId = DEPRECATED_SingleThreadedTaskQueueForTesting::TaskId;
eladalon413ee9a2017-08-22 04:02:52 -070026
27// Test should not rely on the object under test not being faulty. If the task
28// queue ever blocks forever, we want the tests to fail, rather than hang.
29constexpr int kMaxWaitTimeMs = 10000;
30
Yves Gerey6516f762019-08-29 11:50:23 +020031TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest,
32 SanityConstructionDestruction) {
33 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -070034}
35
Yves Gerey6516f762019-08-29 11:50:23 +020036TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest, ExecutesPostedTasks) {
37 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -070038
39 std::atomic<bool> executed(false);
Niels Möllerc572ff32018-11-07 08:43:50 +010040 rtc::Event done;
eladalon413ee9a2017-08-22 04:02:52 -070041
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
Yves Gerey6516f762019-08-29 11:50:23 +020051TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest,
eladalon413ee9a2017-08-22 04:02:52 -070052 PostMultipleTasksFromSameExternalThread) {
Yves Gerey6516f762019-08-29 11:50:23 +020053 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -070054
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++) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +020063 done_events.emplace_back(std::make_unique<rtc::Event>());
eladalon413ee9a2017-08-22 04:02:52 -070064 }
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.
Niels Möllerc572ff32018-11-07 08:43:50 +010070 rtc::Event rendezvous;
Yves Gerey665174f2018-06-19 15:03:05 +020071 task_queue.PostTask(
72 [&rendezvous]() { ASSERT_TRUE(rendezvous.Wait(kMaxWaitTimeMs)); });
eladalon413ee9a2017-08-22 04:02:52 -070073
74 // Post the tasks which comprise the test.
75 for (size_t i = 0; i < kCount; i++) {
76 task_queue.PostTask([&executed, &done_events, i]() { // |i| by value.
77 executed[i].store(true);
78 done_events[i]->Set();
79 });
80 }
81
82 rendezvous.Set(); // Release the task-queue.
83
84 // Wait until the task queue has executed all the tasks.
85 for (size_t i = 0; i < kCount; i++) {
86 ASSERT_TRUE(done_events[i]->Wait(kMaxWaitTimeMs));
87 }
88
89 for (size_t i = 0; i < kCount; i++) {
90 EXPECT_TRUE(executed[i].load());
91 }
92}
93
Yves Gerey6516f762019-08-29 11:50:23 +020094TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest,
95 PostToTaskQueueFromOwnThread) {
96 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -070097
98 std::atomic<bool> executed(false);
Niels Möllerc572ff32018-11-07 08:43:50 +010099 rtc::Event done;
eladalon413ee9a2017-08-22 04:02:52 -0700100
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
Yves Gerey6516f762019-08-29 11:50:23 +0200116TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest,
117 TasksExecutedInSequence) {
118 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -0700119
120 // The first task would perform:
121 // accumulator = 10 * accumulator + i
122 // Where |i| is 1, 2 and 3 for the 1st, 2nd and 3rd tasks, respectively.
123 // The result would be 123 if and only iff the tasks were executed in order.
124 size_t accumulator = 0;
125 size_t expected_value = 0; // Updates to the correct value.
126
127 // Prevent the chain from being set in motion before we've had time to
128 // schedule it all, lest the queue only contain one task at a time.
Niels Möllerc572ff32018-11-07 08:43:50 +0100129 rtc::Event rendezvous;
Yves Gerey665174f2018-06-19 15:03:05 +0200130 task_queue.PostTask(
131 [&rendezvous]() { ASSERT_TRUE(rendezvous.Wait(kMaxWaitTimeMs)); });
eladalon413ee9a2017-08-22 04:02:52 -0700132
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.
Niels Möllerc572ff32018-11-07 08:43:50 +0100141 rtc::Event done;
Yves Gerey665174f2018-06-19 15:03:05 +0200142 task_queue.PostTask([&done]() { done.Set(); });
eladalon413ee9a2017-08-22 04:02:52 -0700143
144 rendezvous.Set(); // Set the chain in motion.
145
146 ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
147
148 EXPECT_EQ(accumulator, expected_value);
149}
150
Yves Gerey6516f762019-08-29 11:50:23 +0200151TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest,
152 ExecutesPostedDelayedTask) {
153 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -0700154
155 std::atomic<bool> executed(false);
Niels Möllerc572ff32018-11-07 08:43:50 +0100156 rtc::Event done;
eladalon413ee9a2017-08-22 04:02:52 -0700157
158 constexpr int64_t delay_ms = 20;
159 static_assert(delay_ms < kMaxWaitTimeMs / 2, "Delay too long for tests.");
160
Yves Gerey665174f2018-06-19 15:03:05 +0200161 task_queue.PostDelayedTask(
162 [&executed, &done]() {
163 executed.store(true);
164 done.Set();
165 },
166 delay_ms);
eladalon413ee9a2017-08-22 04:02:52 -0700167 ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
168
169 EXPECT_TRUE(executed.load());
170}
171
Yves Gerey6516f762019-08-29 11:50:23 +0200172TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest,
173 DoesNotExecuteDelayedTaskTooSoon) {
174 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -0700175
176 std::atomic<bool> executed(false);
177
178 constexpr int64_t delay_ms = 2000;
179 static_assert(delay_ms < kMaxWaitTimeMs / 2, "Delay too long for tests.");
180
Yves Gerey665174f2018-06-19 15:03:05 +0200181 task_queue.PostDelayedTask([&executed]() { executed.store(true); }, delay_ms);
eladalon413ee9a2017-08-22 04:02:52 -0700182
183 // Wait less than is enough, make sure the task was not yet executed.
Niels Möllerc572ff32018-11-07 08:43:50 +0100184 rtc::Event not_done;
eladalon413ee9a2017-08-22 04:02:52 -0700185 ASSERT_FALSE(not_done.Wait(delay_ms / 2));
186 EXPECT_FALSE(executed.load());
187}
188
Yves Gerey6516f762019-08-29 11:50:23 +0200189TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest,
eladalon413ee9a2017-08-22 04:02:52 -0700190 TaskWithLesserDelayPostedAfterFirstDelayedTaskExectuedBeforeFirst) {
Yves Gerey6516f762019-08-29 11:50:23 +0200191 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -0700192
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
Niels Möllerc572ff32018-11-07 08:43:50 +0100202 rtc::Event done;
eladalon413ee9a2017-08-22 04:02:52 -0700203
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
Yves Gerey6516f762019-08-29 11:50:23 +0200223TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest,
eladalon413ee9a2017-08-22 04:02:52 -0700224 TaskWithGreaterDelayPostedAfterFirstDelayedTaskExectuedAfterFirst) {
Yves Gerey6516f762019-08-29 11:50:23 +0200225 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -0700226
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
Niels Möllerc572ff32018-11-07 08:43:50 +0100236 rtc::Event done;
eladalon413ee9a2017-08-22 04:02:52 -0700237
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
Yves Gerey6516f762019-08-29 11:50:23 +0200257TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest,
258 ExternalThreadCancelsTask) {
259 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -0700260
Niels Möllerc572ff32018-11-07 08:43:50 +0100261 rtc::Event done;
eladalon413ee9a2017-08-22 04:02:52 -0700262
263 // Prevent the to-be-cancelled task from being executed before we've had
264 // time to cancel it.
Niels Möllerc572ff32018-11-07 08:43:50 +0100265 rtc::Event rendezvous;
Yves Gerey665174f2018-06-19 15:03:05 +0200266 task_queue.PostTask(
267 [&rendezvous]() { ASSERT_TRUE(rendezvous.Wait(kMaxWaitTimeMs)); });
eladalon413ee9a2017-08-22 04:02:52 -0700268
Yves Gerey665174f2018-06-19 15:03:05 +0200269 TaskId cancelled_task_id = task_queue.PostTask([]() { EXPECT_TRUE(false); });
270 task_queue.PostTask([&done]() { done.Set(); });
eladalon413ee9a2017-08-22 04:02:52 -0700271
272 task_queue.CancelTask(cancelled_task_id);
273
274 // Set the tasks in motion; the cancelled task does not run (otherwise the
275 // test would fail). The last task ends the test, showing that the queue
276 // progressed beyond the cancelled task.
277 rendezvous.Set();
278 ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
279}
280
281// In this test, we'll set off a chain where the first task cancels the second
282// task, then a third task runs (showing that we really cancelled the task,
283// rather than just halted the task-queue).
Yves Gerey6516f762019-08-29 11:50:23 +0200284TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest,
285 InternalThreadCancelsTask) {
286 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -0700287
Niels Möllerc572ff32018-11-07 08:43:50 +0100288 rtc::Event done;
eladalon413ee9a2017-08-22 04:02:52 -0700289
290 // Prevent the chain from being set-off before we've set everything up.
Niels Möllerc572ff32018-11-07 08:43:50 +0100291 rtc::Event rendezvous;
Yves Gerey665174f2018-06-19 15:03:05 +0200292 task_queue.PostTask(
293 [&rendezvous]() { ASSERT_TRUE(rendezvous.Wait(kMaxWaitTimeMs)); });
eladalon413ee9a2017-08-22 04:02:52 -0700294
295 // This is the canceller-task. It takes cancelled_task_id by reference,
296 // because the ID will only become known after the cancelled task is
297 // scheduled.
298 TaskId cancelled_task_id;
299 auto canceller_task = [&task_queue, &cancelled_task_id]() {
300 task_queue.CancelTask(cancelled_task_id);
301 };
302 task_queue.PostTask(canceller_task);
303
304 // This task will be cancelled by the task before it.
Yves Gerey665174f2018-06-19 15:03:05 +0200305 auto cancelled_task = []() { EXPECT_TRUE(false); };
eladalon413ee9a2017-08-22 04:02:52 -0700306 cancelled_task_id = task_queue.PostTask(cancelled_task);
307
308 // When this task runs, it will allow the test to be finished.
Yves Gerey665174f2018-06-19 15:03:05 +0200309 auto completion_marker_task = [&done]() { done.Set(); };
eladalon413ee9a2017-08-22 04:02:52 -0700310 task_queue.PostTask(completion_marker_task);
311
312 rendezvous.Set(); // Set the chain in motion.
313
314 ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
315}
316
Yves Gerey6516f762019-08-29 11:50:23 +0200317TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest, SendTask) {
318 DEPRECATED_SingleThreadedTaskQueueForTesting task_queue("task_queue");
eladalon413ee9a2017-08-22 04:02:52 -0700319
320 std::atomic<bool> executed(false);
321
322 task_queue.SendTask([&executed]() {
323 // Intentionally delay, so that if SendTask didn't block, the sender thread
324 // would have time to read |executed|.
Niels Möllerc572ff32018-11-07 08:43:50 +0100325 rtc::Event delay;
eladalon413ee9a2017-08-22 04:02:52 -0700326 ASSERT_FALSE(delay.Wait(1000));
327 executed.store(true);
328 });
329
330 EXPECT_TRUE(executed);
331}
332
Yves Gerey6516f762019-08-29 11:50:23 +0200333TEST(DEPRECATED_SingleThreadedTaskQueueForTestingTest,
eladalon413ee9a2017-08-22 04:02:52 -0700334 DestructTaskQueueWhileTasksPending) {
335 auto task_queue =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200336 std::make_unique<DEPRECATED_SingleThreadedTaskQueueForTesting>(
Yves Gerey6516f762019-08-29 11:50:23 +0200337 "task_queue");
eladalon413ee9a2017-08-22 04:02:52 -0700338
339 std::atomic<size_t> counter(0);
340
341 constexpr size_t tasks = 10;
342 for (size_t i = 0; i < tasks; i++) {
343 task_queue->PostTask([&counter]() {
344 std::atomic_fetch_add(&counter, static_cast<size_t>(1));
Niels Möllerc572ff32018-11-07 08:43:50 +0100345 rtc::Event delay;
eladalon413ee9a2017-08-22 04:02:52 -0700346 ASSERT_FALSE(delay.Wait(500));
347 });
348 }
349
350 task_queue.reset();
351
352 EXPECT_LT(counter, tasks);
353}
354
355} // namespace
356} // namespace test
357} // namespace webrtc