blob: 148e27b1552f0655ec1bff013dee97399cb47c7f [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,
84 const SocketAddress& remote_addr) {
85 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() {}
125 virtual ~CustomThread() {}
126 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() {
139 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.
151struct Functor1 {
152 int operator()() { return 42; }
153};
154class Functor2 {
155 public:
156 explicit Functor2(bool* flag) : flag_(flag) {}
157 void operator()() { if (flag_) *flag_ = true; }
158 private:
159 bool* flag_;
160};
161
andrew@webrtc.org2f240b42013-09-25 02:33:50 +0000162// See: https://code.google.com/p/webrtc/issues/detail?id=2409
163TEST(ThreadTest, DISABLED_Main) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000164 const SocketAddress addr("127.0.0.1", 0);
165
166 // Create the messaging client on its own thread.
167 Thread th1;
168 Socket* socket = th1.socketserver()->CreateAsyncSocket(addr.family(),
169 SOCK_DGRAM);
170 MessageClient msg_client(&th1, socket);
171
172 // Create the socket client on its own thread.
173 Thread th2;
174 AsyncSocket* asocket =
175 th2.socketserver()->CreateAsyncSocket(addr.family(), SOCK_DGRAM);
176 SocketClient sock_client(asocket, addr, &th1, &msg_client);
177
178 socket->Connect(sock_client.address());
179
180 th1.Start();
181 th2.Start();
182
183 // Get the messages started.
184 th1.PostDelayed(100, &msg_client, 0, new TestMessage(1));
185
186 // Give the clients a little while to run.
187 // Messages will be processed at 100, 300, 500, 700, 900.
188 Thread* th_main = Thread::Current();
189 th_main->ProcessMessages(1000);
190
191 // Stop the sending client. Give the receiver a bit longer to run, in case
192 // it is running on a machine that is under load (e.g. the build machine).
193 th1.Stop();
194 th_main->ProcessMessages(200);
195 th2.Stop();
196
197 // Make sure the results were correct
198 EXPECT_EQ(5, msg_client.count);
199 EXPECT_EQ(34, msg_client.last);
200 EXPECT_EQ(5, sock_client.count);
201 EXPECT_EQ(55, sock_client.last);
202}
203
204// Test that setting thread names doesn't cause a malfunction.
205// There's no easy way to verify the name was set properly at this time.
206TEST(ThreadTest, Names) {
207 // Default name
208 Thread *thread;
209 thread = new Thread();
210 EXPECT_TRUE(thread->Start());
211 thread->Stop();
212 delete thread;
213 thread = new Thread();
214 // Name with no object parameter
215 EXPECT_TRUE(thread->SetName("No object", NULL));
216 EXPECT_TRUE(thread->Start());
217 thread->Stop();
218 delete thread;
219 // Really long name
220 thread = new Thread();
221 EXPECT_TRUE(thread->SetName("Abcdefghijklmnopqrstuvwxyz1234567890", this));
222 EXPECT_TRUE(thread->Start());
223 thread->Stop();
224 delete thread;
225}
226
227// Test that setting thread priorities doesn't cause a malfunction.
228// There's no easy way to verify the priority was set properly at this time.
229TEST(ThreadTest, Priorities) {
230 Thread *thread;
231 thread = new Thread();
232 EXPECT_TRUE(thread->SetPriority(PRIORITY_HIGH));
233 EXPECT_TRUE(thread->Start());
234 thread->Stop();
235 delete thread;
236 thread = new Thread();
237 EXPECT_TRUE(thread->SetPriority(PRIORITY_ABOVE_NORMAL));
238 EXPECT_TRUE(thread->Start());
239 thread->Stop();
240 delete thread;
241
242 thread = new Thread();
243 EXPECT_TRUE(thread->Start());
244#ifdef WIN32
245 EXPECT_TRUE(thread->SetPriority(PRIORITY_ABOVE_NORMAL));
246#else
247 EXPECT_FALSE(thread->SetPriority(PRIORITY_ABOVE_NORMAL));
248#endif
249 thread->Stop();
250 delete thread;
251
252}
253
254TEST(ThreadTest, Wrap) {
255 Thread* current_thread = Thread::Current();
256 current_thread->UnwrapCurrent();
257 CustomThread* cthread = new CustomThread();
258 EXPECT_TRUE(cthread->WrapCurrent());
259 EXPECT_TRUE(cthread->started());
260 EXPECT_FALSE(cthread->IsOwned());
261 cthread->UnwrapCurrent();
262 EXPECT_FALSE(cthread->started());
263 delete cthread;
264 current_thread->WrapCurrent();
265}
266
267// Test that calling Release on a thread causes it to self-destruct when
268// it's finished running
269TEST(ThreadTest, Release) {
270 scoped_ptr<Event> event(new Event(true, false));
271 // Ensure the event is initialized.
272 event->Reset();
273
274 Thread* thread = new SignalWhenDestroyedThread(event.get());
275 thread->Start();
276 thread->Release();
277
278 // The event should get signaled when the thread completes, which should
279 // be nearly instantaneous, since it doesn't do anything. For safety,
280 // give it 3 seconds in case the machine is under load.
281 bool signaled = event->Wait(3000);
282 EXPECT_TRUE(signaled);
283}
284
285TEST(ThreadTest, Invoke) {
286 // Create and start the thread.
287 Thread thread;
288 thread.Start();
289 // Try calling functors.
290 EXPECT_EQ(42, thread.Invoke<int>(Functor1()));
291 bool called = false;
292 Functor2 f2(&called);
293 thread.Invoke<void>(f2);
294 EXPECT_TRUE(called);
295 // Try calling bare functions.
296 struct LocalFuncs {
297 static int Func1() { return 999; }
298 static void Func2() {}
299 };
300 EXPECT_EQ(999, thread.Invoke<int>(&LocalFuncs::Func1));
301 thread.Invoke<void>(&LocalFuncs::Func2);
302}
303
304#ifdef WIN32
305class ComThreadTest : public testing::Test, public MessageHandler {
306 public:
307 ComThreadTest() : done_(false) {}
308 protected:
309 virtual void OnMessage(Message* message) {
310 HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
311 // S_FALSE means the thread was already inited for a multithread apartment.
312 EXPECT_EQ(S_FALSE, hr);
313 if (SUCCEEDED(hr)) {
314 CoUninitialize();
315 }
316 done_ = true;
317 }
318 bool done_;
319};
320
321TEST_F(ComThreadTest, ComInited) {
322 Thread* thread = new ComThread();
323 EXPECT_TRUE(thread->Start());
324 thread->Post(this, 0);
325 EXPECT_TRUE_WAIT(done_, 1000);
326 delete thread;
327}
328#endif