blob: cd35f1741a82af36b34acc729d6d13b3dc18e6b6 [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)
102 : thread_(pth), socket_(socket) {
103 }
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:
117 Thread* thread_;
118 Socket* socket_;
119};
120
121class CustomThread : public talk_base::Thread {
122 public:
123 CustomThread() {}
wu@webrtc.org3c5d2b42013-10-18 16:27:26 +0000124 virtual ~CustomThread() { Stop(); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000125 bool Start() { return false; }
126};
127
128
129// A thread that does nothing when it runs and signals an event
130// when it is destroyed.
131class SignalWhenDestroyedThread : public Thread {
132 public:
133 SignalWhenDestroyedThread(Event* event)
134 : event_(event) {
135 }
136
137 virtual ~SignalWhenDestroyedThread() {
wu@webrtc.org3c5d2b42013-10-18 16:27:26 +0000138 Stop();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000139 event_->Set();
140 }
141
142 virtual void Run() {
143 // Do nothing.
144 }
145
146 private:
147 Event* event_;
148};
149
150// Function objects to test Thread::Invoke.
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000151struct FunctorA {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000152 int operator()() { return 42; }
153};
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000154class FunctorB {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000155 public:
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000156 explicit FunctorB(bool* flag) : flag_(flag) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000157 void operator()() { if (flag_) *flag_ = true; }
158 private:
159 bool* flag_;
160};
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000161struct FunctorC {
162 int operator()() {
163 Thread::Current()->ProcessMessages(50);
164 return 24;
165 }
166};
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000167
andrew@webrtc.org2f240b42013-09-25 02:33:50 +0000168// See: https://code.google.com/p/webrtc/issues/detail?id=2409
169TEST(ThreadTest, DISABLED_Main) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000170 const SocketAddress addr("127.0.0.1", 0);
171
172 // Create the messaging client on its own thread.
173 Thread th1;
174 Socket* socket = th1.socketserver()->CreateAsyncSocket(addr.family(),
175 SOCK_DGRAM);
176 MessageClient msg_client(&th1, socket);
177
178 // Create the socket client on its own thread.
179 Thread th2;
180 AsyncSocket* asocket =
181 th2.socketserver()->CreateAsyncSocket(addr.family(), SOCK_DGRAM);
182 SocketClient sock_client(asocket, addr, &th1, &msg_client);
183
184 socket->Connect(sock_client.address());
185
186 th1.Start();
187 th2.Start();
188
189 // Get the messages started.
190 th1.PostDelayed(100, &msg_client, 0, new TestMessage(1));
191
192 // Give the clients a little while to run.
193 // Messages will be processed at 100, 300, 500, 700, 900.
194 Thread* th_main = Thread::Current();
195 th_main->ProcessMessages(1000);
196
197 // Stop the sending client. Give the receiver a bit longer to run, in case
198 // it is running on a machine that is under load (e.g. the build machine).
199 th1.Stop();
200 th_main->ProcessMessages(200);
201 th2.Stop();
202
203 // Make sure the results were correct
204 EXPECT_EQ(5, msg_client.count);
205 EXPECT_EQ(34, msg_client.last);
206 EXPECT_EQ(5, sock_client.count);
207 EXPECT_EQ(55, sock_client.last);
208}
209
210// Test that setting thread names doesn't cause a malfunction.
211// There's no easy way to verify the name was set properly at this time.
212TEST(ThreadTest, Names) {
213 // Default name
214 Thread *thread;
215 thread = new Thread();
216 EXPECT_TRUE(thread->Start());
217 thread->Stop();
218 delete thread;
219 thread = new Thread();
220 // Name with no object parameter
221 EXPECT_TRUE(thread->SetName("No object", NULL));
222 EXPECT_TRUE(thread->Start());
223 thread->Stop();
224 delete thread;
225 // Really long name
226 thread = new Thread();
227 EXPECT_TRUE(thread->SetName("Abcdefghijklmnopqrstuvwxyz1234567890", this));
228 EXPECT_TRUE(thread->Start());
229 thread->Stop();
230 delete thread;
231}
232
233// Test that setting thread priorities doesn't cause a malfunction.
234// There's no easy way to verify the priority was set properly at this time.
235TEST(ThreadTest, Priorities) {
236 Thread *thread;
237 thread = new Thread();
238 EXPECT_TRUE(thread->SetPriority(PRIORITY_HIGH));
239 EXPECT_TRUE(thread->Start());
240 thread->Stop();
241 delete thread;
242 thread = new Thread();
243 EXPECT_TRUE(thread->SetPriority(PRIORITY_ABOVE_NORMAL));
244 EXPECT_TRUE(thread->Start());
245 thread->Stop();
246 delete thread;
247
248 thread = new Thread();
249 EXPECT_TRUE(thread->Start());
250#ifdef WIN32
251 EXPECT_TRUE(thread->SetPriority(PRIORITY_ABOVE_NORMAL));
252#else
253 EXPECT_FALSE(thread->SetPriority(PRIORITY_ABOVE_NORMAL));
254#endif
255 thread->Stop();
256 delete thread;
257
258}
259
260TEST(ThreadTest, Wrap) {
261 Thread* current_thread = Thread::Current();
262 current_thread->UnwrapCurrent();
263 CustomThread* cthread = new CustomThread();
264 EXPECT_TRUE(cthread->WrapCurrent());
265 EXPECT_TRUE(cthread->started());
266 EXPECT_FALSE(cthread->IsOwned());
267 cthread->UnwrapCurrent();
268 EXPECT_FALSE(cthread->started());
269 delete cthread;
270 current_thread->WrapCurrent();
271}
272
273// Test that calling Release on a thread causes it to self-destruct when
274// it's finished running
275TEST(ThreadTest, Release) {
276 scoped_ptr<Event> event(new Event(true, false));
277 // Ensure the event is initialized.
278 event->Reset();
279
280 Thread* thread = new SignalWhenDestroyedThread(event.get());
281 thread->Start();
282 thread->Release();
283
284 // The event should get signaled when the thread completes, which should
285 // be nearly instantaneous, since it doesn't do anything. For safety,
286 // give it 3 seconds in case the machine is under load.
287 bool signaled = event->Wait(3000);
288 EXPECT_TRUE(signaled);
289}
290
291TEST(ThreadTest, Invoke) {
292 // Create and start the thread.
293 Thread thread;
294 thread.Start();
295 // Try calling functors.
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000296 EXPECT_EQ(42, thread.Invoke<int>(FunctorA()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000297 bool called = false;
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000298 FunctorB f2(&called);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000299 thread.Invoke<void>(f2);
300 EXPECT_TRUE(called);
301 // Try calling bare functions.
302 struct LocalFuncs {
303 static int Func1() { return 999; }
304 static void Func2() {}
305 };
306 EXPECT_EQ(999, thread.Invoke<int>(&LocalFuncs::Func1));
307 thread.Invoke<void>(&LocalFuncs::Func2);
308}
309
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000310class AsyncInvokeTest : public testing::Test {
311 public:
312 void IntCallback(int value) {
313 EXPECT_EQ(expected_thread_, Thread::Current());
314 int_value_ = value;
315 }
316 void AsyncInvokeIntCallback(AsyncInvoker* invoker, Thread* thread) {
317 expected_thread_ = thread;
318 invoker->AsyncInvoke(thread, FunctorC(),
319 &AsyncInvokeTest::IntCallback,
320 static_cast<AsyncInvokeTest*>(this));
321 invoke_started_.Set();
322 }
323 void SetExpectedThreadForIntCallback(Thread* thread) {
324 expected_thread_ = thread;
325 }
326
327 protected:
328 enum { kWaitTimeout = 1000 };
329 AsyncInvokeTest()
330 : int_value_(0),
331 invoke_started_(true, false),
332 expected_thread_(NULL) {}
333
334 int int_value_;
335 Event invoke_started_;
336 Thread* expected_thread_;
337};
338
henrike@webrtc.orgb8c254a2014-02-14 23:38:45 +0000339TEST_F(AsyncInvokeTest, FireAndForget) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000340 AsyncInvoker invoker;
341 // Create and start the thread.
342 Thread thread;
343 thread.Start();
344 // Try calling functor.
345 bool called = false;
346 invoker.AsyncInvoke<void>(&thread, FunctorB(&called));
347 EXPECT_TRUE_WAIT(called, kWaitTimeout);
348}
349
henrike@webrtc.orgb8c254a2014-02-14 23:38:45 +0000350TEST_F(AsyncInvokeTest, WithCallback) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000351 AsyncInvoker invoker;
352 // Create and start the thread.
353 Thread thread;
354 thread.Start();
355 // Try calling functor.
356 SetExpectedThreadForIntCallback(Thread::Current());
357 invoker.AsyncInvoke(&thread, FunctorA(),
358 &AsyncInvokeTest::IntCallback,
359 static_cast<AsyncInvokeTest*>(this));
360 EXPECT_EQ_WAIT(42, int_value_, kWaitTimeout);
361}
362
henrike@webrtc.orgb8c254a2014-02-14 23:38:45 +0000363TEST_F(AsyncInvokeTest, CancelInvoker) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000364 // Create and start the thread.
365 Thread thread;
366 thread.Start();
367 // Try destroying invoker during call.
368 {
369 AsyncInvoker invoker;
370 invoker.AsyncInvoke(&thread, FunctorC(),
371 &AsyncInvokeTest::IntCallback,
372 static_cast<AsyncInvokeTest*>(this));
373 }
374 // With invoker gone, callback should be cancelled.
375 Thread::Current()->ProcessMessages(kWaitTimeout);
376 EXPECT_EQ(0, int_value_);
377}
378
henrike@webrtc.orgb8c254a2014-02-14 23:38:45 +0000379TEST_F(AsyncInvokeTest, CancelCallingThread) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000380 AsyncInvoker invoker;
381 { // Create and start the thread.
382 Thread thread;
383 thread.Start();
384 // Try calling functor.
385 thread.Invoke<void>(Bind(&AsyncInvokeTest::AsyncInvokeIntCallback,
386 static_cast<AsyncInvokeTest*>(this),
387 &invoker, Thread::Current()));
388 // Wait for the call to begin.
389 ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
390 }
391 // Calling thread is gone. Return message shouldn't happen.
392 Thread::Current()->ProcessMessages(kWaitTimeout);
393 EXPECT_EQ(0, int_value_);
394}
395
henrike@webrtc.orgb8c254a2014-02-14 23:38:45 +0000396TEST_F(AsyncInvokeTest, KillInvokerBeforeExecute) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000397 Thread thread;
398 thread.Start();
399 {
400 AsyncInvoker invoker;
401 // Try calling functor.
402 thread.Invoke<void>(Bind(&AsyncInvokeTest::AsyncInvokeIntCallback,
403 static_cast<AsyncInvokeTest*>(this),
404 &invoker, Thread::Current()));
405 // Wait for the call to begin.
406 ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
407 }
408 // Invoker is destroyed. Function should not execute.
409 Thread::Current()->ProcessMessages(kWaitTimeout);
410 EXPECT_EQ(0, int_value_);
411}
412
henrike@webrtc.orgb8c254a2014-02-14 23:38:45 +0000413TEST_F(AsyncInvokeTest, Flush) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000414 AsyncInvoker invoker;
415 bool flag1 = false;
416 bool flag2 = false;
417 // Queue two async calls to the current thread.
418 invoker.AsyncInvoke<void>(Thread::Current(),
419 FunctorB(&flag1));
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 // Force them to run now.
426 invoker.Flush(Thread::Current());
427 EXPECT_TRUE(flag1);
428 EXPECT_TRUE(flag2);
429}
430
henrike@webrtc.orgb8c254a2014-02-14 23:38:45 +0000431TEST_F(AsyncInvokeTest, FlushWithIds) {
sergeyu@chromium.org9cf037b2014-02-07 19:03:26 +0000432 AsyncInvoker invoker;
433 bool flag1 = false;
434 bool flag2 = false;
435 // Queue two async calls to the current thread, one with a message id.
436 invoker.AsyncInvoke<void>(Thread::Current(),
437 FunctorB(&flag1),
438 5);
439 invoker.AsyncInvoke<void>(Thread::Current(),
440 FunctorB(&flag2));
441 // Because we haven't pumped messages, these should not have run yet.
442 EXPECT_FALSE(flag1);
443 EXPECT_FALSE(flag2);
444 // Execute pending calls with id == 5.
445 invoker.Flush(Thread::Current(), 5);
446 EXPECT_TRUE(flag1);
447 EXPECT_FALSE(flag2);
448 flag1 = false;
449 // Execute all pending calls. The id == 5 call should not execute again.
450 invoker.Flush(Thread::Current());
451 EXPECT_FALSE(flag1);
452 EXPECT_TRUE(flag2);
453}
454
455
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000456#ifdef WIN32
457class ComThreadTest : public testing::Test, public MessageHandler {
458 public:
459 ComThreadTest() : done_(false) {}
460 protected:
461 virtual void OnMessage(Message* message) {
462 HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
463 // S_FALSE means the thread was already inited for a multithread apartment.
464 EXPECT_EQ(S_FALSE, hr);
465 if (SUCCEEDED(hr)) {
466 CoUninitialize();
467 }
468 done_ = true;
469 }
470 bool done_;
471};
472
473TEST_F(ComThreadTest, ComInited) {
474 Thread* thread = new ComThread();
475 EXPECT_TRUE(thread->Start());
476 thread->Post(this, 0);
477 EXPECT_TRUE_WAIT(done_, 1000);
478 delete thread;
479}
480#endif