blob: 1465d04f2f60c9967ec71b7b718cb596d243d2ea [file] [log] [blame]
henrike@webrtc.org28e20752013-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.org9cf037b2014-02-07 19:03:26 +000028#include "talk/base/asyncinvoker.h"
henrike@webrtc.org28e20752013-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.org28e20752013-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.org28e20752013-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.orga9890802013-12-13 00:21:03 +000083 const SocketAddress& remote_addr,
84 const PacketTime& packet_time) {
henrike@webrtc.org28e20752013-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.org28e20752013-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.org74a7c482014-04-07 20:49:34 +0000102 : socket_(socket) {
henrike@webrtc.org28e20752013-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.org28e20752013-07-10 00:45:36 +0000117 Socket* socket_;
118};
119
120class CustomThread : public talk_base::Thread {
121 public:
122 CustomThread() {}
wu@webrtc.org3c5d2b42013-10-18 16:27:26 +0000123 virtual ~CustomThread() { Stop(); }
henrike@webrtc.org28e20752013-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.org3c5d2b42013-10-18 16:27:26 +0000137 Stop();
henrike@webrtc.org28e20752013-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.org9cf037b2014-02-07 19:03:26 +0000150struct FunctorA {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000151 int operator()() { return 42; }
152};
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000153class FunctorB {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000154 public:
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000155 explicit FunctorB(bool* flag) : flag_(flag) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000156 void operator()() { if (flag_) *flag_ = true; }
157 private:
158 bool* flag_;
159};
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000160struct FunctorC {
161 int operator()() {
162 Thread::Current()->ProcessMessages(50);
163 return 24;
164 }
165};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000166
andrew@webrtc.org2f240b42013-09-25 02:33:50 +0000167// See: https://code.google.com/p/webrtc/issues/detail?id=2409
168TEST(ThreadTest, DISABLED_Main) {
henrike@webrtc.org28e20752013-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());
264 EXPECT_TRUE(cthread->started());
265 EXPECT_FALSE(cthread->IsOwned());
266 cthread->UnwrapCurrent();
267 EXPECT_FALSE(cthread->started());
268 delete cthread;
269 current_thread->WrapCurrent();
270}
271
272// Test that calling Release on a thread causes it to self-destruct when
273// it's finished running
274TEST(ThreadTest, Release) {
275 scoped_ptr<Event> event(new Event(true, false));
276 // Ensure the event is initialized.
277 event->Reset();
278
279 Thread* thread = new SignalWhenDestroyedThread(event.get());
280 thread->Start();
281 thread->Release();
282
283 // The event should get signaled when the thread completes, which should
284 // be nearly instantaneous, since it doesn't do anything. For safety,
285 // give it 3 seconds in case the machine is under load.
286 bool signaled = event->Wait(3000);
287 EXPECT_TRUE(signaled);
288}
289
290TEST(ThreadTest, Invoke) {
291 // Create and start the thread.
292 Thread thread;
293 thread.Start();
294 // Try calling functors.
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000295 EXPECT_EQ(42, thread.Invoke<int>(FunctorA()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000296 bool called = false;
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000297 FunctorB f2(&called);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000298 thread.Invoke<void>(f2);
299 EXPECT_TRUE(called);
300 // Try calling bare functions.
301 struct LocalFuncs {
302 static int Func1() { return 999; }
303 static void Func2() {}
304 };
305 EXPECT_EQ(999, thread.Invoke<int>(&LocalFuncs::Func1));
306 thread.Invoke<void>(&LocalFuncs::Func2);
307}
308
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000309class AsyncInvokeTest : public testing::Test {
310 public:
311 void IntCallback(int value) {
312 EXPECT_EQ(expected_thread_, Thread::Current());
313 int_value_ = value;
314 }
315 void AsyncInvokeIntCallback(AsyncInvoker* invoker, Thread* thread) {
316 expected_thread_ = thread;
317 invoker->AsyncInvoke(thread, FunctorC(),
318 &AsyncInvokeTest::IntCallback,
319 static_cast<AsyncInvokeTest*>(this));
320 invoke_started_.Set();
321 }
322 void SetExpectedThreadForIntCallback(Thread* thread) {
323 expected_thread_ = thread;
324 }
325
326 protected:
327 enum { kWaitTimeout = 1000 };
328 AsyncInvokeTest()
329 : int_value_(0),
330 invoke_started_(true, false),
331 expected_thread_(NULL) {}
332
333 int int_value_;
334 Event invoke_started_;
335 Thread* expected_thread_;
336};
337
henrike@webrtc.orgb8c254a2014-02-14 23:38:45 +0000338TEST_F(AsyncInvokeTest, FireAndForget) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000339 AsyncInvoker invoker;
340 // Create and start the thread.
341 Thread thread;
342 thread.Start();
343 // Try calling functor.
344 bool called = false;
345 invoker.AsyncInvoke<void>(&thread, FunctorB(&called));
346 EXPECT_TRUE_WAIT(called, kWaitTimeout);
347}
348
henrike@webrtc.orgb8c254a2014-02-14 23:38:45 +0000349TEST_F(AsyncInvokeTest, WithCallback) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000350 AsyncInvoker invoker;
351 // Create and start the thread.
352 Thread thread;
353 thread.Start();
354 // Try calling functor.
355 SetExpectedThreadForIntCallback(Thread::Current());
356 invoker.AsyncInvoke(&thread, FunctorA(),
357 &AsyncInvokeTest::IntCallback,
358 static_cast<AsyncInvokeTest*>(this));
359 EXPECT_EQ_WAIT(42, int_value_, kWaitTimeout);
360}
361
henrike@webrtc.orgb8c254a2014-02-14 23:38:45 +0000362TEST_F(AsyncInvokeTest, CancelInvoker) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000363 // Create and start the thread.
364 Thread thread;
365 thread.Start();
366 // Try destroying invoker during call.
367 {
368 AsyncInvoker invoker;
369 invoker.AsyncInvoke(&thread, FunctorC(),
370 &AsyncInvokeTest::IntCallback,
371 static_cast<AsyncInvokeTest*>(this));
372 }
373 // With invoker gone, callback should be cancelled.
374 Thread::Current()->ProcessMessages(kWaitTimeout);
375 EXPECT_EQ(0, int_value_);
376}
377
henrike@webrtc.orgb8c254a2014-02-14 23:38:45 +0000378TEST_F(AsyncInvokeTest, CancelCallingThread) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000379 AsyncInvoker invoker;
380 { // Create and start the thread.
381 Thread thread;
382 thread.Start();
383 // Try calling functor.
384 thread.Invoke<void>(Bind(&AsyncInvokeTest::AsyncInvokeIntCallback,
385 static_cast<AsyncInvokeTest*>(this),
386 &invoker, Thread::Current()));
387 // Wait for the call to begin.
388 ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
389 }
390 // Calling thread is gone. Return message shouldn't happen.
391 Thread::Current()->ProcessMessages(kWaitTimeout);
392 EXPECT_EQ(0, int_value_);
393}
394
henrike@webrtc.orgb8c254a2014-02-14 23:38:45 +0000395TEST_F(AsyncInvokeTest, KillInvokerBeforeExecute) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000396 Thread thread;
397 thread.Start();
398 {
399 AsyncInvoker invoker;
400 // Try calling functor.
401 thread.Invoke<void>(Bind(&AsyncInvokeTest::AsyncInvokeIntCallback,
402 static_cast<AsyncInvokeTest*>(this),
403 &invoker, Thread::Current()));
404 // Wait for the call to begin.
405 ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
406 }
407 // Invoker is destroyed. Function should not execute.
408 Thread::Current()->ProcessMessages(kWaitTimeout);
409 EXPECT_EQ(0, int_value_);
410}
411
henrike@webrtc.orgb8c254a2014-02-14 23:38:45 +0000412TEST_F(AsyncInvokeTest, Flush) {
sergeyu@chromium.org9cf037b2014-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.
417 invoker.AsyncInvoke<void>(Thread::Current(),
418 FunctorB(&flag1));
419 invoker.AsyncInvoke<void>(Thread::Current(),
420 FunctorB(&flag2));
421 // Because we haven't pumped messages, these should not have run yet.
422 EXPECT_FALSE(flag1);
423 EXPECT_FALSE(flag2);
424 // Force them to run now.
425 invoker.Flush(Thread::Current());
426 EXPECT_TRUE(flag1);
427 EXPECT_TRUE(flag2);
428}
429
henrike@webrtc.orgb8c254a2014-02-14 23:38:45 +0000430TEST_F(AsyncInvokeTest, FlushWithIds) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000431 AsyncInvoker invoker;
432 bool flag1 = false;
433 bool flag2 = false;
434 // Queue two async calls to the current thread, one with a message id.
435 invoker.AsyncInvoke<void>(Thread::Current(),
436 FunctorB(&flag1),
437 5);
438 invoker.AsyncInvoke<void>(Thread::Current(),
439 FunctorB(&flag2));
440 // Because we haven't pumped messages, these should not have run yet.
441 EXPECT_FALSE(flag1);
442 EXPECT_FALSE(flag2);
443 // Execute pending calls with id == 5.
444 invoker.Flush(Thread::Current(), 5);
445 EXPECT_TRUE(flag1);
446 EXPECT_FALSE(flag2);
447 flag1 = false;
448 // Execute all pending calls. The id == 5 call should not execute again.
449 invoker.Flush(Thread::Current());
450 EXPECT_FALSE(flag1);
451 EXPECT_TRUE(flag2);
452}
453
454
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000455#ifdef WIN32
456class ComThreadTest : public testing::Test, public MessageHandler {
457 public:
458 ComThreadTest() : done_(false) {}
459 protected:
460 virtual void OnMessage(Message* message) {
461 HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
462 // S_FALSE means the thread was already inited for a multithread apartment.
463 EXPECT_EQ(S_FALSE, hr);
464 if (SUCCEEDED(hr)) {
465 CoUninitialize();
466 }
467 done_ = true;
468 }
469 bool done_;
470};
471
472TEST_F(ComThreadTest, ComInited) {
473 Thread* thread = new ComThread();
474 EXPECT_TRUE(thread->Start());
475 thread->Post(this, 0);
476 EXPECT_TRUE_WAIT(done_, 1000);
477 delete thread;
478}
479#endif