1 // Copyright (c) 2010 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
);
243 TEST_F(IPCChannelTest
, ChannelProxyTest
) {
244 MyChannelListener channel_listener
;
246 // The thread needs to out-live the ChannelProxy.
247 base::Thread
thread("ChannelProxyTestServer");
248 base::Thread::Options options
;
249 options
.message_loop_type
= MessageLoop::TYPE_IO
;
250 thread
.StartWithOptions(options
);
252 // setup IPC channel proxy
253 IPC::ChannelProxy
chan(kTestClientChannel
, IPC::Channel::MODE_SERVER
,
254 &channel_listener
, thread
.message_loop());
256 channel_listener
.Init(&chan
);
259 base::ProcessHandle process_handle
= SpawnChild(TEST_CLIENT
, NULL
);
260 #elif defined(OS_POSIX)
261 bool debug_on_start
= CommandLine::ForCurrentProcess()->HasSwitch(
262 switches::kDebugChildren
);
263 base::file_handle_mapping_vector fds_to_map
;
264 const int ipcfd
= chan
.GetClientFileDescriptor();
266 fds_to_map
.push_back(std::pair
<int, int>(ipcfd
, kPrimaryIPCChannel
+ 3));
269 base::ProcessHandle process_handle
= MultiProcessTest::SpawnChild(
273 #endif // defined(OS_POSIX)
275 ASSERT_TRUE(process_handle
);
277 Send(&chan
, "hello from parent");
280 MessageLoop::current()->Run();
282 // cleanup child process
283 EXPECT_TRUE(base::WaitForSingleProcess(process_handle
, 5000));
284 base::CloseProcessHandle(process_handle
);
289 class ChannelListenerWithOnConnectedSend
: public IPC::Channel::Listener
{
291 virtual void OnChannelConnected(int32 peer_pid
) {
295 virtual bool OnMessageReceived(const IPC::Message
& message
) {
296 IPC::MessageIterator
iter(message
);
299 const std::string data
= iter
.NextString();
300 const std::string big_string
= iter
.NextString();
301 EXPECT_EQ(kLongMessageStringNumBytes
- 1, big_string
.length());
306 virtual void OnChannelError() {
307 // There is a race when closing the channel so the last message may be lost.
308 EXPECT_LE(messages_left_
, 1);
309 MessageLoop::current()->Quit();
312 void Init(IPC::Message::Sender
* s
) {
318 void SendNextMessage() {
319 if (--messages_left_
== 0) {
320 MessageLoop::current()->Quit();
322 Send(sender_
, "Foo");
326 IPC::Message::Sender
* sender_
;
330 TEST_F(IPCChannelTest
, SendMessageInChannelConnected
) {
331 // This tests the case of a listener sending back an event in it's
332 // OnChannelConnected handler.
334 ChannelListenerWithOnConnectedSend channel_listener
;
335 // Setup IPC channel.
336 IPC::Channel
channel(kTestClientChannel
, IPC::Channel::MODE_SERVER
,
338 channel_listener
.Init(&channel
);
339 ASSERT_TRUE(channel
.Connect());
341 base::ProcessHandle process_handle
= SpawnChild(TEST_CLIENT
, &channel
);
342 ASSERT_TRUE(process_handle
);
344 Send(&channel
, "hello from parent");
347 MessageLoop::current()->Run();
349 // Close Channel so client gets its OnChannelError() callback fired.
352 // Cleanup child process.
353 EXPECT_TRUE(base::WaitForSingleProcess(process_handle
, 5000));
354 base::CloseProcessHandle(process_handle
);
357 MULTIPROCESS_TEST_MAIN(RunTestClient
) {
358 MessageLoopForIO main_message_loop
;
359 MyChannelListener channel_listener
;
362 IPC::Channel
chan(kTestClientChannel
, IPC::Channel::MODE_CLIENT
,
364 CHECK(chan
.Connect());
365 channel_listener
.Init(&chan
);
366 Send(&chan
, "hello from child");
368 MessageLoop::current()->Run();
373 #endif // !PERFORMANCE_TEST
375 #ifdef PERFORMANCE_TEST
377 //-----------------------------------------------------------------------------
378 // Manually performance test
380 // This test times the roundtrip IPC message cycle. It is enabled with a
381 // special preprocessor define to enable it instead of the standard IPC
382 // unit tests. This works around some funny termination conditions in the
383 // regular unit tests.
385 // This test is not automated. To test, you will want to vary the message
386 // count and message size in TEST to get the numbers you want.
388 // FIXME(brettw): Automate this test and have it run by default.
390 // This channel listener just replies to all messages with the exact same
391 // message. It assumes each message has one string parameter. When the string
392 // "quit" is sent, it will exit.
393 class ChannelReflectorListener
: public IPC::Channel::Listener
{
395 explicit ChannelReflectorListener(IPC::Channel
*channel
) :
398 latency_messages_(0) {
399 std::cout
<< "Reflector up" << std::endl
;
402 ~ChannelReflectorListener() {
403 std::cout
<< "Client Messages: " << count_messages_
<< std::endl
;
404 std::cout
<< "Client Latency: " << latency_messages_
<< std::endl
;
407 virtual bool OnMessageReceived(const IPC::Message
& message
) {
409 IPC::MessageIterator
iter(message
);
410 int time
= iter
.NextInt();
411 int msgid
= iter
.NextInt();
412 std::string payload
= iter
.NextString();
413 latency_messages_
+= GetTickCount() - time
;
415 // cout << "reflector msg received: " << msgid << endl;
416 if (payload
== "quit")
417 MessageLoop::current()->Quit();
419 IPC::Message
* msg
= new IPC::Message(0,
421 IPC::Message::PRIORITY_NORMAL
);
422 msg
->WriteInt(GetTickCount());
423 msg
->WriteInt(msgid
);
424 msg
->WriteString(payload
);
429 IPC::Channel
*channel_
;
431 int latency_messages_
;
434 class ChannelPerfListener
: public IPC::Channel::Listener
{
436 ChannelPerfListener(IPC::Channel
* channel
, int msg_count
, int msg_size
) :
437 count_down_(msg_count
),
440 latency_messages_(0) {
441 payload_
.resize(msg_size
);
442 for (int i
= 0; i
< static_cast<int>(payload_
.size()); i
++)
444 std::cout
<< "perflistener up" << std::endl
;
447 ~ChannelPerfListener() {
448 std::cout
<< "Server Messages: " << count_messages_
<< std::endl
;
449 std::cout
<< "Server Latency: " << latency_messages_
<< std::endl
;
452 virtual bool OnMessageReceived(const IPC::Message
& message
) {
454 // decode the string so this gets counted in the total time
455 IPC::MessageIterator
iter(message
);
456 int time
= iter
.NextInt();
457 int msgid
= iter
.NextInt();
458 std::string cur
= iter
.NextString();
459 latency_messages_
+= GetTickCount() - time
;
461 // cout << "perflistener got message" << endl;
464 if (count_down_
== 0) {
465 IPC::Message
* msg
= new IPC::Message(0,
467 IPC::Message::PRIORITY_NORMAL
);
468 msg
->WriteInt(GetTickCount());
469 msg
->WriteInt(count_down_
);
470 msg
->WriteString("quit");
472 SetTimer(NULL
, 1, 250, (TIMERPROC
) PostQuitMessage
);
476 IPC::Message
* msg
= new IPC::Message(0,
478 IPC::Message::PRIORITY_NORMAL
);
479 msg
->WriteInt(GetTickCount());
480 msg
->WriteInt(count_down_
);
481 msg
->WriteString(payload_
);
488 std::string payload_
;
489 IPC::Channel
*channel_
;
491 int latency_messages_
;
494 TEST_F(IPCChannelTest
, Performance
) {
496 IPC::Channel
chan(kReflectorChannel
, IPC::Channel::MODE_SERVER
, NULL
);
497 ChannelPerfListener
perf_listener(&chan
, 10000, 100000);
498 chan
.set_listener(&perf_listener
);
499 ASSERT_TRUE(chan
.Connect());
501 HANDLE process
= SpawnChild(TEST_REFLECTOR
, &chan
);
502 ASSERT_TRUE(process
);
504 PlatformThread::Sleep(1000);
506 PerfTimeLogger
logger("IPC_Perf");
508 // this initial message will kick-start the ping-pong of messages
509 IPC::Message
* message
= new IPC::Message(0,
511 IPC::Message::PRIORITY_NORMAL
);
512 message
->WriteInt(GetTickCount());
513 message
->WriteInt(-1);
514 message
->WriteString("Hello");
518 MessageLoop::current()->Run();
520 // cleanup child process
521 WaitForSingleObject(process
, 5000);
522 CloseHandle(process
);
525 // This message loop bounces all messages back to the sender
526 MULTIPROCESS_TEST_MAIN(RunReflector
) {
527 MessageLoopForIO main_message_loop
;
528 IPC::Channel
chan(kReflectorChannel
, IPC::Channel::MODE_CLIENT
, NULL
);
529 ChannelReflectorListener
channel_reflector_listener(&chan
);
530 chan
.set_listener(&channel_reflector_listener
);
531 ASSERT_TRUE(chan
.Connect());
533 MessageLoop::current()->Run();
537 #endif // PERFORMANCE_TEST
539 int main(int argc
, char** argv
) {
540 #ifdef PERFORMANCE_TEST
541 int retval
= base::PerfTestSuite(argc
, argv
).Run();
543 int retval
= base::TestSuite(argc
, argv
).Run();