blob: cf9c81408ed2964a44a52659de2048f60071668b [file] [log] [blame]
Danil Chapovalov33b716f2019-01-22 18:15:37 +01001/*
2 * Copyright 2019 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#include "api/task_queue/task_queue_test.h"
11
12#include "absl/memory/memory.h"
13#include "absl/strings/string_view.h"
14#include "rtc_base/event.h"
15#include "rtc_base/task_queue.h"
16#include "rtc_base/timeutils.h"
17
18namespace webrtc {
19namespace {
20
21std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue(
22 TaskQueueFactory* factory,
23 absl::string_view task_queue_name,
24 TaskQueueFactory::Priority priority = TaskQueueFactory::Priority::NORMAL) {
25 return factory->CreateTaskQueue(task_queue_name, priority);
26}
27
28TEST_P(TaskQueueTest, Construct) {
29 auto queue = CreateTaskQueue(GetParam(), "Construct");
30 EXPECT_FALSE(queue->IsCurrent());
31}
32
33TEST_P(TaskQueueTest, PostAndCheckCurrent) {
34 rtc::Event event;
35 auto queue = CreateTaskQueue(GetParam(), "PostAndCheckCurrent");
36
37 // We're not running a task, so there shouldn't be a current queue.
38 EXPECT_FALSE(queue->IsCurrent());
39 EXPECT_FALSE(TaskQueueBase::Current());
40
41 queue->PostTask(rtc::NewClosure([&event, &queue] {
42 EXPECT_TRUE(queue->IsCurrent());
43 event.Set();
44 }));
45 EXPECT_TRUE(event.Wait(1000));
46}
47
48TEST_P(TaskQueueTest, PostCustomTask) {
49 rtc::Event ran;
50 auto queue = CreateTaskQueue(GetParam(), "PostCustomImplementation");
51
52 class CustomTask : public QueuedTask {
53 public:
54 explicit CustomTask(rtc::Event* ran) : ran_(ran) {}
55
56 private:
57 bool Run() override {
58 ran_->Set();
59 return false; // Do not allow the task to be deleted by the queue.
60 }
61
62 rtc::Event* const ran_;
63 } my_task(&ran);
64
65 queue->PostTask(absl::WrapUnique(&my_task));
66 EXPECT_TRUE(ran.Wait(1000));
67}
68
69TEST_P(TaskQueueTest, PostDelayedZero) {
70 rtc::Event event;
71 auto queue = CreateTaskQueue(GetParam(), "PostDelayedZero");
72
73 queue->PostDelayedTask(rtc::NewClosure([&event] { event.Set(); }), 0);
74 EXPECT_TRUE(event.Wait(1000));
75}
76
77TEST_P(TaskQueueTest, PostFromQueue) {
78 rtc::Event event;
79 auto queue = CreateTaskQueue(GetParam(), "PostFromQueue");
80
81 queue->PostTask(rtc::NewClosure([&event, &queue] {
82 queue->PostTask(rtc::NewClosure([&event] { event.Set(); }));
83 }));
84 EXPECT_TRUE(event.Wait(1000));
85}
86
87TEST_P(TaskQueueTest, PostDelayed) {
88 rtc::Event event;
89 auto queue = CreateTaskQueue(GetParam(), "PostDelayed",
90 TaskQueueFactory::Priority::HIGH);
91
92 int64_t start = rtc::TimeMillis();
93 queue->PostDelayedTask(rtc::NewClosure([&event, &queue] {
94 EXPECT_TRUE(queue->IsCurrent());
95 event.Set();
96 }),
97 100);
98 EXPECT_TRUE(event.Wait(1000));
99 int64_t end = rtc::TimeMillis();
100 // These tests are a little relaxed due to how "powerful" our test bots can
101 // be. Most recently we've seen windows bots fire the callback after 94-99ms,
102 // which is why we have a little bit of leeway backwards as well.
103 EXPECT_GE(end - start, 90u);
104 EXPECT_NEAR(end - start, 190u, 100u); // Accept 90-290.
105}
106
107TEST_P(TaskQueueTest, PostMultipleDelayed) {
108 auto queue = CreateTaskQueue(GetParam(), "PostMultipleDelayed");
109
110 std::vector<rtc::Event> events(100);
111 for (int i = 0; i < 100; ++i) {
112 rtc::Event* event = &events[i];
113 queue->PostDelayedTask(rtc::NewClosure([event, &queue] {
114 EXPECT_TRUE(queue->IsCurrent());
115 event->Set();
116 }),
117 i);
118 }
119
120 for (rtc::Event& e : events)
121 EXPECT_TRUE(e.Wait(1000));
122}
123
124TEST_P(TaskQueueTest, PostDelayedAfterDestruct) {
125 rtc::Event run;
126 rtc::Event deleted;
127 auto queue = CreateTaskQueue(GetParam(), "PostDelayedAfterDestruct");
128 queue->PostDelayedTask(
129 rtc::NewClosure([&run] { run.Set(); }, [&deleted] { deleted.Set(); }),
130 100);
131 // Destroy the queue.
132 queue = nullptr;
133 // Task might outlive the TaskQueue, but still should be deleted.
134 EXPECT_TRUE(deleted.Wait(200));
135 EXPECT_FALSE(run.Wait(0)); // and should not run.
136}
137
138TEST_P(TaskQueueTest, PostAndReuse) {
139 rtc::Event event;
140 auto post_queue = CreateTaskQueue(GetParam(), "PostQueue");
141 auto reply_queue = CreateTaskQueue(GetParam(), "ReplyQueue");
142
143 int call_count = 0;
144
145 class ReusedTask : public QueuedTask {
146 public:
147 ReusedTask(int* counter, TaskQueueBase* reply_queue, rtc::Event* event)
148 : counter_(*counter), reply_queue_(reply_queue), event_(*event) {
149 EXPECT_EQ(counter_, 0);
150 }
151
152 private:
153 bool Run() override {
154 if (++counter_ == 1) {
155 reply_queue_->PostTask(absl::WrapUnique(this));
156 // At this point, the object is owned by reply_queue_ and it's
157 // theoratically possible that the object has been deleted (e.g. if
158 // posting wasn't possible). So, don't touch any member variables here.
159
160 // Indicate to the current queue that ownership has been transferred.
161 return false;
162 } else {
163 EXPECT_EQ(counter_, 2);
164 EXPECT_TRUE(reply_queue_->IsCurrent());
165 event_.Set();
166 return true; // Indicate that the object should be deleted.
167 }
168 }
169
170 int& counter_;
171 TaskQueueBase* const reply_queue_;
172 rtc::Event& event_;
173 };
174
175 auto task =
176 absl::make_unique<ReusedTask>(&call_count, reply_queue.get(), &event);
177 post_queue->PostTask(std::move(task));
178 EXPECT_TRUE(event.Wait(1000));
179}
180
181// Tests posting more messages than a queue can queue up.
182// In situations like that, tasks will get dropped.
183TEST_P(TaskQueueTest, PostALot) {
184 // To destruct the event after the queue has gone out of scope.
185 rtc::Event event;
186
187 int tasks_executed = 0;
188 int tasks_cleaned_up = 0;
189 static const int kTaskCount = 0xffff;
190
191 {
192 auto queue = CreateTaskQueue(GetParam(), "PostALot");
193
194 // On linux, the limit of pending bytes in the pipe buffer is 0xffff.
195 // So here we post a total of 0xffff+1 messages, which triggers a failure
196 // case inside of the libevent queue implementation.
197
198 queue->PostTask(
199 rtc::NewClosure([&event] { event.Wait(rtc::Event::kForever); }));
200 for (int i = 0; i < kTaskCount; ++i)
201 queue->PostTask(
202 rtc::NewClosure([&tasks_executed] { ++tasks_executed; },
203 [&tasks_cleaned_up] { ++tasks_cleaned_up; }));
204 event.Set(); // Unblock the first task.
205 }
206
207 EXPECT_GE(tasks_cleaned_up, tasks_executed);
208 EXPECT_EQ(tasks_cleaned_up, kTaskCount);
209}
210
211} // namespace
212} // namespace webrtc