blob: 74f046ac9c1b8b629568d1676e422f956dc112d8 [file] [log] [blame]
initial.commit09911bf2008-07-26 23:55:291// Copyright 2008, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29//
30// Unit test for SyncChannel.
31
32#include <windows.h>
33#include <string>
34#include <vector>
35
36#include "base/basictypes.h"
37#include "base/logging.h"
38#include "base/message_loop.h"
39#include "base/string_util.h"
40#include "base/thread.h"
41#include "chrome/common/child_process.h"
42#include "chrome/common/ipc_message.h"
43#include "chrome/common/ipc_sync_channel.h"
44#include "chrome/common/stl_util-inl.h"
45#include "testing/gtest/include/gtest/gtest.h"
46
47#define IPC_MESSAGE_MACROS_ENUMS
48#include "chrome/common/ipc_sync_channel_unittest.h"
49
50// define the classes
51#define IPC_MESSAGE_MACROS_CLASSES
52#include "chrome/common/ipc_sync_channel_unittest.h"
53
54using namespace IPC;
55
56// SyncChannel should only be used in child processes as we don't want to hang
57// the browser. So in the unit test we need to have a ChildProcess object.
58class TestProcess : public ChildProcess {
59 public:
60 explicit TestProcess(const std::wstring& channel_name) {}
61 static void GlobalInit() {
62 ChildProcessFactory<TestProcess> factory;
63 ChildProcess::GlobalInit(L"blah", &factory);
64 }
65};
66
67// Wrapper around an event handle.
68class Event {
69 public:
70 Event() : handle_(CreateEvent(NULL, FALSE, FALSE, NULL)) { }
71 ~Event() { CloseHandle(handle_); }
72 void Set() { SetEvent(handle_); }
73 void Wait() { WaitForSingleObject(handle_, INFINITE); }
74 HANDLE handle() { return handle_; }
75
76 private:
77 HANDLE handle_;
78
79 DISALLOW_EVIL_CONSTRUCTORS(Event);
80};
81
82// Base class for a "process" with listener and IPC threads.
83class Worker : public Channel::Listener, public Message::Sender {
84 public:
85 // Will create a channel without a name.
86 Worker(Channel::Mode mode, const std::string& thread_name)
87 : channel_name_(),
88 mode_(mode),
89 ipc_thread_((thread_name + "_ipc").c_str()),
90 listener_thread_((thread_name + "_listener").c_str()),
91 overrided_thread_(NULL) { }
92
93 // Will create a named channel and use this name for the threads' name.
94 Worker(const std::wstring& channel_name, Channel::Mode mode)
95 : channel_name_(channel_name),
96 mode_(mode),
97 ipc_thread_((WideToUTF8(channel_name) + "_ipc").c_str()),
98 listener_thread_((WideToUTF8(channel_name) + "_listener").c_str()),
99 overrided_thread_(NULL) { }
100
101 // The IPC thread needs to outlive SyncChannel, so force the correct order of
102 // destruction.
103 virtual ~Worker() {
104 CloseChannel();
105 // We must stop the threads and release the channel here. The IPC thread
106 // must die before the listener thread, otherwise if its in the process of
107 // sending a message, it will get an error, it will use channel_, which
108 // references listener_. There are many ways of crashing, depending on
109 // timing.
110 // This is a race condition so you may not see it all the time even if you
111 // reverse the Stop() calls. You may see this bug with AppVerifier only.
112 ipc_thread_.Stop();
113 listener_thread_.Stop();
114 channel_.reset();
115 }
116 void AddRef() { }
117 void Release() { }
118 bool Send(Message* msg) { return channel_->Send(msg); }
119 void WaitForChannelCreation() { channel_created_.Wait(); }
120 void CloseChannel() { channel_.reset(); }
121 void Start() {
122 listener_thread_.Start();
123 Thread* thread = overrided_thread_ ? overrided_thread_ : &listener_thread_;
124 thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
125 this, &Worker::OnStart));
126 }
127 void OverrideThread(Thread* overrided_thread) {
128 DCHECK(overrided_thread_ == NULL);
129 overrided_thread_ = overrided_thread;
130 }
131 Channel::Mode mode() { return mode_; }
132 HANDLE done_event() { return done_.handle(); }
133
134 protected:
135 // Derived classes need to call this when they've completed their part of
136 // the test.
137 void Done() { done_.Set(); }
138
139 // Functions for dervied classes to implement if they wish.
140 virtual void Run() { }
141 virtual void OnDouble(int in, int* out) { NOTREACHED(); }
142 virtual void OnAnswer(int* answer) { NOTREACHED(); }
143 virtual void OnAnswerDelay(Message* reply_msg) {
144 // The message handler map below can only take one entry for
145 // SyncChannelTestMsg_AnswerToLife, so since some classes want
146 // the normal version while other want the delayed reply, we
147 // call the normal version if the derived class didn't override
148 // this function.
149 int answer;
150 OnAnswer(&answer);
151 SyncChannelTestMsg_AnswerToLife::WriteReplyParams(reply_msg, answer);
152 Send(reply_msg);
153 }
154
155 private:
156 // Called on the listener thread to create the sync channel.
157 void OnStart() {
158 ipc_thread_.Start();
159 // Link ipc_thread_, listener_thread_ and channel_ altogether.
160 channel_.reset(new SyncChannel(
161 channel_name_, mode_, this, ipc_thread_.message_loop(), true));
162 channel_created_.Set();
163 Run();
164 }
165
166 void OnMessageReceived(const Message& message) {
167 IPC_BEGIN_MESSAGE_MAP(Worker, message)
168 IPC_MESSAGE_HANDLER(SyncChannelTestMsg_Double, OnDouble)
169 IPC_MESSAGE_HANDLER_DELAY_REPLY(SyncChannelTestMsg_AnswerToLife,
170 OnAnswerDelay)
171 IPC_END_MESSAGE_MAP()
172 }
173
174 Event done_;
175 Event channel_created_;
176 std::wstring channel_name_;
177 Channel::Mode mode_;
178 scoped_ptr<SyncChannel> channel_;
179 Thread ipc_thread_;
180 Thread listener_thread_;
181 Thread* overrided_thread_;
182
183 DISALLOW_EVIL_CONSTRUCTORS(Worker);
184};
185
186
187// Starts the test with the given workers. This function deletes the workers
188// when it's done.
189void RunTest(std::vector<Worker*> workers) {
190 TestProcess::GlobalInit();
191
192 // First we create the workers that are channel servers, or else the other
193 // workers' channel initialization might fail because the pipe isn't created..
194 for (size_t i = 0; i < workers.size(); ++i) {
195 if (workers[i]->mode() == Channel::MODE_SERVER) {
196 workers[i]->Start();
197 workers[i]->WaitForChannelCreation();
198 }
199 }
200
201 // now create the clients
202 for (size_t i = 0; i < workers.size(); ++i) {
203 if (workers[i]->mode() == Channel::MODE_CLIENT)
204 workers[i]->Start();
205 }
206
207 // wait for all the workers to finish
208 std::vector<HANDLE> done_handles;
209 for (size_t i = 0; i < workers.size(); ++i)
210 done_handles.push_back(workers[i]->done_event());
211
212 int count = static_cast<int>(done_handles.size());
213 WaitForMultipleObjects(count, &done_handles.front(), TRUE, INFINITE);
214 STLDeleteContainerPointers(workers.begin(), workers.end());
215}
216
217
218//-----------------------------------------------------------------------------
219class SimpleServer : public Worker {
220 public:
221 SimpleServer() : Worker(Channel::MODE_SERVER, "simpler_server") { }
222 void Run() {
223 int answer = 0;
224 bool result = Send(new SyncChannelTestMsg_AnswerToLife(&answer));
225 DCHECK(result);
226 DCHECK(answer == 42);
227 Done();
228 }
229};
230
231class SimpleClient : public Worker {
232 public:
233 SimpleClient() : Worker(Channel::MODE_CLIENT, "simple_client") { }
234
235 void OnAnswer(int* answer) {
236 *answer = 42;
237 Done();
238 }
239};
240
241// Tests basic synchronous call
242TEST(IPCSyncChannelTest, Simple) {
243 std::vector<Worker*> workers;
244 workers.push_back(new SimpleServer());
245 workers.push_back(new SimpleClient());
246 RunTest(workers);
247}
248
249
250//-----------------------------------------------------------------------------
251class DelayClient : public Worker {
252 public:
253 DelayClient() : Worker(Channel::MODE_CLIENT, "delay_client") { }
254
255 void OnAnswerDelay(Message* reply_msg) {
256 SyncChannelTestMsg_AnswerToLife::WriteReplyParams(reply_msg, 42);
257 Send(reply_msg);
258 Done();
259 }
260};
261
262// Tests that asynchronous replies work
263TEST(IPCSyncChannelTest, DelayReply) {
264 std::vector<Worker*> workers;
265 workers.push_back(new SimpleServer());
266 workers.push_back(new DelayClient());
267 RunTest(workers);
268}
269
270
271//-----------------------------------------------------------------------------
272class NoHangServer : public Worker {
273 public:
274 explicit NoHangServer(Event* got_first_reply)
275 : Worker(Channel::MODE_SERVER, "no_hang_server"),
276 got_first_reply_(got_first_reply) { }
277 void Run() {
278 int answer = 0;
279 bool result = Send(new SyncChannelTestMsg_AnswerToLife(&answer));
280 DCHECK(result);
281 DCHECK(answer == 42);
282 got_first_reply_->Set();
283
284 result = Send(new SyncChannelTestMsg_AnswerToLife(&answer));
285 DCHECK(!result);
286 Done();
287 }
288
289 Event* got_first_reply_;
290};
291
292class NoHangClient : public Worker {
293 public:
294 explicit NoHangClient(Event* got_first_reply)
295 : Worker(Channel::MODE_CLIENT, "no_hang_client"),
296 got_first_reply_(got_first_reply) { }
297
298 virtual void OnAnswerDelay(Message* reply_msg) {
299 // Use the DELAY_REPLY macro so that we can force the reply to be sent
300 // before this function returns (when the channel will be reset).
301 SyncChannelTestMsg_AnswerToLife::WriteReplyParams(reply_msg, 42);
302 Send(reply_msg);
303 got_first_reply_->Wait();
304 CloseChannel();
305 Done();
306 }
307
308 Event* got_first_reply_;
309};
310
311// Tests that caller doesn't hang if receiver dies
312TEST(IPCSyncChannelTest, NoHang) {
313 Event got_first_reply;
314
315 std::vector<Worker*> workers;
316 workers.push_back(new NoHangServer(&got_first_reply));
317 workers.push_back(new NoHangClient(&got_first_reply));
318 RunTest(workers);
319}
320
321
322//-----------------------------------------------------------------------------
323class RecursiveServer : public Worker {
324 public:
325 RecursiveServer() : Worker(Channel::MODE_SERVER, "recursive_server") { }
326 void Run() {
327 int answer = 0;
328 bool result = Send(new SyncChannelTestMsg_AnswerToLife(&answer));
329 DCHECK(result);
330 DCHECK(answer == 42);
331 Done();
332 }
333
334 void OnDouble(int in, int* out) {
335 *out = in * 2;
336 }
337};
338
339class RecursiveClient : public Worker {
340 public:
341 RecursiveClient() : Worker(Channel::MODE_CLIENT, "recursive_client") { }
342
343 void OnAnswer(int* answer) {
344 BOOL result = Send(new SyncChannelTestMsg_Double(21, answer));
345 DCHECK(result);
346 Done();
347 }
348};
349
350// Tests that the caller unblocks to answer a sync message from the receiver.
351TEST(IPCSyncChannelTest, Recursive) {
352 std::vector<Worker*> workers;
353 workers.push_back(new RecursiveServer());
354 workers.push_back(new RecursiveClient());
355 RunTest(workers);
356}
357
358
359//-----------------------------------------------------------------------------
360class MultipleServer1 : public Worker {
361 public:
362 MultipleServer1() : Worker(L"test_channel1", Channel::MODE_SERVER) { }
363 void Run() {
364 int answer = 0;
365 bool result = Send(new SyncChannelTestMsg_Double(5, &answer));
366 DCHECK(result);
367 DCHECK(answer == 10);
368 Done();
369 }
370};
371
372class MultipleClient1 : public Worker {
373 public:
374 MultipleClient1(Event* client1_msg_received, Event* client1_can_reply) :
375 Worker(L"test_channel1", Channel::MODE_CLIENT),
376 client1_msg_received_(client1_msg_received),
377 client1_can_reply_(client1_can_reply) { }
378
379 void OnDouble(int in, int* out) {
380 client1_msg_received_->Set();
381 *out = in * 2;
382 client1_can_reply_->Wait();
383 Done();
384 }
385
386 private:
387 Event *client1_msg_received_, *client1_can_reply_;
388};
389
390class MultipleServer2 : public Worker {
391 public:
392 MultipleServer2() : Worker(L"test_channel2", Channel::MODE_SERVER) { }
393
394 void OnAnswer(int* result) {
395 *result = 42;
396 Done();
397 }
398};
399
400class MultipleClient2 : public Worker {
401 public:
402 MultipleClient2(Event* client1_msg_received, Event* client1_can_reply) :
403 Worker(L"test_channel2", Channel::MODE_CLIENT),
404 client1_msg_received_(client1_msg_received),
405 client1_can_reply_(client1_can_reply) { }
406
407 void Run() {
408 int answer = 0;
409 client1_msg_received_->Wait();
410 bool result = Send(new SyncChannelTestMsg_AnswerToLife(&answer));
411 DCHECK(result);
412 DCHECK(answer == 42);
413 client1_can_reply_->Set();
414 Done();
415 }
416
417 private:
418 Event *client1_msg_received_, *client1_can_reply_;
419};
420
421// Tests that multiple SyncObjects on the same listener thread can unblock each
422// other.
423TEST(IPCSyncChannelTest, Multiple) {
424 std::vector<Worker*> workers;
425
426 // A shared worker thread so that server1 and server2 run on one thread.
427 Thread worker_thread("Multiple");
428 worker_thread.Start();
429
430 // Server1 sends a sync msg to client1, which blocks the reply until
431 // server2 (which runs on the same worker thread as server1) responds
432 // to a sync msg from client2.
433 Event client1_msg_received, client1_can_reply;
434
435 Worker* worker;
436
437 worker = new MultipleServer2();
438 worker->OverrideThread(&worker_thread);
439 workers.push_back(worker);
440
441 worker = new MultipleClient2(
442 &client1_msg_received, &client1_can_reply);
443 workers.push_back(worker);
444
445 worker = new MultipleServer1();
446 worker->OverrideThread(&worker_thread);
447 workers.push_back(worker);
448
449 worker = new MultipleClient1(
450 &client1_msg_received, &client1_can_reply);
451 workers.push_back(worker);
452
453 RunTest(workers);
454}
455
456
457//-----------------------------------------------------------------------------
458class QueuedReplyServer1 : public Worker {
459 public:
460 QueuedReplyServer1() : Worker(L"test_channel1", Channel::MODE_SERVER) { }
461 void Run() {
462 int answer = 0;
463 bool result = Send(new SyncChannelTestMsg_Double(5, &answer));
464 DCHECK(result);
465 DCHECK(answer == 10);
466 Done();
467 }
468};
469
470class QueuedReplyClient1 : public Worker {
471 public:
472 QueuedReplyClient1(Event* client1_msg_received, Event* server2_can_reply) :
473 Worker(L"test_channel1", Channel::MODE_CLIENT),
474 client1_msg_received_(client1_msg_received),
475 server2_can_reply_(server2_can_reply) { }
476
477 void OnDouble(int in, int* out) {
478 client1_msg_received_->Set();
479 *out = in * 2;
480 server2_can_reply_->Wait();
481 Done();
482 }
483
484 private:
485 Event *client1_msg_received_, *server2_can_reply_;
486};
487
488class QueuedReplyServer2 : public Worker {
489 public:
490 explicit QueuedReplyServer2(Event* server2_can_reply) :
491 Worker(L"test_channel2", Channel::MODE_SERVER),
492 server2_can_reply_(server2_can_reply) { }
493
494 void OnAnswer(int* result) {
495 server2_can_reply_->Set();
496
497 // give client1's reply time to reach the server listener thread
498 Sleep(200);
499
500 *result = 42;
501 Done();
502 }
503
504 Event *server2_can_reply_;
505};
506
507class QueuedReplyClient2 : public Worker {
508 public:
509 explicit QueuedReplyClient2(Event* client1_msg_received) :
510 Worker(L"test_channel2", Channel::MODE_CLIENT),
511 client1_msg_received_(client1_msg_received) { }
512
513 void Run() {
514 int answer = 0;
515 client1_msg_received_->Wait();
516 bool result = Send(new SyncChannelTestMsg_AnswerToLife(&answer));
517 DCHECK(result);
518 DCHECK(answer == 42);
519 Done();
520 }
521
522 private:
523 Event *client1_msg_received_;
524};
525
526// While a blocking send is in progress, the listener thread might answer other
527// synchronous messages. This tests that if during the response to another
528// message the reply to the original messages comes, it is queued up correctly
529// and the original Send is unblocked later.
530TEST(IPCSyncChannelTest, QueuedReply) {
531 std::vector<Worker*> workers;
532
533 // A shared worker thread so that server1 and server2 run on one thread.
534 Thread worker_thread("QueuedReply");
535 worker_thread.Start();
536
537 Event client1_msg_received, server2_can_reply;
538
539 Worker* worker;
540
541 worker = new QueuedReplyServer2(&server2_can_reply);
542 worker->OverrideThread(&worker_thread);
543 workers.push_back(worker);
544
545 worker = new QueuedReplyClient2(&client1_msg_received);
546 workers.push_back(worker);
547
548 worker = new QueuedReplyServer1();
549 worker->OverrideThread(&worker_thread);
550 workers.push_back(worker);
551
552 worker = new QueuedReplyClient1(
553 &client1_msg_received, &server2_can_reply);
554 workers.push_back(worker);
555
556 RunTest(workers);
557}
558
559
560//-----------------------------------------------------------------------------
561class BadServer : public Worker {
562 public:
563 BadServer() : Worker(Channel::MODE_SERVER, "simpler_server") { }
564 void Run() {
565 int answer = 0;
566
567 Message* msg = new SyncMessage(MSG_ROUTING_CONTROL,
568 SyncChannelTestMsg_Double::ID,
569 Message::PRIORITY_NORMAL,
570 NULL);
571 // Temporarily set the minimum logging very high so that the assertion
572 // in ipc_message_utils doesn't fire.
573 int log_level = logging::GetMinLogLevel();
574 logging::SetMinLogLevel(kint32max);
575 bool result = Send(msg);
576 logging::SetMinLogLevel(log_level);
577 DCHECK(!result);
578
579 // Need to send another message to get the client to call Done().
580 result = Send(new SyncChannelTestMsg_AnswerToLife(&answer));
581 DCHECK(result);
582 DCHECK(answer == 42);
583
584 Done();
585 }
586};
587
588// Tests that if a message is not serialized correctly, the Send() will fail.
589TEST(IPCSyncChannelTest, BadMessage) {
590 std::vector<Worker*> workers;
591 workers.push_back(new BadServer());
592 workers.push_back(new SimpleClient());
593 RunTest(workers);
594}
595
596
597//-----------------------------------------------------------------------------
598class ChattyRecursiveClient : public Worker {
599 public:
600 ChattyRecursiveClient() :
601 Worker(Channel::MODE_CLIENT, "chatty_recursive_client") { }
602
603 void OnAnswer(int* answer) {
604 // The PostMessage limit is 10k. Send 20% more than that.
605 const int kMessageLimit = 10000;
606 const int kMessagesToSend = kMessageLimit * 120 / 100;
607 for (int i = 0; i < kMessagesToSend; ++i) {
608 bool result = Send(new SyncChannelTestMsg_Double(21, answer));
609 DCHECK(result);
610 if (!result)
611 break;
612 }
613 Done();
614 }
615};
616
617// Tests http://b/issue?id=1093251 - that sending lots of sync messages while
618// the receiver is waiting for a sync reply does not overflow the PostMessage
619// queue.
620TEST(IPCSyncChannelTest, ChattyServer) {
621 std::vector<Worker*> workers;
622 workers.push_back(new RecursiveServer());
623 workers.push_back(new ChattyRecursiveClient());
624 RunTest(workers);
625}