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_switches.h"
32 #include "testing/multiprocess_func_list.h"
34 // Define to enable IPC performance testing instead of the regular unit tests
35 // #define PERFORMANCE_TEST
37 const char kTestClientChannel
[] = "T1";
38 const char kReflectorChannel
[] = "T2";
39 const char kFuzzerChannel
[] = "F3";
40 const char kSyncSocketChannel
[] = "S4";
42 const size_t kLongMessageStringNumBytes
= 50000;
44 #ifndef PERFORMANCE_TEST
46 void IPCChannelTest::SetUp() {
47 MultiProcessTest::SetUp();
49 // Construct a fresh IO Message loop for the duration of each test.
50 message_loop_
= new MessageLoopForIO();
53 void IPCChannelTest::TearDown() {
57 MultiProcessTest::TearDown();
61 base::ProcessHandle
IPCChannelTest::SpawnChild(ChildType child_type
,
62 IPC::Channel
*channel
) {
63 // kDebugChildren support.
65 CommandLine::ForCurrentProcess()->HasSwitch(switches::kDebugChildren
);
69 return MultiProcessTest::SpawnChild("RunTestClient", debug_on_start
);
71 return MultiProcessTest::SpawnChild("RunReflector", debug_on_start
);
73 return MultiProcessTest::SpawnChild("RunFuzzServer", debug_on_start
);
74 case SYNC_SOCKET_SERVER
:
75 return MultiProcessTest::SpawnChild("RunSyncSocketServer", debug_on_start
);
80 #elif defined(OS_POSIX)
81 base::ProcessHandle
IPCChannelTest::SpawnChild(ChildType child_type
,
82 IPC::Channel
*channel
) {
83 // kDebugChildren support.
85 CommandLine::ForCurrentProcess()->HasSwitch(switches::kDebugChildren
);
87 base::file_handle_mapping_vector fds_to_map
;
88 const int ipcfd
= channel
->GetClientFileDescriptor();
90 fds_to_map
.push_back(std::pair
<int, int>(ipcfd
, kPrimaryIPCChannel
+ 3));
93 base::ProcessHandle ret
= base::kNullProcessHandle
;
96 ret
= MultiProcessTest::SpawnChild("RunTestClient",
100 case TEST_DESCRIPTOR_CLIENT
:
101 ret
= MultiProcessTest::SpawnChild("RunTestDescriptorClient",
105 case TEST_DESCRIPTOR_CLIENT_SANDBOXED
:
106 ret
= MultiProcessTest::SpawnChild("RunTestDescriptorClientSandboxed",
111 ret
= MultiProcessTest::SpawnChild("RunReflector",
116 ret
= MultiProcessTest::SpawnChild("RunFuzzServer",
120 case SYNC_SOCKET_SERVER
:
121 ret
= MultiProcessTest::SpawnChild("RunSyncSocketServer",
126 return base::kNullProcessHandle
;
131 #endif // defined(OS_POSIX)
133 TEST_F(IPCChannelTest
, BasicMessageTest
) {
135 std::string
v2("foobar");
136 std::wstring
v3(L
"hello world");
138 IPC::Message
m(0, 1, IPC::Message::PRIORITY_NORMAL
);
139 EXPECT_TRUE(m
.WriteInt(v1
));
140 EXPECT_TRUE(m
.WriteString(v2
));
141 EXPECT_TRUE(m
.WriteWString(v3
));
149 EXPECT_TRUE(m
.ReadInt(&iter
, &vi
));
152 EXPECT_TRUE(m
.ReadString(&iter
, &vs
));
155 EXPECT_TRUE(m
.ReadWString(&iter
, &vw
));
159 EXPECT_FALSE(m
.ReadInt(&iter
, &vi
));
160 EXPECT_FALSE(m
.ReadString(&iter
, &vs
));
161 EXPECT_FALSE(m
.ReadWString(&iter
, &vw
));
164 static void Send(IPC::Message::Sender
* sender
, const char* text
) {
165 static int message_index
= 0;
167 IPC::Message
* message
= new IPC::Message(0,
169 IPC::Message::PRIORITY_NORMAL
);
170 message
->WriteInt(message_index
++);
171 message
->WriteString(std::string(text
));
173 // Make sure we can handle large messages.
174 char junk
[kLongMessageStringNumBytes
];
175 memset(junk
, 'a', sizeof(junk
)-1);
176 junk
[sizeof(junk
)-1] = 0;
177 message
->WriteString(std::string(junk
));
179 // DEBUG: printf("[%u] sending message [%s]\n", GetCurrentProcessId(), text);
180 sender
->Send(message
);
183 class MyChannelListener
: public IPC::Channel::Listener
{
185 virtual bool OnMessageReceived(const IPC::Message
& message
) {
186 IPC::MessageIterator
iter(message
);
189 const std::string data
= iter
.NextString();
190 const std::string big_string
= iter
.NextString();
191 EXPECT_EQ(kLongMessageStringNumBytes
- 1, big_string
.length());
194 if (--messages_left_
== 0) {
195 MessageLoop::current()->Quit();
197 Send(sender_
, "Foo");
202 virtual void OnChannelError() {
203 // There is a race when closing the channel so the last message may be lost.
204 EXPECT_LE(messages_left_
, 1);
205 MessageLoop::current()->Quit();
208 void Init(IPC::Message::Sender
* s
) {
214 IPC::Message::Sender
* sender_
;
218 TEST_F(IPCChannelTest
, ChannelTest
) {
219 MyChannelListener channel_listener
;
220 // Setup IPC channel.
221 IPC::Channel
chan(kTestClientChannel
, IPC::Channel::MODE_SERVER
,
223 ASSERT_TRUE(chan
.Connect());
225 channel_listener
.Init(&chan
);
227 base::ProcessHandle process_handle
= SpawnChild(TEST_CLIENT
, &chan
);
228 ASSERT_TRUE(process_handle
);
230 Send(&chan
, "hello from parent");
233 MessageLoop::current()->Run();
235 // Close Channel so client gets its OnChannelError() callback fired.
238 // Cleanup child process.
239 EXPECT_TRUE(base::WaitForSingleProcess(process_handle
, 5000));
240 base::CloseProcessHandle(process_handle
);
244 TEST_F(IPCChannelTest
, ChannelTestExistingPipe
) {
245 MyChannelListener channel_listener
;
246 // Setup IPC channel with existing pipe. Specify name in Chrome format.
247 std::string
name("\\\\.\\pipe\\chrome.");
248 name
.append(kTestClientChannel
);
249 const DWORD open_mode
= PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
|
250 FILE_FLAG_FIRST_PIPE_INSTANCE
;
251 HANDLE pipe
= CreateNamedPipeA(name
.c_str(),
253 PIPE_TYPE_BYTE
| PIPE_READMODE_BYTE
,
259 IPC::Channel
chan(IPC::ChannelHandle(pipe
), IPC::Channel::MODE_SERVER
,
261 // Channel will duplicate the handle.
263 ASSERT_TRUE(chan
.Connect());
265 channel_listener
.Init(&chan
);
267 base::ProcessHandle process_handle
= SpawnChild(TEST_CLIENT
, &chan
);
268 ASSERT_TRUE(process_handle
);
270 Send(&chan
, "hello from parent");
273 MessageLoop::current()->Run();
275 // Close Channel so client gets its OnChannelError() callback fired.
278 // Cleanup child process.
279 EXPECT_TRUE(base::WaitForSingleProcess(process_handle
, 5000));
280 base::CloseProcessHandle(process_handle
);
282 #endif // defined (OS_WIN)
284 TEST_F(IPCChannelTest
, ChannelProxyTest
) {
285 MyChannelListener channel_listener
;
287 // The thread needs to out-live the ChannelProxy.
288 base::Thread
thread("ChannelProxyTestServer");
289 base::Thread::Options options
;
290 options
.message_loop_type
= MessageLoop::TYPE_IO
;
291 thread
.StartWithOptions(options
);
293 // setup IPC channel proxy
294 IPC::ChannelProxy
chan(kTestClientChannel
, IPC::Channel::MODE_SERVER
,
295 &channel_listener
, thread
.message_loop_proxy());
297 channel_listener
.Init(&chan
);
300 base::ProcessHandle process_handle
= SpawnChild(TEST_CLIENT
, NULL
);
301 #elif defined(OS_POSIX)
302 bool debug_on_start
= CommandLine::ForCurrentProcess()->HasSwitch(
303 switches::kDebugChildren
);
304 base::file_handle_mapping_vector fds_to_map
;
305 const int ipcfd
= chan
.GetClientFileDescriptor();
307 fds_to_map
.push_back(std::pair
<int, int>(ipcfd
, kPrimaryIPCChannel
+ 3));
310 base::ProcessHandle process_handle
= MultiProcessTest::SpawnChild(
314 #endif // defined(OS_POSIX)
316 ASSERT_TRUE(process_handle
);
318 Send(&chan
, "hello from parent");
321 MessageLoop::current()->Run();
323 // cleanup child process
324 EXPECT_TRUE(base::WaitForSingleProcess(process_handle
, 5000));
325 base::CloseProcessHandle(process_handle
);
330 class ChannelListenerWithOnConnectedSend
: public IPC::Channel::Listener
{
332 virtual void OnChannelConnected(int32 peer_pid
) OVERRIDE
{
336 virtual bool OnMessageReceived(const IPC::Message
& message
) OVERRIDE
{
337 IPC::MessageIterator
iter(message
);
340 const std::string data
= iter
.NextString();
341 const std::string big_string
= iter
.NextString();
342 EXPECT_EQ(kLongMessageStringNumBytes
- 1, big_string
.length());
347 virtual void OnChannelError() OVERRIDE
{
348 // There is a race when closing the channel so the last message may be lost.
349 EXPECT_LE(messages_left_
, 1);
350 MessageLoop::current()->Quit();
353 void Init(IPC::Message::Sender
* s
) {
359 void SendNextMessage() {
360 if (--messages_left_
== 0) {
361 MessageLoop::current()->Quit();
363 Send(sender_
, "Foo");
367 IPC::Message::Sender
* sender_
;
371 TEST_F(IPCChannelTest
, SendMessageInChannelConnected
) {
372 // This tests the case of a listener sending back an event in it's
373 // OnChannelConnected handler.
375 ChannelListenerWithOnConnectedSend channel_listener
;
376 // Setup IPC channel.
377 IPC::Channel
channel(kTestClientChannel
, IPC::Channel::MODE_SERVER
,
379 channel_listener
.Init(&channel
);
380 ASSERT_TRUE(channel
.Connect());
382 base::ProcessHandle process_handle
= SpawnChild(TEST_CLIENT
, &channel
);
383 ASSERT_TRUE(process_handle
);
385 Send(&channel
, "hello from parent");
388 MessageLoop::current()->Run();
390 // Close Channel so client gets its OnChannelError() callback fired.
393 // Cleanup child process.
394 EXPECT_TRUE(base::WaitForSingleProcess(process_handle
, 5000));
395 base::CloseProcessHandle(process_handle
);
398 MULTIPROCESS_TEST_MAIN(RunTestClient
) {
399 MessageLoopForIO main_message_loop
;
400 MyChannelListener channel_listener
;
403 IPC::Channel
chan(kTestClientChannel
, IPC::Channel::MODE_CLIENT
,
405 CHECK(chan
.Connect());
406 channel_listener
.Init(&chan
);
407 Send(&chan
, "hello from child");
409 MessageLoop::current()->Run();
414 #endif // !PERFORMANCE_TEST
416 #ifdef PERFORMANCE_TEST
418 //-----------------------------------------------------------------------------
419 // Manually performance test
421 // This test times the roundtrip IPC message cycle. It is enabled with a
422 // special preprocessor define to enable it instead of the standard IPC
423 // unit tests. This works around some funny termination conditions in the
424 // regular unit tests.
426 // This test is not automated. To test, you will want to vary the message
427 // count and message size in TEST to get the numbers you want.
429 // FIXME(brettw): Automate this test and have it run by default.
431 // This channel listener just replies to all messages with the exact same
432 // message. It assumes each message has one string parameter. When the string
433 // "quit" is sent, it will exit.
434 class ChannelReflectorListener
: public IPC::Channel::Listener
{
436 explicit ChannelReflectorListener(IPC::Channel
*channel
) :
439 latency_messages_(0) {
440 std::cout
<< "Reflector up" << std::endl
;
443 ~ChannelReflectorListener() {
444 std::cout
<< "Client Messages: " << count_messages_
<< std::endl
;
445 std::cout
<< "Client Latency: " << latency_messages_
<< std::endl
;
448 virtual bool OnMessageReceived(const IPC::Message
& message
) {
450 IPC::MessageIterator
iter(message
);
451 int time
= iter
.NextInt();
452 int msgid
= iter
.NextInt();
453 std::string payload
= iter
.NextString();
454 latency_messages_
+= GetTickCount() - time
;
456 // cout << "reflector msg received: " << msgid << endl;
457 if (payload
== "quit")
458 MessageLoop::current()->Quit();
460 IPC::Message
* msg
= new IPC::Message(0,
462 IPC::Message::PRIORITY_NORMAL
);
463 msg
->WriteInt(GetTickCount());
464 msg
->WriteInt(msgid
);
465 msg
->WriteString(payload
);
470 IPC::Channel
*channel_
;
472 int latency_messages_
;
475 class ChannelPerfListener
: public IPC::Channel::Listener
{
477 ChannelPerfListener(IPC::Channel
* channel
, int msg_count
, int msg_size
) :
478 count_down_(msg_count
),
481 latency_messages_(0) {
482 payload_
.resize(msg_size
);
483 for (int i
= 0; i
< static_cast<int>(payload_
.size()); i
++)
485 std::cout
<< "perflistener up" << std::endl
;
488 ~ChannelPerfListener() {
489 std::cout
<< "Server Messages: " << count_messages_
<< std::endl
;
490 std::cout
<< "Server Latency: " << latency_messages_
<< std::endl
;
493 virtual bool OnMessageReceived(const IPC::Message
& message
) {
495 // decode the string so this gets counted in the total time
496 IPC::MessageIterator
iter(message
);
497 int time
= iter
.NextInt();
498 int msgid
= iter
.NextInt();
499 std::string cur
= iter
.NextString();
500 latency_messages_
+= GetTickCount() - time
;
502 // cout << "perflistener got message" << endl;
505 if (count_down_
== 0) {
506 IPC::Message
* msg
= new IPC::Message(0,
508 IPC::Message::PRIORITY_NORMAL
);
509 msg
->WriteInt(GetTickCount());
510 msg
->WriteInt(count_down_
);
511 msg
->WriteString("quit");
513 SetTimer(NULL
, 1, 250, (TIMERPROC
) PostQuitMessage
);
517 IPC::Message
* msg
= new IPC::Message(0,
519 IPC::Message::PRIORITY_NORMAL
);
520 msg
->WriteInt(GetTickCount());
521 msg
->WriteInt(count_down_
);
522 msg
->WriteString(payload_
);
529 std::string payload_
;
530 IPC::Channel
*channel_
;
532 int latency_messages_
;
535 TEST_F(IPCChannelTest
, Performance
) {
537 IPC::Channel
chan(kReflectorChannel
, IPC::Channel::MODE_SERVER
, NULL
);
538 ChannelPerfListener
perf_listener(&chan
, 10000, 100000);
539 chan
.set_listener(&perf_listener
);
540 ASSERT_TRUE(chan
.Connect());
542 HANDLE process
= SpawnChild(TEST_REFLECTOR
, &chan
);
543 ASSERT_TRUE(process
);
545 PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
547 PerfTimeLogger
logger("IPC_Perf");
549 // this initial message will kick-start the ping-pong of messages
550 IPC::Message
* message
= new IPC::Message(0,
552 IPC::Message::PRIORITY_NORMAL
);
553 message
->WriteInt(GetTickCount());
554 message
->WriteInt(-1);
555 message
->WriteString("Hello");
559 MessageLoop::current()->Run();
561 // cleanup child process
562 WaitForSingleObject(process
, 5000);
563 CloseHandle(process
);
566 // This message loop bounces all messages back to the sender
567 MULTIPROCESS_TEST_MAIN(RunReflector
) {
568 MessageLoopForIO main_message_loop
;
569 IPC::Channel
chan(kReflectorChannel
, IPC::Channel::MODE_CLIENT
, NULL
);
570 ChannelReflectorListener
channel_reflector_listener(&chan
);
571 chan
.set_listener(&channel_reflector_listener
);
572 ASSERT_TRUE(chan
.Connect());
574 MessageLoop::current()->Run();
578 #endif // PERFORMANCE_TEST
580 int main(int argc
, char** argv
) {
581 #ifdef PERFORMANCE_TEST
582 int retval
= base::PerfTestSuite(argc
, argv
).Run();
584 int retval
= base::TestSuite(argc
, argv
).Run();