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, PostLambda) { | |
52 static const char kQueueName[] = "PostLambda"; | |
53 TaskQueue queue(kQueueName); | |
54 | |
55 Event event(false, false); | |
56 queue.PostTask([&event]() { event.Set(); }); | |
57 EXPECT_TRUE(event.Wait(1000)); | |
58 } | |
59 | |
60 TEST(TaskQueueTest, PostFromQueue) { | |
61 static const char kQueueName[] = "PostFromQueue"; | |
62 TaskQueue queue(kQueueName); | |
63 | |
64 Event event(false, false); | |
65 queue.PostTask( | |
66 [&event, &queue]() { queue.PostTask([&event]() { event.Set(); }); }); | |
67 EXPECT_TRUE(event.Wait(1000)); | |
68 } | |
69 | |
70 TEST(TaskQueueTest, PostDelayed) { | |
71 static const char kQueueName[] = "PostDelayed"; | |
72 TaskQueue queue(kQueueName); | |
73 | |
74 Event event(false, false); | |
75 uint32_t start = Time(); | |
76 queue.PostDelayedTask(Bind(&CheckCurrent, kQueueName, &event, &queue), 100); | |
77 EXPECT_TRUE(event.Wait(1000)); | |
78 uint32_t end = Time(); | |
79 EXPECT_GE(end - start, 100u); | |
perkj_webrtc
2016/04/26 14:30:38
EXPECT_NEAR ? to check an upper bound.
tommi
2016/04/28 12:04:02
Done.
| |
80 } | |
81 | |
82 TEST(TaskQueueTest, PostMultipleDelayed) { | |
83 static const char kQueueName[] = "PostMultipleDelayed"; | |
84 TaskQueue queue(kQueueName); | |
85 | |
86 std::vector<std::unique_ptr<Event>> events; | |
87 for (int i = 0; i < 10; ++i) { | |
88 events.push_back(std::unique_ptr<Event>(new Event(false, false))); | |
89 queue.PostDelayedTask( | |
90 Bind(&CheckCurrent, kQueueName, events.back().get(), &queue), 10); | |
91 } | |
92 | |
93 for (const auto& e : events) | |
94 EXPECT_TRUE(e->Wait(100)); | |
95 } | |
96 | |
97 TEST(TaskQueueTest, PostDelayedAfterDestruct) { | |
98 static const char kQueueName[] = "PostDelayedAfterDestruct"; | |
99 Event event(false, false); | |
100 { | |
101 TaskQueue queue(kQueueName); | |
102 queue.PostDelayedTask(Bind(&CheckCurrent, kQueueName, &event, &queue), 100); | |
103 } | |
104 EXPECT_FALSE(event.Wait(200)); // Task should not run. | |
105 } | |
106 | |
107 TEST(TaskQueueTest, PostAndReply) { | |
108 static const char kPostQueue[] = "PostQueue"; | |
109 static const char kReplyQueue[] = "ReplyQueue"; | |
110 TaskQueue post_queue(kPostQueue); | |
111 TaskQueue reply_queue(kReplyQueue); | |
112 | |
113 Event event(false, false); | |
114 post_queue.PostTaskAndReply( | |
115 Bind(&CheckCurrent, kPostQueue, nullptr, &post_queue), | |
116 Bind(&CheckCurrent, kReplyQueue, &event, &reply_queue), &reply_queue); | |
117 EXPECT_TRUE(event.Wait(1000)); | |
118 } | |
119 | |
120 TEST(TaskQueueTest, PostAndReuse) { | |
121 static const char kPostQueue[] = "PostQueue"; | |
122 static const char kReplyQueue[] = "ReplyQueue"; | |
123 TaskQueue post_queue(kPostQueue); | |
124 TaskQueue reply_queue(kReplyQueue); | |
125 | |
126 int call_count = 0; | |
127 | |
128 class ReusedTask : public QueuedTask { | |
129 public: | |
130 ReusedTask(int* counter, TaskQueue* reply_queue, Event* event) | |
131 : counter_(counter), reply_queue_(reply_queue), event_(event) { | |
132 EXPECT_EQ(0, *counter_); | |
133 } | |
134 | |
135 private: | |
136 bool Run() override { | |
137 if (++(*counter_) == 1) { | |
138 std::unique_ptr<QueuedTask> myself(this); | |
139 reply_queue_->PostTask(std::move(myself)); | |
140 // At this point, the object is owned by reply_queue_ and it's | |
141 // theoratically possible that the object has been deleted (e.g. if | |
142 // posting wasn't possible). So, don't touch any member variables here. | |
143 | |
144 // Indicate to the current queue that ownership has been transferred. | |
145 return false; | |
146 } else { | |
147 EXPECT_EQ(2, *counter_); | |
148 EXPECT_TRUE(reply_queue_->IsCurrent()); | |
149 event_->Set(); | |
150 return true; // Indicate that the object should be deleted. | |
151 } | |
152 } | |
153 | |
154 int* const counter_; | |
155 TaskQueue* const reply_queue_; | |
156 Event* const event_; | |
157 }; | |
158 | |
159 Event event(false, false); | |
160 std::unique_ptr<QueuedTask> task( | |
161 new ReusedTask(&call_count, &reply_queue, &event)); | |
162 | |
163 post_queue.PostTask(std::move(task)); | |
164 EXPECT_TRUE(event.Wait(1000)); | |
165 } | |
166 | |
167 TEST(TaskQueueTest, PostAndReplyLambda) { | |
168 static const char kPostQueue[] = "PostQueue"; | |
169 static const char kReplyQueue[] = "ReplyQueue"; | |
170 TaskQueue post_queue(kPostQueue); | |
171 TaskQueue reply_queue(kReplyQueue); | |
172 | |
173 Event event(false, false); | |
174 bool my_flag = false; | |
175 post_queue.PostTaskAndReply([&my_flag]() { my_flag = true; }, | |
176 [&event]() { event.Set(); }, &reply_queue); | |
177 EXPECT_TRUE(event.Wait(1000)); | |
178 EXPECT_TRUE(my_flag); | |
179 } | |
180 | |
181 void TestPostTaskAndReply(TaskQueue* work_queue, | |
182 const char* work_queue_name, | |
183 Event* event) { | |
184 ASSERT_FALSE(work_queue->IsCurrent()); | |
185 work_queue->PostTaskAndReply( | |
186 Bind(&CheckCurrent, work_queue_name, nullptr, work_queue), | |
187 Bind(&Event::Set, event)); | |
188 } | |
189 | |
190 // Does a PostTaskAndReply from within a task to post and reply to the current | |
191 // queue. All in all there will be 3 tasks posted and run. | |
192 TEST(TaskQueueTest, PostAndReply2) { | |
193 static const char kQueueName[] = "PostAndReply2"; | |
194 static const char kWorkQueueName[] = "PostAndReply2_Worker"; | |
195 TaskQueue queue(kQueueName); | |
196 TaskQueue work_queue(kWorkQueueName); | |
197 | |
198 Event event(false, false); | |
199 queue.PostTask( | |
200 Bind(&TestPostTaskAndReply, &work_queue, kWorkQueueName, &event)); | |
201 EXPECT_TRUE(event.Wait(1000)); | |
202 } | |
203 | |
204 TEST(TaskQueueTest, PostALot) { | |
205 // To destruct the event after the queue has gone out of scope. | |
206 Event event(false, false); | |
207 | |
208 static const char kQueueName[] = "PostALot"; | |
209 TaskQueue queue(kQueueName); | |
210 | |
211 // On linux, the limit of pending bytes in the pipe buffer is 0xffff. | |
212 // So here we post a total of 0xffff+1 messages, which triggers a failure case | |
213 // inside of the libevent queue implementation. | |
214 | |
215 queue.PostTask([&event]() { event.Wait(Event::kForever); }); | |
216 for (int i = 0; i < 0xffff; ++i) | |
217 queue.PostTask([]() {}); | |
218 event.Set(); | |
219 } | |
220 | |
221 } // namespace rtc | |
OLD | NEW |