1 // Copyright (c) 2006-2009 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/at_exit.h"
21 #include "base/base_switches.h"
22 #include "base/command_line.h"
23 #include "base/debug_on_start.h"
25 #include "base/at_exit.h"
26 #include "base/global_descriptors_posix.h"
28 #include "base/perftimer.h"
29 #include "base/test/perf_test_suite.h"
30 #include "base/test/test_suite.h"
31 #include "base/thread.h"
32 #include "ipc/ipc_descriptors.h"
33 #include "ipc/ipc_channel.h"
34 #include "ipc/ipc_channel_proxy.h"
35 #include "ipc/ipc_message_utils.h"
36 #include "ipc/ipc_switches.h"
37 #include "testing/multiprocess_func_list.h"
39 // Define to enable IPC performance testing instead of the regular unit tests
40 // #define PERFORMANCE_TEST
42 const char kTestClientChannel
[] = "T1";
43 const char kReflectorChannel
[] = "T2";
44 const char kFuzzerChannel
[] = "F3";
45 const char kSyncSocketChannel
[] = "S4";
47 const size_t kLongMessageStringNumBytes
= 50000;
49 #ifndef PERFORMANCE_TEST
51 void IPCChannelTest::SetUp() {
52 MultiProcessTest::SetUp();
54 // Construct a fresh IO Message loop for the duration of each test.
55 message_loop_
= new MessageLoopForIO();
58 void IPCChannelTest::TearDown() {
62 MultiProcessTest::TearDown();
66 base::ProcessHandle
IPCChannelTest::SpawnChild(ChildType child_type
,
67 IPC::Channel
*channel
) {
68 // kDebugChildren support.
70 CommandLine::ForCurrentProcess()->HasSwitch(switches::kDebugChildren
);
74 return MultiProcessTest::SpawnChild(L
"RunTestClient", debug_on_start
);
77 return MultiProcessTest::SpawnChild(L
"RunReflector", debug_on_start
);
80 return MultiProcessTest::SpawnChild(L
"RunFuzzServer", debug_on_start
);
82 case SYNC_SOCKET_SERVER
:
83 return MultiProcessTest::SpawnChild(L
"RunSyncSocketServer", debug_on_start
);
90 #elif defined(OS_POSIX)
91 base::ProcessHandle
IPCChannelTest::SpawnChild(ChildType child_type
,
92 IPC::Channel
*channel
) {
93 // kDebugChildren support.
95 CommandLine::ForCurrentProcess()->HasSwitch(switches::kDebugChildren
);
97 base::file_handle_mapping_vector fds_to_map
;
98 const int ipcfd
= channel
->GetClientFileDescriptor();
100 fds_to_map
.push_back(std::pair
<int,int>(ipcfd
, kPrimaryIPCChannel
+ 3));
103 base::ProcessHandle ret
= NULL
;
104 switch (child_type
) {
106 ret
= MultiProcessTest::SpawnChild(L
"RunTestClient",
110 case TEST_DESCRIPTOR_CLIENT
:
111 ret
= MultiProcessTest::SpawnChild(L
"RunTestDescriptorClient",
115 case TEST_DESCRIPTOR_CLIENT_SANDBOXED
:
116 ret
= MultiProcessTest::SpawnChild(L
"RunTestDescriptorClientSandboxed",
121 ret
= MultiProcessTest::SpawnChild(L
"RunReflector",
126 ret
= MultiProcessTest::SpawnChild(L
"RunFuzzServer",
130 case SYNC_SOCKET_SERVER
:
131 ret
= MultiProcessTest::SpawnChild(L
"RunSyncSocketServer",
141 #endif // defined(OS_POSIX)
143 TEST_F(IPCChannelTest
, BasicMessageTest
) {
145 std::string
v2("foobar");
146 std::wstring
v3(L
"hello world");
148 IPC::Message
m(0, 1, IPC::Message::PRIORITY_NORMAL
);
149 EXPECT_TRUE(m
.WriteInt(v1
));
150 EXPECT_TRUE(m
.WriteString(v2
));
151 EXPECT_TRUE(m
.WriteWString(v3
));
159 EXPECT_TRUE(m
.ReadInt(&iter
, &vi
));
162 EXPECT_TRUE(m
.ReadString(&iter
, &vs
));
165 EXPECT_TRUE(m
.ReadWString(&iter
, &vw
));
169 EXPECT_FALSE(m
.ReadInt(&iter
, &vi
));
170 EXPECT_FALSE(m
.ReadString(&iter
, &vs
));
171 EXPECT_FALSE(m
.ReadWString(&iter
, &vw
));
174 static void Send(IPC::Message::Sender
* sender
, const char* text
) {
175 static int message_index
= 0;
177 IPC::Message
* message
= new IPC::Message(0,
179 IPC::Message::PRIORITY_NORMAL
);
180 message
->WriteInt(message_index
++);
181 message
->WriteString(std::string(text
));
183 // Make sure we can handle large messages.
184 char junk
[kLongMessageStringNumBytes
];
185 memset(junk
, 'a', sizeof(junk
)-1);
186 junk
[sizeof(junk
)-1] = 0;
187 message
->WriteString(std::string(junk
));
189 // DEBUG: printf("[%u] sending message [%s]\n", GetCurrentProcessId(), text);
190 sender
->Send(message
);
193 class MyChannelListener
: public IPC::Channel::Listener
{
195 virtual void OnMessageReceived(const IPC::Message
& message
) {
196 IPC::MessageIterator
iter(message
);
199 const std::string data
= iter
.NextString();
200 const std::string big_string
= iter
.NextString();
201 EXPECT_EQ(kLongMessageStringNumBytes
- 1, big_string
.length());
204 if (--messages_left_
== 0) {
205 MessageLoop::current()->Quit();
207 Send(sender_
, "Foo");
211 virtual void OnChannelError() {
212 // There is a race when closing the channel so the last message may be lost.
213 EXPECT_LE(messages_left_
, 1);
214 MessageLoop::current()->Quit();
217 void Init(IPC::Message::Sender
* s
) {
223 IPC::Message::Sender
* sender_
;
227 TEST_F(IPCChannelTest
, ChannelTest
) {
228 MyChannelListener channel_listener
;
229 // Setup IPC channel.
230 IPC::Channel
chan(kTestClientChannel
, IPC::Channel::MODE_SERVER
,
234 channel_listener
.Init(&chan
);
236 base::ProcessHandle process_handle
= SpawnChild(TEST_CLIENT
, &chan
);
237 ASSERT_TRUE(process_handle
);
239 Send(&chan
, "hello from parent");
242 MessageLoop::current()->Run();
244 // Close Channel so client gets its OnChannelError() callback fired.
247 // Cleanup child process.
248 EXPECT_TRUE(base::WaitForSingleProcess(process_handle
, 5000));
249 base::CloseProcessHandle(process_handle
);
252 TEST_F(IPCChannelTest
, ChannelProxyTest
) {
253 MyChannelListener channel_listener
;
255 // The thread needs to out-live the ChannelProxy.
256 base::Thread
thread("ChannelProxyTestServer");
257 base::Thread::Options options
;
258 options
.message_loop_type
= MessageLoop::TYPE_IO
;
259 thread
.StartWithOptions(options
);
261 // setup IPC channel proxy
262 IPC::ChannelProxy
chan(kTestClientChannel
, IPC::Channel::MODE_SERVER
,
263 &channel_listener
, NULL
, thread
.message_loop());
265 channel_listener
.Init(&chan
);
268 base::ProcessHandle process_handle
= SpawnChild(TEST_CLIENT
, NULL
);
269 #elif defined(OS_POSIX)
270 bool debug_on_start
= CommandLine::ForCurrentProcess()->HasSwitch(
271 switches::kDebugChildren
);
272 base::file_handle_mapping_vector fds_to_map
;
273 const int ipcfd
= chan
.GetClientFileDescriptor();
275 fds_to_map
.push_back(std::pair
<int,int>(ipcfd
, kPrimaryIPCChannel
+ 3));
278 base::ProcessHandle process_handle
= MultiProcessTest::SpawnChild(
282 #endif // defined(OS_POSIX)
284 ASSERT_TRUE(process_handle
);
286 Send(&chan
, "hello from parent");
289 MessageLoop::current()->Run();
291 // cleanup child process
292 EXPECT_TRUE(base::WaitForSingleProcess(process_handle
, 5000));
293 base::CloseProcessHandle(process_handle
);
298 class ChannelListenerWithOnConnectedSend
: public IPC::Channel::Listener
{
300 virtual void OnChannelConnected(int32 peer_pid
) {
304 virtual void OnMessageReceived(const IPC::Message
& message
) {
305 IPC::MessageIterator
iter(message
);
308 const std::string data
= iter
.NextString();
309 const std::string big_string
= iter
.NextString();
310 EXPECT_EQ(kLongMessageStringNumBytes
- 1, big_string
.length());
314 virtual void OnChannelError() {
315 // There is a race when closing the channel so the last message may be lost.
316 EXPECT_LE(messages_left_
, 1);
317 MessageLoop::current()->Quit();
320 void Init(IPC::Message::Sender
* s
) {
326 void SendNextMessage() {
327 if (--messages_left_
== 0) {
328 MessageLoop::current()->Quit();
330 Send(sender_
, "Foo");
334 IPC::Message::Sender
* sender_
;
338 TEST_F(IPCChannelTest
, SendMessageInChannelConnected
) {
339 // This tests the case of a listener sending back an event in it's
340 // OnChannelConnected handler.
342 ChannelListenerWithOnConnectedSend channel_listener
;
343 // Setup IPC channel.
344 IPC::Channel
channel(kTestClientChannel
, IPC::Channel::MODE_SERVER
,
346 channel_listener
.Init(&channel
);
349 base::ProcessHandle process_handle
= SpawnChild(TEST_CLIENT
, &channel
);
350 ASSERT_TRUE(process_handle
);
352 Send(&channel
, "hello from parent");
355 MessageLoop::current()->Run();
357 // Close Channel so client gets its OnChannelError() callback fired.
360 // Cleanup child process.
361 EXPECT_TRUE(base::WaitForSingleProcess(process_handle
, 5000));
362 base::CloseProcessHandle(process_handle
);
365 MULTIPROCESS_TEST_MAIN(RunTestClient
) {
366 MessageLoopForIO main_message_loop
;
367 MyChannelListener channel_listener
;
370 IPC::Channel
chan(kTestClientChannel
, IPC::Channel::MODE_CLIENT
,
373 channel_listener
.Init(&chan
);
374 Send(&chan
, "hello from child");
376 MessageLoop::current()->Run();
381 #endif // !PERFORMANCE_TEST
383 #ifdef PERFORMANCE_TEST
385 //-----------------------------------------------------------------------------
386 // Manually performance test
388 // This test times the roundtrip IPC message cycle. It is enabled with a
389 // special preprocessor define to enable it instead of the standard IPC
390 // unit tests. This works around some funny termination conditions in the
391 // regular unit tests.
393 // This test is not automated. To test, you will want to vary the message
394 // count and message size in TEST to get the numbers you want.
396 // FIXME(brettw): Automate this test and have it run by default.
398 // This channel listener just replies to all messages with the exact same
399 // message. It assumes each message has one string parameter. When the string
400 // "quit" is sent, it will exit.
401 class ChannelReflectorListener
: public IPC::Channel::Listener
{
403 explicit ChannelReflectorListener(IPC::Channel
*channel
) :
406 latency_messages_(0) {
407 std::cout
<< "Reflector up" << std::endl
;
410 ~ChannelReflectorListener() {
411 std::cout
<< "Client Messages: " << count_messages_
<< std::endl
;
412 std::cout
<< "Client Latency: " << latency_messages_
<< std::endl
;
415 virtual void OnMessageReceived(const IPC::Message
& message
) {
417 IPC::MessageIterator
iter(message
);
418 int time
= iter
.NextInt();
419 int msgid
= iter
.NextInt();
420 std::string payload
= iter
.NextString();
421 latency_messages_
+= GetTickCount() - time
;
423 // cout << "reflector msg received: " << msgid << endl;
424 if (payload
== "quit")
425 MessageLoop::current()->Quit();
427 IPC::Message
* msg
= new IPC::Message(0,
429 IPC::Message::PRIORITY_NORMAL
);
430 msg
->WriteInt(GetTickCount());
431 msg
->WriteInt(msgid
);
432 msg
->WriteString(payload
);
436 IPC::Channel
*channel_
;
438 int latency_messages_
;
441 class ChannelPerfListener
: public IPC::Channel::Listener
{
443 ChannelPerfListener(IPC::Channel
* channel
, int msg_count
, int msg_size
) :
444 count_down_(msg_count
),
447 latency_messages_(0) {
448 payload_
.resize(msg_size
);
449 for (int i
= 0; i
< static_cast<int>(payload_
.size()); i
++)
451 std::cout
<< "perflistener up" << std::endl
;
454 ~ChannelPerfListener() {
455 std::cout
<< "Server Messages: " << count_messages_
<< std::endl
;
456 std::cout
<< "Server Latency: " << latency_messages_
<< std::endl
;
459 virtual void OnMessageReceived(const IPC::Message
& message
) {
461 // decode the string so this gets counted in the total time
462 IPC::MessageIterator
iter(message
);
463 int time
= iter
.NextInt();
464 int msgid
= iter
.NextInt();
465 std::string cur
= iter
.NextString();
466 latency_messages_
+= GetTickCount() - time
;
468 // cout << "perflistener got message" << endl;
471 if (count_down_
== 0) {
472 IPC::Message
* msg
= new IPC::Message(0,
474 IPC::Message::PRIORITY_NORMAL
);
475 msg
->WriteInt(GetTickCount());
476 msg
->WriteInt(count_down_
);
477 msg
->WriteString("quit");
479 SetTimer(NULL
, 1, 250, (TIMERPROC
) PostQuitMessage
);
483 IPC::Message
* msg
= new IPC::Message(0,
485 IPC::Message::PRIORITY_NORMAL
);
486 msg
->WriteInt(GetTickCount());
487 msg
->WriteInt(count_down_
);
488 msg
->WriteString(payload_
);
494 std::string payload_
;
495 IPC::Channel
*channel_
;
497 int latency_messages_
;
500 TEST_F(IPCChannelTest
, Performance
) {
502 IPC::Channel
chan(kReflectorChannel
, IPC::Channel::MODE_SERVER
, NULL
);
503 ChannelPerfListener
perf_listener(&chan
, 10000, 100000);
504 chan
.set_listener(&perf_listener
);
507 HANDLE process
= SpawnChild(TEST_REFLECTOR
, &chan
);
508 ASSERT_TRUE(process
);
510 PlatformThread::Sleep(1000);
512 PerfTimeLogger
logger("IPC_Perf");
514 // this initial message will kick-start the ping-pong of messages
515 IPC::Message
* message
= new IPC::Message(0,
517 IPC::Message::PRIORITY_NORMAL
);
518 message
->WriteInt(GetTickCount());
519 message
->WriteInt(-1);
520 message
->WriteString("Hello");
524 MessageLoop::current()->Run();
526 // cleanup child process
527 WaitForSingleObject(process
, 5000);
528 CloseHandle(process
);
531 // This message loop bounces all messages back to the sender
532 MULTIPROCESS_TEST_MAIN(RunReflector
) {
533 MessageLoopForIO main_message_loop
;
534 IPC::Channel
chan(kReflectorChannel
, IPC::Channel::MODE_CLIENT
, NULL
);
535 ChannelReflectorListener
channel_reflector_listener(&chan
);
536 chan
.set_listener(&channel_reflector_listener
);
539 MessageLoop::current()->Run();
543 #endif // PERFORMANCE_TEST
545 int main(int argc
, char** argv
) {
546 #ifdef PERFORMANCE_TEST
547 int retval
= PerfTestSuite(argc
, argv
).Run();
549 int retval
= TestSuite(argc
, argv
).Run();