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(process_handle
, 5000));
242 base::CloseProcessHandle(process_handle
);
246 TEST_F(IPCChannelTest
, ChannelTestExistingPipe
) {
247 MyChannelListener channel_listener
;
248 // Setup IPC channel with existing pipe. Specify name in Chrome format.
249 std::string
name("\\\\.\\pipe\\chrome.");
250 name
.append(kTestClientChannel
);
251 const DWORD open_mode
= PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
|
252 FILE_FLAG_FIRST_PIPE_INSTANCE
;
253 HANDLE pipe
= CreateNamedPipeA(name
.c_str(),
255 PIPE_TYPE_BYTE
| PIPE_READMODE_BYTE
,
261 IPC::Channel
chan(IPC::ChannelHandle(pipe
), IPC::Channel::MODE_SERVER
,
263 // Channel will duplicate the handle.
265 ASSERT_TRUE(chan
.Connect());
267 channel_listener
.Init(&chan
);
269 base::ProcessHandle process_handle
= SpawnChild(TEST_CLIENT
, &chan
);
270 ASSERT_TRUE(process_handle
);
272 Send(&chan
, "hello from parent");
275 MessageLoop::current()->Run();
277 // Close Channel so client gets its OnChannelError() callback fired.
280 // Cleanup child process.
281 EXPECT_TRUE(base::WaitForSingleProcess(process_handle
, 5000));
282 base::CloseProcessHandle(process_handle
);
284 #endif // defined (OS_WIN)
286 TEST_F(IPCChannelTest
, ChannelProxyTest
) {
287 MyChannelListener channel_listener
;
289 // The thread needs to out-live the ChannelProxy.
290 base::Thread
thread("ChannelProxyTestServer");
291 base::Thread::Options options
;
292 options
.message_loop_type
= MessageLoop::TYPE_IO
;
293 thread
.StartWithOptions(options
);
295 // setup IPC channel proxy
296 IPC::ChannelProxy
chan(kTestClientChannel
, IPC::Channel::MODE_SERVER
,
297 &channel_listener
, thread
.message_loop_proxy());
299 channel_listener
.Init(&chan
);
302 base::ProcessHandle process_handle
= SpawnChild(TEST_CLIENT
, NULL
);
303 #elif defined(OS_POSIX)
304 bool debug_on_start
= CommandLine::ForCurrentProcess()->HasSwitch(
305 switches::kDebugChildren
);
306 base::FileHandleMappingVector fds_to_map
;
307 const int ipcfd
= chan
.GetClientFileDescriptor();
309 fds_to_map
.push_back(std::pair
<int, int>(ipcfd
, kPrimaryIPCChannel
+ 3));
312 base::ProcessHandle process_handle
= MultiProcessTest::SpawnChild(
316 #endif // defined(OS_POSIX)
318 ASSERT_TRUE(process_handle
);
320 Send(&chan
, "hello from parent");
323 MessageLoop::current()->Run();
325 // cleanup child process
326 EXPECT_TRUE(base::WaitForSingleProcess(process_handle
, 5000));
327 base::CloseProcessHandle(process_handle
);
332 class ChannelListenerWithOnConnectedSend
: public IPC::Listener
{
334 virtual void OnChannelConnected(int32 peer_pid
) OVERRIDE
{
338 virtual bool OnMessageReceived(const IPC::Message
& message
) OVERRIDE
{
339 IPC::MessageIterator
iter(message
);
342 const std::string data
= iter
.NextString();
343 const std::string big_string
= iter
.NextString();
344 EXPECT_EQ(kLongMessageStringNumBytes
- 1, big_string
.length());
349 virtual void OnChannelError() OVERRIDE
{
350 // There is a race when closing the channel so the last message may be lost.
351 EXPECT_LE(messages_left_
, 1);
352 MessageLoop::current()->Quit();
355 void Init(IPC::Sender
* s
) {
361 void SendNextMessage() {
362 if (--messages_left_
== 0) {
363 MessageLoop::current()->Quit();
365 Send(sender_
, "Foo");
369 IPC::Sender
* sender_
;
374 // Acting flakey in Windows. http://crbug.com/129595
375 #define MAYBE_SendMessageInChannelConnected DISABLED_SendMessageInChannelConnected
377 #define MAYBE_SendMessageInChannelConnected SendMessageInChannelConnected
379 TEST_F(IPCChannelTest
, MAYBE_SendMessageInChannelConnected
) {
380 // This tests the case of a listener sending back an event in it's
381 // OnChannelConnected handler.
383 ChannelListenerWithOnConnectedSend channel_listener
;
384 // Setup IPC channel.
385 IPC::Channel
channel(kTestClientChannel
, IPC::Channel::MODE_SERVER
,
387 channel_listener
.Init(&channel
);
388 ASSERT_TRUE(channel
.Connect());
390 base::ProcessHandle process_handle
= SpawnChild(TEST_CLIENT
, &channel
);
391 ASSERT_TRUE(process_handle
);
393 Send(&channel
, "hello from parent");
396 MessageLoop::current()->Run();
398 // Close Channel so client gets its OnChannelError() callback fired.
401 // Cleanup child process.
402 EXPECT_TRUE(base::WaitForSingleProcess(process_handle
, 5000));
403 base::CloseProcessHandle(process_handle
);
406 MULTIPROCESS_IPC_TEST_MAIN(RunTestClient
) {
407 MessageLoopForIO main_message_loop
;
408 MyChannelListener channel_listener
;
411 IPC::Channel
chan(kTestClientChannel
, IPC::Channel::MODE_CLIENT
,
413 CHECK(chan
.Connect());
414 channel_listener
.Init(&chan
);
415 Send(&chan
, "hello from child");
417 MessageLoop::current()->Run();
422 #endif // !PERFORMANCE_TEST
424 #ifdef PERFORMANCE_TEST
426 //-----------------------------------------------------------------------------
427 // Manually performance test
429 // This test times the roundtrip IPC message cycle. It is enabled with a
430 // special preprocessor define to enable it instead of the standard IPC
431 // unit tests. This works around some funny termination conditions in the
432 // regular unit tests.
434 // This test is not automated. To test, you will want to vary the message
435 // count and message size in TEST to get the numbers you want.
437 // FIXME(brettw): Automate this test and have it run by default.
439 // This channel listener just replies to all messages with the exact same
440 // message. It assumes each message has one string parameter. When the string
441 // "quit" is sent, it will exit.
442 class ChannelReflectorListener
: public IPC::Listener
{
444 explicit ChannelReflectorListener(IPC::Channel
*channel
) :
447 latency_messages_(0) {
448 std::cout
<< "Reflector up" << std::endl
;
451 ~ChannelReflectorListener() {
452 std::cout
<< "Client Messages: " << count_messages_
<< std::endl
;
453 std::cout
<< "Client Latency: " << latency_messages_
<< std::endl
;
456 virtual bool OnMessageReceived(const IPC::Message
& message
) {
458 IPC::MessageIterator
iter(message
);
459 int time
= iter
.NextInt();
460 int msgid
= iter
.NextInt();
461 std::string payload
= iter
.NextString();
462 latency_messages_
+= GetTickCount() - time
;
464 // cout << "reflector msg received: " << msgid << endl;
465 if (payload
== "quit")
466 MessageLoop::current()->Quit();
468 IPC::Message
* msg
= new IPC::Message(0,
470 IPC::Message::PRIORITY_NORMAL
);
471 msg
->WriteInt(GetTickCount());
472 msg
->WriteInt(msgid
);
473 msg
->WriteString(payload
);
479 IPC::Channel
*channel_
;
481 int latency_messages_
;
484 class ChannelPerfListener
: public IPC::Listener
{
486 ChannelPerfListener(IPC::Channel
* channel
, int msg_count
, int msg_size
) :
487 count_down_(msg_count
),
490 latency_messages_(0) {
491 payload_
.resize(msg_size
);
492 for (int i
= 0; i
< static_cast<int>(payload_
.size()); i
++)
494 std::cout
<< "perflistener up" << std::endl
;
497 ~ChannelPerfListener() {
498 std::cout
<< "Server Messages: " << count_messages_
<< std::endl
;
499 std::cout
<< "Server Latency: " << latency_messages_
<< std::endl
;
502 virtual bool OnMessageReceived(const IPC::Message
& message
) {
504 // decode the string so this gets counted in the total time
505 IPC::MessageIterator
iter(message
);
506 int time
= iter
.NextInt();
507 int msgid
= iter
.NextInt();
508 std::string cur
= iter
.NextString();
509 latency_messages_
+= GetTickCount() - time
;
511 // cout << "perflistener got message" << endl;
514 if (count_down_
== 0) {
515 IPC::Message
* msg
= new IPC::Message(0,
517 IPC::Message::PRIORITY_NORMAL
);
518 msg
->WriteInt(GetTickCount());
519 msg
->WriteInt(count_down_
);
520 msg
->WriteString("quit");
522 SetTimer(NULL
, 1, 250, (TIMERPROC
) PostQuitMessage
);
526 IPC::Message
* msg
= new IPC::Message(0,
528 IPC::Message::PRIORITY_NORMAL
);
529 msg
->WriteInt(GetTickCount());
530 msg
->WriteInt(count_down_
);
531 msg
->WriteString(payload_
);
538 std::string payload_
;
539 IPC::Channel
*channel_
;
541 int latency_messages_
;
544 TEST_F(IPCChannelTest
, Performance
) {
546 IPC::Channel
chan(kReflectorChannel
, IPC::Channel::MODE_SERVER
, NULL
);
547 ChannelPerfListener
perf_listener(&chan
, 10000, 100000);
548 chan
.set_listener(&perf_listener
);
549 ASSERT_TRUE(chan
.Connect());
551 HANDLE process
= SpawnChild(TEST_REFLECTOR
, &chan
);
552 ASSERT_TRUE(process
);
554 PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
556 PerfTimeLogger
logger("IPC_Perf");
558 // this initial message will kick-start the ping-pong of messages
559 IPC::Message
* message
= new IPC::Message(0,
561 IPC::Message::PRIORITY_NORMAL
);
562 message
->WriteInt(GetTickCount());
563 message
->WriteInt(-1);
564 message
->WriteString("Hello");
568 MessageLoop::current()->Run();
570 // cleanup child process
571 WaitForSingleObject(process
, 5000);
572 CloseHandle(process
);
575 // This message loop bounces all messages back to the sender
576 MULTIPROCESS_IPC_TEST_MAIN(RunReflector
) {
577 MessageLoopForIO main_message_loop
;
578 IPC::Channel
chan(kReflectorChannel
, IPC::Channel::MODE_CLIENT
, NULL
);
579 ChannelReflectorListener
channel_reflector_listener(&chan
);
580 chan
.set_listener(&channel_reflector_listener
);
581 ASSERT_TRUE(chan
.Connect());
583 MessageLoop::current()->Run();
587 #endif // PERFORMANCE_TEST
589 int main(int argc
, char** argv
) {
590 #ifdef PERFORMANCE_TEST
591 int retval
= base::PerfTestSuite(argc
, argv
).Run();
593 int retval
= base::TestSuite(argc
, argv
).Run();