blob: d6af17ac1798f23d6bfff8e49b2ece29defb0fb7 [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
28#include "talk/base/asyncudpsocket.h"
29#include "talk/base/event.h"
30#include "talk/base/gunit.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000031#include "talk/base/physicalsocketserver.h"
32#include "talk/base/socketaddress.h"
33#include "talk/base/thread.h"
34
35#ifdef WIN32
36#include <comdef.h> // NOLINT
37#endif
38
39using namespace talk_base;
40
41const int MAX = 65536;
42
43// Generates a sequence of numbers (collaboratively).
44class TestGenerator {
45 public:
46 TestGenerator() : last(0), count(0) {}
47
48 int Next(int prev) {
49 int result = prev + last;
50 last = result;
51 count += 1;
52 return result;
53 }
54
55 int last;
56 int count;
57};
58
59struct TestMessage : public MessageData {
60 explicit TestMessage(int v) : value(v) {}
61 virtual ~TestMessage() {}
62
63 int value;
64};
65
66// Receives on a socket and sends by posting messages.
67class SocketClient : public TestGenerator, public sigslot::has_slots<> {
68 public:
69 SocketClient(AsyncSocket* socket, const SocketAddress& addr,
70 Thread* post_thread, MessageHandler* phandler)
71 : socket_(AsyncUDPSocket::Create(socket, addr)),
72 post_thread_(post_thread),
73 post_handler_(phandler) {
74 socket_->SignalReadPacket.connect(this, &SocketClient::OnPacket);
75 }
76
77 ~SocketClient() {
78 delete socket_;
79 }
80
81 SocketAddress address() const { return socket_->GetLocalAddress(); }
82
83 void OnPacket(AsyncPacketSocket* socket, const char* buf, size_t size,
wu@webrtc.org20182692013-12-12 22:54:25 +000084 const SocketAddress& remote_addr) {
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
89 //socket_->set_readable(last < MAX);
90 post_thread_->PostDelayed(200, post_handler_, 0, new TestMessage(result));
91 }
92
93 private:
94 AsyncUDPSocket* socket_;
95 Thread* post_thread_;
96 MessageHandler* post_handler_;
97};
98
99// Receives messages and sends on a socket.
100class MessageClient : public MessageHandler, public TestGenerator {
101 public:
102 MessageClient(Thread* pth, Socket* socket)
103 : thread_(pth), socket_(socket) {
104 }
105
106 virtual ~MessageClient() {
107 delete socket_;
108 }
109
110 virtual void OnMessage(Message *pmsg) {
111 TestMessage* msg = static_cast<TestMessage*>(pmsg->pdata);
112 int result = Next(msg->value);
113 EXPECT_GE(socket_->Send(&result, sizeof(result)), 0);
114 delete msg;
115 }
116
117 private:
118 Thread* thread_;
119 Socket* socket_;
120};
121
122class CustomThread : public talk_base::Thread {
123 public:
124 CustomThread() {}
wu@webrtc.org3c5d2b42013-10-18 16:27:26 +0000125 virtual ~CustomThread() { Stop(); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000126 bool Start() { return false; }
127};
128
129
130// A thread that does nothing when it runs and signals an event
131// when it is destroyed.
132class SignalWhenDestroyedThread : public Thread {
133 public:
134 SignalWhenDestroyedThread(Event* event)
135 : event_(event) {
136 }
137
138 virtual ~SignalWhenDestroyedThread() {
wu@webrtc.org3c5d2b42013-10-18 16:27:26 +0000139 Stop();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000140 event_->Set();
141 }
142
143 virtual void Run() {
144 // Do nothing.
145 }
146
147 private:
148 Event* event_;
149};
150
151// Function objects to test Thread::Invoke.
152struct Functor1 {
153 int operator()() { return 42; }
154};
155class Functor2 {
156 public:
157 explicit Functor2(bool* flag) : flag_(flag) {}
158 void operator()() { if (flag_) *flag_ = true; }
159 private:
160 bool* flag_;
161};
162
andrew@webrtc.org2f240b42013-09-25 02:33:50 +0000163// See: https://code.google.com/p/webrtc/issues/detail?id=2409
164TEST(ThreadTest, DISABLED_Main) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000165 const SocketAddress addr("127.0.0.1", 0);
166
167 // Create the messaging client on its own thread.
168 Thread th1;
169 Socket* socket = th1.socketserver()->CreateAsyncSocket(addr.family(),
170 SOCK_DGRAM);
171 MessageClient msg_client(&th1, socket);
172
173 // Create the socket client on its own thread.
174 Thread th2;
175 AsyncSocket* asocket =
176 th2.socketserver()->CreateAsyncSocket(addr.family(), SOCK_DGRAM);
177 SocketClient sock_client(asocket, addr, &th1, &msg_client);
178
179 socket->Connect(sock_client.address());
180
181 th1.Start();
182 th2.Start();
183
184 // Get the messages started.
185 th1.PostDelayed(100, &msg_client, 0, new TestMessage(1));
186
187 // Give the clients a little while to run.
188 // Messages will be processed at 100, 300, 500, 700, 900.
189 Thread* th_main = Thread::Current();
190 th_main->ProcessMessages(1000);
191
192 // Stop the sending client. Give the receiver a bit longer to run, in case
193 // it is running on a machine that is under load (e.g. the build machine).
194 th1.Stop();
195 th_main->ProcessMessages(200);
196 th2.Stop();
197
198 // Make sure the results were correct
199 EXPECT_EQ(5, msg_client.count);
200 EXPECT_EQ(34, msg_client.last);
201 EXPECT_EQ(5, sock_client.count);
202 EXPECT_EQ(55, sock_client.last);
203}
204
205// Test that setting thread names doesn't cause a malfunction.
206// There's no easy way to verify the name was set properly at this time.
207TEST(ThreadTest, Names) {
208 // Default name
209 Thread *thread;
210 thread = new Thread();
211 EXPECT_TRUE(thread->Start());
212 thread->Stop();
213 delete thread;
214 thread = new Thread();
215 // Name with no object parameter
216 EXPECT_TRUE(thread->SetName("No object", NULL));
217 EXPECT_TRUE(thread->Start());
218 thread->Stop();
219 delete thread;
220 // Really long name
221 thread = new Thread();
222 EXPECT_TRUE(thread->SetName("Abcdefghijklmnopqrstuvwxyz1234567890", this));
223 EXPECT_TRUE(thread->Start());
224 thread->Stop();
225 delete thread;
226}
227
228// Test that setting thread priorities doesn't cause a malfunction.
229// There's no easy way to verify the priority was set properly at this time.
230TEST(ThreadTest, Priorities) {
231 Thread *thread;
232 thread = new Thread();
233 EXPECT_TRUE(thread->SetPriority(PRIORITY_HIGH));
234 EXPECT_TRUE(thread->Start());
235 thread->Stop();
236 delete thread;
237 thread = new Thread();
238 EXPECT_TRUE(thread->SetPriority(PRIORITY_ABOVE_NORMAL));
239 EXPECT_TRUE(thread->Start());
240 thread->Stop();
241 delete thread;
242
243 thread = new Thread();
244 EXPECT_TRUE(thread->Start());
245#ifdef WIN32
246 EXPECT_TRUE(thread->SetPriority(PRIORITY_ABOVE_NORMAL));
247#else
248 EXPECT_FALSE(thread->SetPriority(PRIORITY_ABOVE_NORMAL));
249#endif
250 thread->Stop();
251 delete thread;
252
253}
254
255TEST(ThreadTest, Wrap) {
256 Thread* current_thread = Thread::Current();
257 current_thread->UnwrapCurrent();
258 CustomThread* cthread = new CustomThread();
259 EXPECT_TRUE(cthread->WrapCurrent());
260 EXPECT_TRUE(cthread->started());
261 EXPECT_FALSE(cthread->IsOwned());
262 cthread->UnwrapCurrent();
263 EXPECT_FALSE(cthread->started());
264 delete cthread;
265 current_thread->WrapCurrent();
266}
267
268// Test that calling Release on a thread causes it to self-destruct when
269// it's finished running
270TEST(ThreadTest, Release) {
271 scoped_ptr<Event> event(new Event(true, false));
272 // Ensure the event is initialized.
273 event->Reset();
274
275 Thread* thread = new SignalWhenDestroyedThread(event.get());
276 thread->Start();
277 thread->Release();
278
279 // The event should get signaled when the thread completes, which should
280 // be nearly instantaneous, since it doesn't do anything. For safety,
281 // give it 3 seconds in case the machine is under load.
282 bool signaled = event->Wait(3000);
283 EXPECT_TRUE(signaled);
284}
285
286TEST(ThreadTest, Invoke) {
287 // Create and start the thread.
288 Thread thread;
289 thread.Start();
290 // Try calling functors.
291 EXPECT_EQ(42, thread.Invoke<int>(Functor1()));
292 bool called = false;
293 Functor2 f2(&called);
294 thread.Invoke<void>(f2);
295 EXPECT_TRUE(called);
296 // Try calling bare functions.
297 struct LocalFuncs {
298 static int Func1() { return 999; }
299 static void Func2() {}
300 };
301 EXPECT_EQ(999, thread.Invoke<int>(&LocalFuncs::Func1));
302 thread.Invoke<void>(&LocalFuncs::Func2);
303}
304
305#ifdef WIN32
306class ComThreadTest : public testing::Test, public MessageHandler {
307 public:
308 ComThreadTest() : done_(false) {}
309 protected:
310 virtual void OnMessage(Message* message) {
311 HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
312 // S_FALSE means the thread was already inited for a multithread apartment.
313 EXPECT_EQ(S_FALSE, hr);
314 if (SUCCEEDED(hr)) {
315 CoUninitialize();
316 }
317 done_ = true;
318 }
319 bool done_;
320};
321
322TEST_F(ComThreadTest, ComInited) {
323 Thread* thread = new ComThread();
324 EXPECT_TRUE(thread->Start());
325 thread->Post(this, 0);
326 EXPECT_TRUE_WAIT(done_, 1000);
327 delete thread;
328}
329#endif