OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright 2016 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 <memory> | |
12 #include <vector> | |
13 | |
14 #include "webrtc/base/bind.h" | |
15 #include "webrtc/base/event.h" | |
16 #include "webrtc/base/gunit.h" | |
17 #include "webrtc/base/task_queue.h" | |
18 #include "webrtc/base/timeutils.h" | |
19 | |
20 namespace rtc { | |
21 | |
22 namespace { | |
23 void CheckCurrent(const char* expected_queue, Event* signal, TaskQueue* queue) { | |
24 EXPECT_TRUE(TaskQueue::IsCurrent(expected_queue)); | |
25 EXPECT_TRUE(queue->IsCurrent()); | |
26 if (signal) | |
27 signal->Set(); | |
28 } | |
29 | |
30 } // namespace | |
31 | |
32 TEST(TaskQueueTest, Construct) { | |
33 static const char kQueueName[] = "Construct"; | |
34 TaskQueue queue(kQueueName); | |
35 EXPECT_FALSE(queue.IsCurrent()); | |
36 } | |
37 | |
38 TEST(TaskQueueTest, PostAndCheckCurrent) { | |
39 static const char kQueueName[] = "PostAndCheckCurrent"; | |
40 TaskQueue queue(kQueueName); | |
41 | |
42 // We're not running a task, so there shouldn't be a current queue. | |
43 EXPECT_FALSE(queue.IsCurrent()); | |
44 EXPECT_FALSE(TaskQueue::Current()); | |
45 | |
46 Event event(false, false); | |
47 queue.PostTask(Bind(&CheckCurrent, kQueueName, &event, &queue)); | |
48 EXPECT_TRUE(event.Wait(1000)); | |
49 } | |
50 | |
51 TEST(TaskQueueTest, PostCustomTask) { | |
52 static const char kQueueName[] = "PostCustomImplementation"; | |
53 TaskQueue queue(kQueueName); | |
54 | |
55 Event event(false, false); | |
56 | |
57 class CustomTask : public QueuedTask { | |
58 public: | |
59 CustomTask(Event* event) : event_(event) {} | |
60 | |
61 private: | |
62 bool Run() override { | |
63 event_->Set(); | |
64 return false; // Never allows the task to be deleted by the queue. | |
65 } | |
66 | |
67 Event* const event_; | |
68 }; | |
69 | |
70 queue.PostTask(std::unique_ptr<QueuedTask>(new CustomTask(&event))); | |
perkj_webrtc
2016/04/28 14:40:18
leaks CustomTask since Run returns false :-> See b
tommi
2016/04/28 15:30:33
Ah, thanks. I was debating allocating the task in
| |
71 EXPECT_TRUE(event.Wait(1000)); | |
72 } | |
73 | |
74 TEST(TaskQueueTest, PostLambda) { | |
75 static const char kQueueName[] = "PostLambda"; | |
76 TaskQueue queue(kQueueName); | |
77 | |
78 Event event(false, false); | |
79 queue.PostTask([&event]() { event.Set(); }); | |
80 EXPECT_TRUE(event.Wait(1000)); | |
81 } | |
82 | |
83 TEST(TaskQueueTest, PostFromQueue) { | |
84 static const char kQueueName[] = "PostFromQueue"; | |
85 TaskQueue queue(kQueueName); | |
86 | |
87 Event event(false, false); | |
88 queue.PostTask( | |
89 [&event, &queue]() { queue.PostTask([&event]() { event.Set(); }); }); | |
90 EXPECT_TRUE(event.Wait(1000)); | |
91 } | |
92 | |
93 TEST(TaskQueueTest, PostDelayed) { | |
94 static const char kQueueName[] = "PostDelayed"; | |
95 TaskQueue queue(kQueueName); | |
96 | |
97 Event event(false, false); | |
98 uint32_t start = Time(); | |
99 queue.PostDelayedTask(Bind(&CheckCurrent, kQueueName, &event, &queue), 100); | |
100 EXPECT_TRUE(event.Wait(1000)); | |
101 uint32_t end = Time(); | |
102 EXPECT_GE(end - start, 100u); | |
103 EXPECT_NEAR(end - start, 200u, 100u); // Accept 100-300. | |
perkj_webrtc
2016/04/28 14:40:18
200?
tommi
2016/04/28 15:30:33
Yes... I figured that because some of our trybots
| |
104 } | |
105 | |
106 TEST(TaskQueueTest, PostMultipleDelayed) { | |
107 static const char kQueueName[] = "PostMultipleDelayed"; | |
108 TaskQueue queue(kQueueName); | |
109 | |
110 std::vector<std::unique_ptr<Event>> events; | |
111 for (int i = 0; i < 10; ++i) { | |
112 events.push_back(std::unique_ptr<Event>(new Event(false, false))); | |
113 queue.PostDelayedTask( | |
114 Bind(&CheckCurrent, kQueueName, events.back().get(), &queue), 10); | |
115 } | |
116 | |
117 for (const auto& e : events) | |
118 EXPECT_TRUE(e->Wait(100)); | |
119 } | |
120 | |
121 TEST(TaskQueueTest, PostDelayedAfterDestruct) { | |
122 static const char kQueueName[] = "PostDelayedAfterDestruct"; | |
123 Event event(false, false); | |
124 { | |
125 TaskQueue queue(kQueueName); | |
126 queue.PostDelayedTask(Bind(&CheckCurrent, kQueueName, &event, &queue), 100); | |
127 } | |
128 EXPECT_FALSE(event.Wait(200)); // Task should not run. | |
129 } | |
130 | |
131 TEST(TaskQueueTest, PostAndReply) { | |
132 static const char kPostQueue[] = "PostQueue"; | |
133 static const char kReplyQueue[] = "ReplyQueue"; | |
134 TaskQueue post_queue(kPostQueue); | |
135 TaskQueue reply_queue(kReplyQueue); | |
136 | |
137 Event event(false, false); | |
138 post_queue.PostTaskAndReply( | |
139 Bind(&CheckCurrent, kPostQueue, nullptr, &post_queue), | |
140 Bind(&CheckCurrent, kReplyQueue, &event, &reply_queue), &reply_queue); | |
perkj_webrtc
2016/04/28 14:40:17
So you made PostTaskAndReply to another queue publ
tommi
2016/04/28 15:30:33
It was already public. I had forgotten about this
| |
141 EXPECT_TRUE(event.Wait(1000)); | |
142 } | |
143 | |
144 TEST(TaskQueueTest, PostAndReuse) { | |
145 static const char kPostQueue[] = "PostQueue"; | |
146 static const char kReplyQueue[] = "ReplyQueue"; | |
147 TaskQueue post_queue(kPostQueue); | |
148 TaskQueue reply_queue(kReplyQueue); | |
149 | |
150 int call_count = 0; | |
151 | |
152 class ReusedTask : public QueuedTask { | |
153 public: | |
154 ReusedTask(int* counter, TaskQueue* reply_queue, Event* event) | |
155 : counter_(counter), reply_queue_(reply_queue), event_(event) { | |
156 EXPECT_EQ(0, *counter_); | |
157 } | |
158 | |
159 private: | |
160 bool Run() override { | |
161 if (++(*counter_) == 1) { | |
162 std::unique_ptr<QueuedTask> myself(this); | |
163 reply_queue_->PostTask(std::move(myself)); | |
164 // At this point, the object is owned by reply_queue_ and it's | |
165 // theoratically possible that the object has been deleted (e.g. if | |
166 // posting wasn't possible). So, don't touch any member variables here. | |
167 | |
168 // Indicate to the current queue that ownership has been transferred. | |
169 return false; | |
170 } else { | |
171 EXPECT_EQ(2, *counter_); | |
172 EXPECT_TRUE(reply_queue_->IsCurrent()); | |
173 event_->Set(); | |
174 return true; // Indicate that the object should be deleted. | |
175 } | |
176 } | |
177 | |
178 int* const counter_; | |
179 TaskQueue* const reply_queue_; | |
180 Event* const event_; | |
181 }; | |
182 | |
183 Event event(false, false); | |
184 std::unique_ptr<QueuedTask> task( | |
185 new ReusedTask(&call_count, &reply_queue, &event)); | |
186 | |
187 post_queue.PostTask(std::move(task)); | |
188 EXPECT_TRUE(event.Wait(1000)); | |
189 } | |
190 | |
191 TEST(TaskQueueTest, PostAndReplyLambda) { | |
192 static const char kPostQueue[] = "PostQueue"; | |
193 static const char kReplyQueue[] = "ReplyQueue"; | |
194 TaskQueue post_queue(kPostQueue); | |
195 TaskQueue reply_queue(kReplyQueue); | |
196 | |
197 Event event(false, false); | |
198 bool my_flag = false; | |
199 post_queue.PostTaskAndReply([&my_flag]() { my_flag = true; }, | |
200 [&event]() { event.Set(); }, &reply_queue); | |
201 EXPECT_TRUE(event.Wait(1000)); | |
202 EXPECT_TRUE(my_flag); | |
203 } | |
204 | |
205 void TestPostTaskAndReply(TaskQueue* work_queue, | |
206 const char* work_queue_name, | |
207 Event* event) { | |
208 ASSERT_FALSE(work_queue->IsCurrent()); | |
209 work_queue->PostTaskAndReply( | |
210 Bind(&CheckCurrent, work_queue_name, nullptr, work_queue), | |
211 NewClosure([event]() { event->Set(); })); | |
212 } | |
213 | |
214 // Does a PostTaskAndReply from within a task to post and reply to the current | |
215 // queue. All in all there will be 3 tasks posted and run. | |
216 TEST(TaskQueueTest, PostAndReply2) { | |
217 static const char kQueueName[] = "PostAndReply2"; | |
218 static const char kWorkQueueName[] = "PostAndReply2_Worker"; | |
219 TaskQueue queue(kQueueName); | |
220 TaskQueue work_queue(kWorkQueueName); | |
221 | |
222 Event event(false, false); | |
223 queue.PostTask( | |
224 Bind(&TestPostTaskAndReply, &work_queue, kWorkQueueName, &event)); | |
225 EXPECT_TRUE(event.Wait(1000)); | |
226 } | |
227 | |
228 TEST(TaskQueueTest, PostALot) { | |
perkj_webrtc
2016/04/28 14:40:18
please add a better description of what this tests
tommi
2016/04/28 15:30:33
Done.
I also modified the test a bit as well as s
| |
229 // To destruct the event after the queue has gone out of scope. | |
230 Event event(false, false); | |
231 | |
232 static const char kQueueName[] = "PostALot"; | |
perkj_webrtc
2016/04/28 14:40:18
why static?
tommi
2016/04/28 15:30:33
since this is supposed to be a compile-time consta
| |
233 TaskQueue queue(kQueueName); | |
234 | |
235 // On linux, the limit of pending bytes in the pipe buffer is 0xffff. | |
236 // So here we post a total of 0xffff+1 messages, which triggers a failure case | |
237 // inside of the libevent queue implementation. | |
238 | |
239 queue.PostTask([&event]() { event.Wait(Event::kForever); }); | |
240 for (int i = 0; i < 0xffff; ++i) | |
241 queue.PostTask([]() {}); | |
242 event.Set(); | |
243 } | |
244 | |
245 } // namespace rtc | |
OLD | NEW |