blob: d7d6a0129e49779564394f56acc33ed60d982f89 [file] [log] [blame]
henrike@webrtc.org0e118e72013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2004--2011, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +000028#include "talk/base/asyncinvoker.h"
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000029#include "talk/base/asyncudpsocket.h"
30#include "talk/base/event.h"
31#include "talk/base/gunit.h"
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000032#include "talk/base/physicalsocketserver.h"
33#include "talk/base/socketaddress.h"
34#include "talk/base/thread.h"
35
36#ifdef WIN32
37#include <comdef.h> // NOLINT
38#endif
39
40using namespace talk_base;
41
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000042// Generates a sequence of numbers (collaboratively).
43class TestGenerator {
44 public:
45 TestGenerator() : last(0), count(0) {}
46
47 int Next(int prev) {
48 int result = prev + last;
49 last = result;
50 count += 1;
51 return result;
52 }
53
54 int last;
55 int count;
56};
57
58struct TestMessage : public MessageData {
59 explicit TestMessage(int v) : value(v) {}
60 virtual ~TestMessage() {}
61
62 int value;
63};
64
65// Receives on a socket and sends by posting messages.
66class SocketClient : public TestGenerator, public sigslot::has_slots<> {
67 public:
68 SocketClient(AsyncSocket* socket, const SocketAddress& addr,
69 Thread* post_thread, MessageHandler* phandler)
70 : socket_(AsyncUDPSocket::Create(socket, addr)),
71 post_thread_(post_thread),
72 post_handler_(phandler) {
73 socket_->SignalReadPacket.connect(this, &SocketClient::OnPacket);
74 }
75
76 ~SocketClient() {
77 delete socket_;
78 }
79
80 SocketAddress address() const { return socket_->GetLocalAddress(); }
81
82 void OnPacket(AsyncPacketSocket* socket, const char* buf, size_t size,
wu@webrtc.orgf89a4032013-12-13 00:21:03 +000083 const SocketAddress& remote_addr,
84 const PacketTime& packet_time) {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000085 EXPECT_EQ(size, sizeof(uint32));
86 uint32 prev = reinterpret_cast<const uint32*>(buf)[0];
87 uint32 result = Next(prev);
88
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000089 post_thread_->PostDelayed(200, post_handler_, 0, new TestMessage(result));
90 }
91
92 private:
93 AsyncUDPSocket* socket_;
94 Thread* post_thread_;
95 MessageHandler* post_handler_;
96};
97
98// Receives messages and sends on a socket.
99class MessageClient : public MessageHandler, public TestGenerator {
100 public:
101 MessageClient(Thread* pth, Socket* socket)
henrike@webrtc.orga518cc92014-04-07 20:49:34 +0000102 : socket_(socket) {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000103 }
104
105 virtual ~MessageClient() {
106 delete socket_;
107 }
108
109 virtual void OnMessage(Message *pmsg) {
110 TestMessage* msg = static_cast<TestMessage*>(pmsg->pdata);
111 int result = Next(msg->value);
112 EXPECT_GE(socket_->Send(&result, sizeof(result)), 0);
113 delete msg;
114 }
115
116 private:
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000117 Socket* socket_;
118};
119
120class CustomThread : public talk_base::Thread {
121 public:
122 CustomThread() {}
wu@webrtc.orge5b49102013-10-18 16:27:26 +0000123 virtual ~CustomThread() { Stop(); }
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000124 bool Start() { return false; }
125};
126
127
128// A thread that does nothing when it runs and signals an event
129// when it is destroyed.
130class SignalWhenDestroyedThread : public Thread {
131 public:
132 SignalWhenDestroyedThread(Event* event)
133 : event_(event) {
134 }
135
136 virtual ~SignalWhenDestroyedThread() {
wu@webrtc.orge5b49102013-10-18 16:27:26 +0000137 Stop();
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000138 event_->Set();
139 }
140
141 virtual void Run() {
142 // Do nothing.
143 }
144
145 private:
146 Event* event_;
147};
148
149// Function objects to test Thread::Invoke.
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +0000150struct FunctorA {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000151 int operator()() { return 42; }
152};
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +0000153class FunctorB {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000154 public:
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +0000155 explicit FunctorB(bool* flag) : flag_(flag) {}
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000156 void operator()() { if (flag_) *flag_ = true; }
157 private:
158 bool* flag_;
159};
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +0000160struct FunctorC {
161 int operator()() {
162 Thread::Current()->ProcessMessages(50);
163 return 24;
164 }
165};
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000166
andrew@webrtc.org9fde9662013-09-25 02:33:50 +0000167// See: https://code.google.com/p/webrtc/issues/detail?id=2409
168TEST(ThreadTest, DISABLED_Main) {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000169 const SocketAddress addr("127.0.0.1", 0);
170
171 // Create the messaging client on its own thread.
172 Thread th1;
173 Socket* socket = th1.socketserver()->CreateAsyncSocket(addr.family(),
174 SOCK_DGRAM);
175 MessageClient msg_client(&th1, socket);
176
177 // Create the socket client on its own thread.
178 Thread th2;
179 AsyncSocket* asocket =
180 th2.socketserver()->CreateAsyncSocket(addr.family(), SOCK_DGRAM);
181 SocketClient sock_client(asocket, addr, &th1, &msg_client);
182
183 socket->Connect(sock_client.address());
184
185 th1.Start();
186 th2.Start();
187
188 // Get the messages started.
189 th1.PostDelayed(100, &msg_client, 0, new TestMessage(1));
190
191 // Give the clients a little while to run.
192 // Messages will be processed at 100, 300, 500, 700, 900.
193 Thread* th_main = Thread::Current();
194 th_main->ProcessMessages(1000);
195
196 // Stop the sending client. Give the receiver a bit longer to run, in case
197 // it is running on a machine that is under load (e.g. the build machine).
198 th1.Stop();
199 th_main->ProcessMessages(200);
200 th2.Stop();
201
202 // Make sure the results were correct
203 EXPECT_EQ(5, msg_client.count);
204 EXPECT_EQ(34, msg_client.last);
205 EXPECT_EQ(5, sock_client.count);
206 EXPECT_EQ(55, sock_client.last);
207}
208
209// Test that setting thread names doesn't cause a malfunction.
210// There's no easy way to verify the name was set properly at this time.
211TEST(ThreadTest, Names) {
212 // Default name
213 Thread *thread;
214 thread = new Thread();
215 EXPECT_TRUE(thread->Start());
216 thread->Stop();
217 delete thread;
218 thread = new Thread();
219 // Name with no object parameter
220 EXPECT_TRUE(thread->SetName("No object", NULL));
221 EXPECT_TRUE(thread->Start());
222 thread->Stop();
223 delete thread;
224 // Really long name
225 thread = new Thread();
226 EXPECT_TRUE(thread->SetName("Abcdefghijklmnopqrstuvwxyz1234567890", this));
227 EXPECT_TRUE(thread->Start());
228 thread->Stop();
229 delete thread;
230}
231
232// Test that setting thread priorities doesn't cause a malfunction.
233// There's no easy way to verify the priority was set properly at this time.
234TEST(ThreadTest, Priorities) {
235 Thread *thread;
236 thread = new Thread();
237 EXPECT_TRUE(thread->SetPriority(PRIORITY_HIGH));
238 EXPECT_TRUE(thread->Start());
239 thread->Stop();
240 delete thread;
241 thread = new Thread();
242 EXPECT_TRUE(thread->SetPriority(PRIORITY_ABOVE_NORMAL));
243 EXPECT_TRUE(thread->Start());
244 thread->Stop();
245 delete thread;
246
247 thread = new Thread();
248 EXPECT_TRUE(thread->Start());
249#ifdef WIN32
250 EXPECT_TRUE(thread->SetPriority(PRIORITY_ABOVE_NORMAL));
251#else
252 EXPECT_FALSE(thread->SetPriority(PRIORITY_ABOVE_NORMAL));
253#endif
254 thread->Stop();
255 delete thread;
256
257}
258
259TEST(ThreadTest, Wrap) {
260 Thread* current_thread = Thread::Current();
261 current_thread->UnwrapCurrent();
262 CustomThread* cthread = new CustomThread();
263 EXPECT_TRUE(cthread->WrapCurrent());
fischman@webrtc.org738caf82014-05-23 17:28:50 +0000264 EXPECT_TRUE(cthread->RunningForTest());
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000265 EXPECT_FALSE(cthread->IsOwned());
266 cthread->UnwrapCurrent();
fischman@webrtc.org738caf82014-05-23 17:28:50 +0000267 EXPECT_FALSE(cthread->RunningForTest());
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000268 delete cthread;
269 current_thread->WrapCurrent();
270}
271
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000272TEST(ThreadTest, Invoke) {
273 // Create and start the thread.
274 Thread thread;
275 thread.Start();
276 // Try calling functors.
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +0000277 EXPECT_EQ(42, thread.Invoke<int>(FunctorA()));
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000278 bool called = false;
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +0000279 FunctorB f2(&called);
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000280 thread.Invoke<void>(f2);
281 EXPECT_TRUE(called);
282 // Try calling bare functions.
283 struct LocalFuncs {
284 static int Func1() { return 999; }
285 static void Func2() {}
286 };
287 EXPECT_EQ(999, thread.Invoke<int>(&LocalFuncs::Func1));
288 thread.Invoke<void>(&LocalFuncs::Func2);
289}
290
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +0000291class AsyncInvokeTest : public testing::Test {
292 public:
293 void IntCallback(int value) {
294 EXPECT_EQ(expected_thread_, Thread::Current());
295 int_value_ = value;
296 }
297 void AsyncInvokeIntCallback(AsyncInvoker* invoker, Thread* thread) {
298 expected_thread_ = thread;
299 invoker->AsyncInvoke(thread, FunctorC(),
300 &AsyncInvokeTest::IntCallback,
301 static_cast<AsyncInvokeTest*>(this));
302 invoke_started_.Set();
303 }
304 void SetExpectedThreadForIntCallback(Thread* thread) {
305 expected_thread_ = thread;
306 }
307
308 protected:
309 enum { kWaitTimeout = 1000 };
310 AsyncInvokeTest()
311 : int_value_(0),
312 invoke_started_(true, false),
313 expected_thread_(NULL) {}
314
315 int int_value_;
316 Event invoke_started_;
317 Thread* expected_thread_;
318};
319
henrike@webrtc.org54caffd2014-02-14 23:38:45 +0000320TEST_F(AsyncInvokeTest, FireAndForget) {
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +0000321 AsyncInvoker invoker;
322 // Create and start the thread.
323 Thread thread;
324 thread.Start();
325 // Try calling functor.
326 bool called = false;
327 invoker.AsyncInvoke<void>(&thread, FunctorB(&called));
328 EXPECT_TRUE_WAIT(called, kWaitTimeout);
329}
330
henrike@webrtc.org54caffd2014-02-14 23:38:45 +0000331TEST_F(AsyncInvokeTest, WithCallback) {
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +0000332 AsyncInvoker invoker;
333 // Create and start the thread.
334 Thread thread;
335 thread.Start();
336 // Try calling functor.
337 SetExpectedThreadForIntCallback(Thread::Current());
338 invoker.AsyncInvoke(&thread, FunctorA(),
339 &AsyncInvokeTest::IntCallback,
340 static_cast<AsyncInvokeTest*>(this));
341 EXPECT_EQ_WAIT(42, int_value_, kWaitTimeout);
342}
343
henrike@webrtc.org54caffd2014-02-14 23:38:45 +0000344TEST_F(AsyncInvokeTest, CancelInvoker) {
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +0000345 // Create and start the thread.
346 Thread thread;
347 thread.Start();
348 // Try destroying invoker during call.
349 {
350 AsyncInvoker invoker;
351 invoker.AsyncInvoke(&thread, FunctorC(),
352 &AsyncInvokeTest::IntCallback,
353 static_cast<AsyncInvokeTest*>(this));
354 }
355 // With invoker gone, callback should be cancelled.
356 Thread::Current()->ProcessMessages(kWaitTimeout);
357 EXPECT_EQ(0, int_value_);
358}
359
henrike@webrtc.org54caffd2014-02-14 23:38:45 +0000360TEST_F(AsyncInvokeTest, CancelCallingThread) {
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +0000361 AsyncInvoker invoker;
362 { // Create and start the thread.
363 Thread thread;
364 thread.Start();
365 // Try calling functor.
366 thread.Invoke<void>(Bind(&AsyncInvokeTest::AsyncInvokeIntCallback,
367 static_cast<AsyncInvokeTest*>(this),
368 &invoker, Thread::Current()));
369 // Wait for the call to begin.
370 ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
371 }
372 // Calling thread is gone. Return message shouldn't happen.
373 Thread::Current()->ProcessMessages(kWaitTimeout);
374 EXPECT_EQ(0, int_value_);
375}
376
henrike@webrtc.org54caffd2014-02-14 23:38:45 +0000377TEST_F(AsyncInvokeTest, KillInvokerBeforeExecute) {
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +0000378 Thread thread;
379 thread.Start();
380 {
381 AsyncInvoker invoker;
382 // Try calling functor.
383 thread.Invoke<void>(Bind(&AsyncInvokeTest::AsyncInvokeIntCallback,
384 static_cast<AsyncInvokeTest*>(this),
385 &invoker, Thread::Current()));
386 // Wait for the call to begin.
387 ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
388 }
389 // Invoker is destroyed. Function should not execute.
390 Thread::Current()->ProcessMessages(kWaitTimeout);
391 EXPECT_EQ(0, int_value_);
392}
393
henrike@webrtc.org54caffd2014-02-14 23:38:45 +0000394TEST_F(AsyncInvokeTest, Flush) {
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +0000395 AsyncInvoker invoker;
396 bool flag1 = false;
397 bool flag2 = false;
398 // Queue two async calls to the current thread.
399 invoker.AsyncInvoke<void>(Thread::Current(),
400 FunctorB(&flag1));
401 invoker.AsyncInvoke<void>(Thread::Current(),
402 FunctorB(&flag2));
403 // Because we haven't pumped messages, these should not have run yet.
404 EXPECT_FALSE(flag1);
405 EXPECT_FALSE(flag2);
406 // Force them to run now.
407 invoker.Flush(Thread::Current());
408 EXPECT_TRUE(flag1);
409 EXPECT_TRUE(flag2);
410}
411
henrike@webrtc.org54caffd2014-02-14 23:38:45 +0000412TEST_F(AsyncInvokeTest, FlushWithIds) {
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +0000413 AsyncInvoker invoker;
414 bool flag1 = false;
415 bool flag2 = false;
416 // Queue two async calls to the current thread, one with a message id.
417 invoker.AsyncInvoke<void>(Thread::Current(),
418 FunctorB(&flag1),
419 5);
420 invoker.AsyncInvoke<void>(Thread::Current(),
421 FunctorB(&flag2));
422 // Because we haven't pumped messages, these should not have run yet.
423 EXPECT_FALSE(flag1);
424 EXPECT_FALSE(flag2);
425 // Execute pending calls with id == 5.
426 invoker.Flush(Thread::Current(), 5);
427 EXPECT_TRUE(flag1);
428 EXPECT_FALSE(flag2);
429 flag1 = false;
430 // Execute all pending calls. The id == 5 call should not execute again.
431 invoker.Flush(Thread::Current());
432 EXPECT_FALSE(flag1);
433 EXPECT_TRUE(flag2);
434}
435
436
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000437#ifdef WIN32
438class ComThreadTest : public testing::Test, public MessageHandler {
439 public:
440 ComThreadTest() : done_(false) {}
441 protected:
442 virtual void OnMessage(Message* message) {
443 HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
444 // S_FALSE means the thread was already inited for a multithread apartment.
445 EXPECT_EQ(S_FALSE, hr);
446 if (SUCCEEDED(hr)) {
447 CoUninitialize();
448 }
449 done_ = true;
450 }
451 bool done_;
452};
453
454TEST_F(ComThreadTest, ComInited) {
455 Thread* thread = new ComThread();
456 EXPECT_TRUE(thread->Start());
457 thread->Post(this, 0);
458 EXPECT_TRUE_WAIT(done_, 1000);
459 delete thread;
460}
461#endif