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