1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "build/build_config.h"
9 #elif defined(OS_POSIX)
10 #include <sys/types.h>
18 #include "ipc/ipc_tests.h"
20 #include "base/base_switches.h"
21 #include "base/command_line.h"
22 #include "base/debug/debug_on_start_win.h"
23 #include "base/perftimer.h"
24 #include "base/test/perf_test_suite.h"
25 #include "base/test/test_suite.h"
26 #include "base/threading/thread.h"
27 #include "ipc/ipc_descriptors.h"
28 #include "ipc/ipc_channel.h"
29 #include "ipc/ipc_channel_proxy.h"
30 #include "ipc/ipc_message_utils.h"
31 #include "ipc/ipc_multiprocess_test.h"
32 #include "ipc/ipc_sender.h"
33 #include "ipc/ipc_switches.h"
34 #include "testing/multiprocess_func_list.h"
36 // Define to enable IPC performance testing instead of the regular unit tests
37 // #define PERFORMANCE_TEST
39 const char kTestClientChannel
[] = "T1";
40 const char kReflectorChannel
[] = "T2";
41 const char kFuzzerChannel
[] = "F3";
42 const char kSyncSocketChannel
[] = "S4";
44 const size_t kLongMessageStringNumBytes
= 50000;
46 #ifndef PERFORMANCE_TEST
48 void IPCChannelTest::SetUp() {
49 MultiProcessTest::SetUp();
51 // Construct a fresh IO Message loop for the duration of each test.
52 message_loop_
= new MessageLoopForIO();
55 void IPCChannelTest::TearDown() {
59 MultiProcessTest::TearDown();
63 base::ProcessHandle
IPCChannelTest::SpawnChild(ChildType child_type
,
64 IPC::Channel
*channel
) {
65 // kDebugChildren support.
67 CommandLine::ForCurrentProcess()->HasSwitch(switches::kDebugChildren
);
71 return MultiProcessTest::SpawnChild("RunTestClient", debug_on_start
);
73 return MultiProcessTest::SpawnChild("RunReflector", debug_on_start
);
75 return MultiProcessTest::SpawnChild("RunFuzzServer", debug_on_start
);
76 case SYNC_SOCKET_SERVER
:
77 return MultiProcessTest::SpawnChild("RunSyncSocketServer", debug_on_start
);
82 #elif defined(OS_POSIX)
83 base::ProcessHandle
IPCChannelTest::SpawnChild(ChildType child_type
,
84 IPC::Channel
*channel
) {
85 // kDebugChildren support.
87 CommandLine::ForCurrentProcess()->HasSwitch(switches::kDebugChildren
);
89 base::FileHandleMappingVector fds_to_map
;
90 const int ipcfd
= channel
->GetClientFileDescriptor();
92 fds_to_map
.push_back(std::pair
<int, int>(ipcfd
, kPrimaryIPCChannel
+ 3));
95 base::ProcessHandle ret
= base::kNullProcessHandle
;
98 ret
= MultiProcessTest::SpawnChild("RunTestClient",
102 case TEST_DESCRIPTOR_CLIENT
:
103 ret
= MultiProcessTest::SpawnChild("RunTestDescriptorClient",
107 case TEST_DESCRIPTOR_CLIENT_SANDBOXED
:
108 ret
= MultiProcessTest::SpawnChild("RunTestDescriptorClientSandboxed",
113 ret
= MultiProcessTest::SpawnChild("RunReflector",
118 ret
= MultiProcessTest::SpawnChild("RunFuzzServer",
122 case SYNC_SOCKET_SERVER
:
123 ret
= MultiProcessTest::SpawnChild("RunSyncSocketServer",
128 return base::kNullProcessHandle
;
133 #endif // defined(OS_POSIX)
135 TEST_F(IPCChannelTest
, BasicMessageTest
) {
137 std::string
v2("foobar");
138 std::wstring
v3(L
"hello world");
140 IPC::Message
m(0, 1, IPC::Message::PRIORITY_NORMAL
);
141 EXPECT_TRUE(m
.WriteInt(v1
));
142 EXPECT_TRUE(m
.WriteString(v2
));
143 EXPECT_TRUE(m
.WriteWString(v3
));
145 PickleIterator
iter(m
);
151 EXPECT_TRUE(m
.ReadInt(&iter
, &vi
));
154 EXPECT_TRUE(m
.ReadString(&iter
, &vs
));
157 EXPECT_TRUE(m
.ReadWString(&iter
, &vw
));
161 EXPECT_FALSE(m
.ReadInt(&iter
, &vi
));
162 EXPECT_FALSE(m
.ReadString(&iter
, &vs
));
163 EXPECT_FALSE(m
.ReadWString(&iter
, &vw
));
166 static void Send(IPC::Sender
* sender
, const char* text
) {
167 static int message_index
= 0;
169 IPC::Message
* message
= new IPC::Message(0,
171 IPC::Message::PRIORITY_NORMAL
);
172 message
->WriteInt(message_index
++);
173 message
->WriteString(std::string(text
));
175 // Make sure we can handle large messages.
176 char junk
[kLongMessageStringNumBytes
];
177 memset(junk
, 'a', sizeof(junk
)-1);
178 junk
[sizeof(junk
)-1] = 0;
179 message
->WriteString(std::string(junk
));
181 // DEBUG: printf("[%u] sending message [%s]\n", GetCurrentProcessId(), text);
182 sender
->Send(message
);
185 class MyChannelListener
: public IPC::Listener
{
187 virtual bool OnMessageReceived(const IPC::Message
& message
) {
188 IPC::MessageIterator
iter(message
);
191 const std::string data
= iter
.NextString();
192 const std::string big_string
= iter
.NextString();
193 EXPECT_EQ(kLongMessageStringNumBytes
- 1, big_string
.length());
196 if (--messages_left_
== 0) {
197 MessageLoop::current()->Quit();
199 Send(sender_
, "Foo");
204 virtual void OnChannelError() {
205 // There is a race when closing the channel so the last message may be lost.
206 EXPECT_LE(messages_left_
, 1);
207 MessageLoop::current()->Quit();
210 void Init(IPC::Sender
* s
) {
216 IPC::Sender
* sender_
;
220 TEST_F(IPCChannelTest
, ChannelTest
) {
221 MyChannelListener channel_listener
;
222 // Setup IPC channel.
223 IPC::Channel
chan(kTestClientChannel
, IPC::Channel::MODE_SERVER
,
225 ASSERT_TRUE(chan
.Connect());
227 channel_listener
.Init(&chan
);
229 base::ProcessHandle process_handle
= SpawnChild(TEST_CLIENT
, &chan
);
230 ASSERT_TRUE(process_handle
);
232 Send(&chan
, "hello from parent");
235 MessageLoop::current()->Run();
237 // Close Channel so client gets its OnChannelError() callback fired.
240 // Cleanup child process.
241 EXPECT_TRUE(base::WaitForSingleProcess(
242 process_handle
, base::TimeDelta::FromSeconds(5)));
243 base::CloseProcessHandle(process_handle
);
247 TEST_F(IPCChannelTest
, ChannelTestExistingPipe
) {
248 MyChannelListener channel_listener
;
249 // Setup IPC channel with existing pipe. Specify name in Chrome format.
250 std::string
name("\\\\.\\pipe\\chrome.");
251 name
.append(kTestClientChannel
);
252 const DWORD open_mode
= PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
|
253 FILE_FLAG_FIRST_PIPE_INSTANCE
;
254 HANDLE pipe
= CreateNamedPipeA(name
.c_str(),
256 PIPE_TYPE_BYTE
| PIPE_READMODE_BYTE
,
262 IPC::Channel
chan(IPC::ChannelHandle(pipe
), IPC::Channel::MODE_SERVER
,
264 // Channel will duplicate the handle.
266 ASSERT_TRUE(chan
.Connect());
268 channel_listener
.Init(&chan
);
270 base::ProcessHandle process_handle
= SpawnChild(TEST_CLIENT
, &chan
);
271 ASSERT_TRUE(process_handle
);
273 Send(&chan
, "hello from parent");
276 MessageLoop::current()->Run();
278 // Close Channel so client gets its OnChannelError() callback fired.
281 // Cleanup child process.
282 EXPECT_TRUE(base::WaitForSingleProcess(
283 process_handle
, base::TimeDelta::FromSeconds(5)));
284 base::CloseProcessHandle(process_handle
);
286 #endif // defined (OS_WIN)
288 TEST_F(IPCChannelTest
, ChannelProxyTest
) {
289 MyChannelListener channel_listener
;
291 // The thread needs to out-live the ChannelProxy.
292 base::Thread
thread("ChannelProxyTestServer");
293 base::Thread::Options options
;
294 options
.message_loop_type
= MessageLoop::TYPE_IO
;
295 thread
.StartWithOptions(options
);
297 // setup IPC channel proxy
298 IPC::ChannelProxy
chan(kTestClientChannel
, IPC::Channel::MODE_SERVER
,
299 &channel_listener
, thread
.message_loop_proxy());
301 channel_listener
.Init(&chan
);
304 base::ProcessHandle process_handle
= SpawnChild(TEST_CLIENT
, NULL
);
305 #elif defined(OS_POSIX)
306 bool debug_on_start
= CommandLine::ForCurrentProcess()->HasSwitch(
307 switches::kDebugChildren
);
308 base::FileHandleMappingVector fds_to_map
;
309 const int ipcfd
= chan
.GetClientFileDescriptor();
311 fds_to_map
.push_back(std::pair
<int, int>(ipcfd
, kPrimaryIPCChannel
+ 3));
314 base::ProcessHandle process_handle
= MultiProcessTest::SpawnChild(
318 #endif // defined(OS_POSIX)
320 ASSERT_TRUE(process_handle
);
322 Send(&chan
, "hello from parent");
325 MessageLoop::current()->Run();
327 // cleanup child process
328 EXPECT_TRUE(base::WaitForSingleProcess(
329 process_handle
, base::TimeDelta::FromSeconds(5)));
330 base::CloseProcessHandle(process_handle
);
335 class ChannelListenerWithOnConnectedSend
: public IPC::Listener
{
337 virtual void OnChannelConnected(int32 peer_pid
) OVERRIDE
{
341 virtual bool OnMessageReceived(const IPC::Message
& message
) OVERRIDE
{
342 IPC::MessageIterator
iter(message
);
345 const std::string data
= iter
.NextString();
346 const std::string big_string
= iter
.NextString();
347 EXPECT_EQ(kLongMessageStringNumBytes
- 1, big_string
.length());
352 virtual void OnChannelError() OVERRIDE
{
353 // There is a race when closing the channel so the last message may be lost.
354 EXPECT_LE(messages_left_
, 1);
355 MessageLoop::current()->Quit();
358 void Init(IPC::Sender
* s
) {
364 void SendNextMessage() {
365 if (--messages_left_
== 0) {
366 MessageLoop::current()->Quit();
368 Send(sender_
, "Foo");
372 IPC::Sender
* sender_
;
377 // Acting flakey in Windows. http://crbug.com/129595
378 #define MAYBE_SendMessageInChannelConnected DISABLED_SendMessageInChannelConnected
380 #define MAYBE_SendMessageInChannelConnected SendMessageInChannelConnected
382 TEST_F(IPCChannelTest
, MAYBE_SendMessageInChannelConnected
) {
383 // This tests the case of a listener sending back an event in it's
384 // OnChannelConnected handler.
386 ChannelListenerWithOnConnectedSend channel_listener
;
387 // Setup IPC channel.
388 IPC::Channel
channel(kTestClientChannel
, IPC::Channel::MODE_SERVER
,
390 channel_listener
.Init(&channel
);
391 ASSERT_TRUE(channel
.Connect());
393 base::ProcessHandle process_handle
= SpawnChild(TEST_CLIENT
, &channel
);
394 ASSERT_TRUE(process_handle
);
396 Send(&channel
, "hello from parent");
399 MessageLoop::current()->Run();
401 // Close Channel so client gets its OnChannelError() callback fired.
404 // Cleanup child process.
405 EXPECT_TRUE(base::WaitForSingleProcess(
406 process_handle
, base::TimeDelta::FromSeconds(5)));
407 base::CloseProcessHandle(process_handle
);
410 MULTIPROCESS_IPC_TEST_MAIN(RunTestClient
) {
411 MessageLoopForIO main_message_loop
;
412 MyChannelListener channel_listener
;
415 IPC::Channel
chan(kTestClientChannel
, IPC::Channel::MODE_CLIENT
,
417 CHECK(chan
.Connect());
418 channel_listener
.Init(&chan
);
419 Send(&chan
, "hello from child");
421 MessageLoop::current()->Run();
426 #endif // !PERFORMANCE_TEST
428 #ifdef PERFORMANCE_TEST
430 //-----------------------------------------------------------------------------
431 // Manually performance test
433 // This test times the roundtrip IPC message cycle. It is enabled with a
434 // special preprocessor define to enable it instead of the standard IPC
435 // unit tests. This works around some funny termination conditions in the
436 // regular unit tests.
438 // This test is not automated. To test, you will want to vary the message
439 // count and message size in TEST to get the numbers you want.
441 // FIXME(brettw): Automate this test and have it run by default.
443 // This channel listener just replies to all messages with the exact same
444 // message. It assumes each message has one string parameter. When the string
445 // "quit" is sent, it will exit.
446 class ChannelReflectorListener
: public IPC::Listener
{
448 explicit ChannelReflectorListener(IPC::Channel
*channel
) :
451 latency_messages_(0) {
452 std::cout
<< "Reflector up" << std::endl
;
455 ~ChannelReflectorListener() {
456 std::cout
<< "Client Messages: " << count_messages_
<< std::endl
;
457 std::cout
<< "Client Latency: " << latency_messages_
<< std::endl
;
460 virtual bool OnMessageReceived(const IPC::Message
& message
) {
462 IPC::MessageIterator
iter(message
);
463 int time
= iter
.NextInt();
464 int msgid
= iter
.NextInt();
465 std::string payload
= iter
.NextString();
466 latency_messages_
+= GetTickCount() - time
;
468 // cout << "reflector msg received: " << msgid << endl;
469 if (payload
== "quit")
470 MessageLoop::current()->Quit();
472 IPC::Message
* msg
= new IPC::Message(0,
474 IPC::Message::PRIORITY_NORMAL
);
475 msg
->WriteInt(GetTickCount());
476 msg
->WriteInt(msgid
);
477 msg
->WriteString(payload
);
483 IPC::Channel
*channel_
;
485 int latency_messages_
;
488 class ChannelPerfListener
: public IPC::Listener
{
490 ChannelPerfListener(IPC::Channel
* channel
, int msg_count
, int msg_size
) :
491 count_down_(msg_count
),
494 latency_messages_(0) {
495 payload_
.resize(msg_size
);
496 for (int i
= 0; i
< static_cast<int>(payload_
.size()); i
++)
498 std::cout
<< "perflistener up" << std::endl
;
501 ~ChannelPerfListener() {
502 std::cout
<< "Server Messages: " << count_messages_
<< std::endl
;
503 std::cout
<< "Server Latency: " << latency_messages_
<< std::endl
;
506 virtual bool OnMessageReceived(const IPC::Message
& message
) {
508 // decode the string so this gets counted in the total time
509 IPC::MessageIterator
iter(message
);
510 int time
= iter
.NextInt();
511 int msgid
= iter
.NextInt();
512 std::string cur
= iter
.NextString();
513 latency_messages_
+= GetTickCount() - time
;
515 // cout << "perflistener got message" << endl;
518 if (count_down_
== 0) {
519 IPC::Message
* msg
= new IPC::Message(0,
521 IPC::Message::PRIORITY_NORMAL
);
522 msg
->WriteInt(GetTickCount());
523 msg
->WriteInt(count_down_
);
524 msg
->WriteString("quit");
526 SetTimer(NULL
, 1, 250, (TIMERPROC
) PostQuitMessage
);
530 IPC::Message
* msg
= new IPC::Message(0,
532 IPC::Message::PRIORITY_NORMAL
);
533 msg
->WriteInt(GetTickCount());
534 msg
->WriteInt(count_down_
);
535 msg
->WriteString(payload_
);
542 std::string payload_
;
543 IPC::Channel
*channel_
;
545 int latency_messages_
;
548 TEST_F(IPCChannelTest
, Performance
) {
550 IPC::Channel
chan(kReflectorChannel
, IPC::Channel::MODE_SERVER
, NULL
);
551 ChannelPerfListener
perf_listener(&chan
, 10000, 100000);
552 chan
.set_listener(&perf_listener
);
553 ASSERT_TRUE(chan
.Connect());
555 HANDLE process
= SpawnChild(TEST_REFLECTOR
, &chan
);
556 ASSERT_TRUE(process
);
558 PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
560 PerfTimeLogger
logger("IPC_Perf");
562 // this initial message will kick-start the ping-pong of messages
563 IPC::Message
* message
= new IPC::Message(0,
565 IPC::Message::PRIORITY_NORMAL
);
566 message
->WriteInt(GetTickCount());
567 message
->WriteInt(-1);
568 message
->WriteString("Hello");
572 MessageLoop::current()->Run();
574 // cleanup child process
575 WaitForSingleObject(process
, 5000);
576 CloseHandle(process
);
579 // This message loop bounces all messages back to the sender
580 MULTIPROCESS_IPC_TEST_MAIN(RunReflector
) {
581 MessageLoopForIO main_message_loop
;
582 IPC::Channel
chan(kReflectorChannel
, IPC::Channel::MODE_CLIENT
, NULL
);
583 ChannelReflectorListener
channel_reflector_listener(&chan
);
584 chan
.set_listener(&channel_reflector_listener
);
585 ASSERT_TRUE(chan
.Connect());
587 MessageLoop::current()->Run();
591 #endif // PERFORMANCE_TEST
593 int main(int argc
, char** argv
) {
594 #ifdef PERFORMANCE_TEST
595 int retval
= base::PerfTestSuite(argc
, argv
).Run();
597 int retval
= base::TestSuite(argc
, argv
).Run();