blob: e2b541605137a855d4da2dbd16b6d3d26c620ab8 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 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.
initial.commit09911bf2008-07-26 23:55:294
[email protected]645aaa52009-02-07 01:03:055#include "build/build_config.h"
6
[email protected]d4651ff2008-12-02 16:51:587#if defined(OS_WIN)
initial.commit09911bf2008-07-26 23:55:298#include <windows.h>
[email protected]43cf8152009-02-07 00:57:459#elif defined(OS_POSIX)
10#include <sys/types.h>
11#include <sys/stat.h>
12#include <unistd.h>
[email protected]d4651ff2008-12-02 16:51:5813#endif
[email protected]43cf8152009-02-07 00:57:4514
initial.commit09911bf2008-07-26 23:55:2915#include <stdio.h>
16#include <iostream>
17#include <string>
18
19#include "chrome/common/ipc_tests.h"
20
[email protected]ae6454712008-08-01 03:06:2521#include "base/at_exit.h"
initial.commit09911bf2008-07-26 23:55:2922#include "base/base_switches.h"
23#include "base/command_line.h"
24#include "base/debug_on_start.h"
25#include "base/perftimer.h"
[email protected]302831b2009-01-13 22:35:1026#include "base/perf_test_suite.h"
[email protected]95cb7fb92008-12-09 22:00:4727#include "base/test_suite.h"
initial.commit09911bf2008-07-26 23:55:2928#include "base/thread.h"
29#include "chrome/common/chrome_switches.h"
[email protected]526776c2009-02-07 00:39:2630#if defined(OS_POSIX)
31#include "chrome/common/file_descriptor_posix.h"
32#endif
initial.commit09911bf2008-07-26 23:55:2933#include "chrome/common/ipc_channel.h"
34#include "chrome/common/ipc_channel_proxy.h"
35#include "chrome/common/ipc_message_utils.h"
[email protected]95cb7fb92008-12-09 22:00:4736#include "testing/multiprocess_func_list.h"
initial.commit09911bf2008-07-26 23:55:2937
38// Define to enable IPC performance testing instead of the regular unit tests
39// #define PERFORMANCE_TEST
40
41const wchar_t kTestClientChannel[] = L"T1";
42const wchar_t kReflectorChannel[] = L"T2";
43const wchar_t kFuzzerChannel[] = L"F3";
44
initial.commit09911bf2008-07-26 23:55:2945#ifndef PERFORMANCE_TEST
46
[email protected]95cb7fb92008-12-09 22:00:4747void IPCChannelTest::SetUp() {
48 MultiProcessTest::SetUp();
49
50 // Construct a fresh IO Message loop for the duration of each test.
51 message_loop_ = new MessageLoopForIO();
52}
53
54void IPCChannelTest::TearDown() {
55 delete message_loop_;
56 message_loop_ = NULL;
57
58 MultiProcessTest::TearDown();
59}
60
[email protected]df3c1ca12008-12-19 21:37:0161#if defined(OS_WIN)
62base::ProcessHandle IPCChannelTest::SpawnChild(ChildType child_type,
63 IPC::Channel *channel) {
[email protected]95cb7fb92008-12-09 22:00:4764 // kDebugChildren support.
[email protected]bb975362009-01-21 01:00:2265 bool debug_on_start =
66 CommandLine::ForCurrentProcess()->HasSwitch(switches::kDebugChildren);
[email protected]95cb7fb92008-12-09 22:00:4767
68 switch (child_type) {
69 case TEST_CLIENT:
70 return MultiProcessTest::SpawnChild(L"RunTestClient", debug_on_start);
71 break;
72 case TEST_REFLECTOR:
73 return MultiProcessTest::SpawnChild(L"RunReflector", debug_on_start);
74 break;
75 case FUZZER_SERVER:
76 return MultiProcessTest::SpawnChild(L"RunFuzzServer", debug_on_start);
77 break;
78 default:
79 return NULL;
80 break;
81 }
82}
[email protected]df3c1ca12008-12-19 21:37:0183#elif defined(OS_POSIX)
84base::ProcessHandle IPCChannelTest::SpawnChild(ChildType child_type,
85 IPC::Channel *channel) {
86 // kDebugChildren support.
[email protected]bb975362009-01-21 01:00:2287 bool debug_on_start =
88 CommandLine::ForCurrentProcess()->HasSwitch(switches::kDebugChildren);
[email protected]df3c1ca12008-12-19 21:37:0189
90 base::file_handle_mapping_vector fds_to_map;
91 int src_fd;
92 int dest_fd;
93 channel->GetClientFileDescriptorMapping(&src_fd, &dest_fd);
94 if (src_fd > -1) {
95 fds_to_map.push_back(std::pair<int,int>(src_fd, dest_fd));
96 }
97
98 base::ProcessHandle ret = NULL;
99 switch (child_type) {
100 case TEST_CLIENT:
101 ret = MultiProcessTest::SpawnChild(L"RunTestClient",
102 fds_to_map,
103 debug_on_start);
104 channel->OnClientConnected();
105 break;
[email protected]526776c2009-02-07 00:39:26106 case TEST_DESCRIPTOR_CLIENT:
107 ret = MultiProcessTest::SpawnChild(L"RunTestDescriptorClient",
108 fds_to_map,
109 debug_on_start);
110 channel->OnClientConnected();
111 break;
[email protected]df3c1ca12008-12-19 21:37:01112 case TEST_REFLECTOR:
113 ret = MultiProcessTest::SpawnChild(L"RunReflector",
114 fds_to_map,
115 debug_on_start);
116 channel->OnClientConnected();
117 break;
118 case FUZZER_SERVER:
119 ret = MultiProcessTest::SpawnChild(L"RunFuzzServer",
120 fds_to_map,
121 debug_on_start);
122 channel->OnClientConnected();
123 break;
124 default:
125 return NULL;
126 break;
127 }
128 return ret;
129}
130#endif // defined(OS_POSIX)
[email protected]95cb7fb92008-12-09 22:00:47131
132TEST_F(IPCChannelTest, BasicMessageTest) {
initial.commit09911bf2008-07-26 23:55:29133 int v1 = 10;
134 std::string v2("foobar");
135 std::wstring v3(L"hello world");
136
137 IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
138 EXPECT_TRUE(m.WriteInt(v1));
139 EXPECT_TRUE(m.WriteString(v2));
140 EXPECT_TRUE(m.WriteWString(v3));
141
142 void* iter = NULL;
143
144 int vi;
145 std::string vs;
146 std::wstring vw;
147
148 EXPECT_TRUE(m.ReadInt(&iter, &vi));
149 EXPECT_EQ(v1, vi);
150
151 EXPECT_TRUE(m.ReadString(&iter, &vs));
152 EXPECT_EQ(v2, vs);
153
154 EXPECT_TRUE(m.ReadWString(&iter, &vw));
155 EXPECT_EQ(v3, vw);
156
157 // should fail
158 EXPECT_FALSE(m.ReadInt(&iter, &vi));
159 EXPECT_FALSE(m.ReadString(&iter, &vs));
160 EXPECT_FALSE(m.ReadWString(&iter, &vw));
161}
162
163static void Send(IPC::Message::Sender* sender, const char* text) {
164 static int message_index = 0;
165
166 IPC::Message* message = new IPC::Message(0,
167 2,
168 IPC::Message::PRIORITY_NORMAL);
169 message->WriteInt(message_index++);
170 message->WriteString(std::string(text));
171
[email protected]3d1b6662009-01-29 17:03:11172 // Make sure we can handle large messages.
initial.commit09911bf2008-07-26 23:55:29173 char junk[50000];
[email protected]3d1b6662009-01-29 17:03:11174 memset(junk, 'a', sizeof(junk)-1);
initial.commit09911bf2008-07-26 23:55:29175 junk[sizeof(junk)-1] = 0;
176 message->WriteString(std::string(junk));
177
178 // DEBUG: printf("[%u] sending message [%s]\n", GetCurrentProcessId(), text);
179 sender->Send(message);
180}
181
182class MyChannelListener : public IPC::Channel::Listener {
183 public:
184 virtual void OnMessageReceived(const IPC::Message& message) {
185 IPC::MessageIterator iter(message);
186
[email protected]d4651ff2008-12-02 16:51:58187 iter.NextInt();
initial.commit09911bf2008-07-26 23:55:29188 const std::string data = iter.NextString();
initial.commit09911bf2008-07-26 23:55:29189 if (--messages_left_ == 0) {
190 MessageLoop::current()->Quit();
191 } else {
192 Send(sender_, "Foo");
193 }
194 }
195
[email protected]b6be5882008-11-07 21:53:03196 virtual void OnChannelError() {
197 // There is a race when closing the channel so the last message may be lost.
198 EXPECT_LE(messages_left_, 1);
199 MessageLoop::current()->Quit();
200 }
201
initial.commit09911bf2008-07-26 23:55:29202 void Init(IPC::Message::Sender* s) {
203 sender_ = s;
204 messages_left_ = 50;
205 }
206
207 private:
208 IPC::Message::Sender* sender_;
209 int messages_left_;
210};
211static MyChannelListener channel_listener;
212
[email protected]95cb7fb92008-12-09 22:00:47213TEST_F(IPCChannelTest, ChannelTest) {
[email protected]3d1b6662009-01-29 17:03:11214 // Setup IPC channel.
initial.commit09911bf2008-07-26 23:55:29215 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
216 &channel_listener);
217 chan.Connect();
218
219 channel_listener.Init(&chan);
220
[email protected]df3c1ca12008-12-19 21:37:01221 base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, &chan);
initial.commit09911bf2008-07-26 23:55:29222 ASSERT_TRUE(process_handle);
223
224 Send(&chan, "hello from parent");
225
[email protected]3d1b6662009-01-29 17:03:11226 // Run message loop.
initial.commit09911bf2008-07-26 23:55:29227 MessageLoop::current()->Run();
228
[email protected]3d1b6662009-01-29 17:03:11229 // Close Channel so client gets its OnChannelError() callback fired.
230 chan.Close();
231
232 // Cleanup child process.
[email protected]95cb7fb92008-12-09 22:00:47233 EXPECT_TRUE(base::WaitForSingleProcess(process_handle, 5000));
initial.commit09911bf2008-07-26 23:55:29234}
235
[email protected]526776c2009-02-07 00:39:26236#if defined(OS_POSIX)
237
238class MyChannelDescriptorListener : public IPC::Channel::Listener {
239 public:
240 virtual void OnMessageReceived(const IPC::Message& message) {
241 void* iter = NULL;
242
243 FileDescriptor descriptor;
244
245 ASSERT_TRUE(
246 IPC::ParamTraits<FileDescriptor>::Read(&message, &iter, &descriptor));
247 VerifyDescriptor(&descriptor);
248 MessageLoop::current()->Quit();
249 }
250
251 virtual void OnChannelError() {
252 MessageLoop::current()->Quit();
253 }
254
255private:
256 static void VerifyDescriptor(FileDescriptor* descriptor) {
257 const int fd = open("/dev/null", O_RDONLY);
258 struct stat st1, st2;
259 fstat(fd, &st1);
260 close(fd);
261 fstat(descriptor->fd, &st2);
262 close(descriptor->fd);
263 ASSERT_EQ(st1.st_ino, st2.st_ino);
264 }
265};
266
267TEST_F(IPCChannelTest, DescriptorTest) {
268 // Setup IPC channel.
269 MyChannelDescriptorListener listener;
270
271 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
272 &listener);
273 chan.Connect();
274
275 base::ProcessHandle process_handle = SpawnChild(TEST_DESCRIPTOR_CLIENT,
276 &chan);
277 ASSERT_TRUE(process_handle);
278
279 FileDescriptor descriptor;
280 const int fd = open("/dev/null", O_RDONLY);
281 ASSERT_GE(fd, 0);
282 descriptor.auto_close = true;
283 descriptor.fd = fd;
284
285 IPC::Message* message = new IPC::Message(0, // routing_id
286 3, // message type
287 IPC::Message::PRIORITY_NORMAL);
288 IPC::ParamTraits<FileDescriptor>::Write(message, descriptor);
289 chan.Send(message);
290
291 // Run message loop.
292 MessageLoop::current()->Run();
293
294 // Close Channel so client gets its OnChannelError() callback fired.
295 chan.Close();
296
297 // Cleanup child process.
298 EXPECT_TRUE(base::WaitForSingleProcess(process_handle, 5000));
299}
300
301MULTIPROCESS_TEST_MAIN(RunTestDescriptorClient) {
302 MessageLoopForIO main_message_loop;
303 MyChannelDescriptorListener listener;
304
305 // setup IPC channel
306 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_CLIENT,
307 &listener);
308 chan.Connect();
309
310 // run message loop
311 MessageLoop::current()->Run();
312 // return true;
313 return NULL;
314}
315
316#endif // defined(OS_POSIX)
317
[email protected]95cb7fb92008-12-09 22:00:47318TEST_F(IPCChannelTest, ChannelProxyTest) {
initial.commit09911bf2008-07-26 23:55:29319 // The thread needs to out-live the ChannelProxy.
[email protected]ab820df2008-08-26 05:55:10320 base::Thread thread("ChannelProxyTestServer");
321 base::Thread::Options options;
322 options.message_loop_type = MessageLoop::TYPE_IO;
323 thread.StartWithOptions(options);
initial.commit09911bf2008-07-26 23:55:29324 {
325 // setup IPC channel proxy
326 IPC::ChannelProxy chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
327 &channel_listener, NULL, thread.message_loop());
328
329 channel_listener.Init(&chan);
330
[email protected]e74488c2008-12-22 22:43:41331#if defined(OS_WIN)
[email protected]bb975362009-01-21 01:00:22332 base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, NULL);
[email protected]e74488c2008-12-22 22:43:41333#elif defined(OS_POSIX)
[email protected]bb975362009-01-21 01:00:22334 bool debug_on_start = CommandLine::ForCurrentProcess()->HasSwitch(
335 switches::kDebugChildren);
[email protected]e74488c2008-12-22 22:43:41336 base::file_handle_mapping_vector fds_to_map;
337 int src_fd;
338 int dest_fd;
339 chan.GetClientFileDescriptorMapping(&src_fd, &dest_fd);
340 if (src_fd > -1) {
341 fds_to_map.push_back(std::pair<int,int>(src_fd, dest_fd));
342 }
343
[email protected]df3c1ca12008-12-19 21:37:01344 base::ProcessHandle process_handle = MultiProcessTest::SpawnChild(
345 L"RunTestClient",
[email protected]e74488c2008-12-22 22:43:41346 fds_to_map,
[email protected]df3c1ca12008-12-19 21:37:01347 debug_on_start);
[email protected]e74488c2008-12-22 22:43:41348 chan.OnClientConnected();
349#endif // defined(OS_POXIX)
350
initial.commit09911bf2008-07-26 23:55:29351 ASSERT_TRUE(process_handle);
352
353 Send(&chan, "hello from parent");
354
355 // run message loop
356 MessageLoop::current()->Run();
357
358 // cleanup child process
[email protected]df3c1ca12008-12-19 21:37:01359 EXPECT_TRUE(base::WaitForSingleProcess(process_handle, 5000));
initial.commit09911bf2008-07-26 23:55:29360 }
361 thread.Stop();
362}
363
[email protected]95cb7fb92008-12-09 22:00:47364MULTIPROCESS_TEST_MAIN(RunTestClient) {
365 MessageLoopForIO main_message_loop;
366
initial.commit09911bf2008-07-26 23:55:29367 // setup IPC channel
368 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_CLIENT,
369 &channel_listener);
370 chan.Connect();
371 channel_listener.Init(&chan);
372 Send(&chan, "hello from child");
373 // run message loop
374 MessageLoop::current()->Run();
[email protected]95cb7fb92008-12-09 22:00:47375 // return true;
376 return NULL;
initial.commit09911bf2008-07-26 23:55:29377}
[email protected]526776c2009-02-07 00:39:26378
initial.commit09911bf2008-07-26 23:55:29379#endif // !PERFORMANCE_TEST
380
381#ifdef PERFORMANCE_TEST
382
383//-----------------------------------------------------------------------------
384// Manually performance test
385//
386// This test times the roundtrip IPC message cycle. It is enabled with a
387// special preprocessor define to enable it instead of the standard IPC
388// unit tests. This works around some funny termination conditions in the
389// regular unit tests.
390//
391// This test is not automated. To test, you will want to vary the message
392// count and message size in TEST to get the numbers you want.
393//
394// FIXME(brettw): Automate this test and have it run by default.
395
396// This channel listener just replies to all messages with the exact same
397// message. It assumes each message has one string parameter. When the string
398// "quit" is sent, it will exit.
399class ChannelReflectorListener : public IPC::Channel::Listener {
400 public:
[email protected]95cb7fb92008-12-09 22:00:47401 explicit ChannelReflectorListener(IPC::Channel *channel) :
initial.commit09911bf2008-07-26 23:55:29402 channel_(channel),
403 count_messages_(0),
404 latency_messages_(0) {
405 std::cout << "Reflector up" << std::endl;
406 }
407
408 ~ChannelReflectorListener() {
409 std::cout << "Client Messages: " << count_messages_ << std::endl;
410 std::cout << "Client Latency: " << latency_messages_ << std::endl;
411 }
412
413 virtual void OnMessageReceived(const IPC::Message& message) {
414 count_messages_++;
415 IPC::MessageIterator iter(message);
416 int time = iter.NextInt();
417 int msgid = iter.NextInt();
418 std::string payload = iter.NextString();
419 latency_messages_ += GetTickCount() - time;
420
421 // cout << "reflector msg received: " << msgid << endl;
422 if (payload == "quit")
423 MessageLoop::current()->Quit();
424
425 IPC::Message* msg = new IPC::Message(0,
426 2,
427 IPC::Message::PRIORITY_NORMAL);
428 msg->WriteInt(GetTickCount());
429 msg->WriteInt(msgid);
430 msg->WriteString(payload);
431 channel_->Send(msg);
432 }
433 private:
434 IPC::Channel *channel_;
435 int count_messages_;
436 int latency_messages_;
437};
438
439class ChannelPerfListener : public IPC::Channel::Listener {
440 public:
441 ChannelPerfListener(IPC::Channel* channel, int msg_count, int msg_size) :
442 count_down_(msg_count),
443 channel_(channel),
444 count_messages_(0),
445 latency_messages_(0) {
446 payload_.resize(msg_size);
447 for (int i = 0; i < static_cast<int>(payload_.size()); i++)
448 payload_[i] = 'a';
449 std::cout << "perflistener up" << std::endl;
450 }
451
452 ~ChannelPerfListener() {
453 std::cout << "Server Messages: " << count_messages_ << std::endl;
454 std::cout << "Server Latency: " << latency_messages_ << std::endl;
455 }
456
457 virtual void OnMessageReceived(const IPC::Message& message) {
458 count_messages_++;
459 // decode the string so this gets counted in the total time
460 IPC::MessageIterator iter(message);
461 int time = iter.NextInt();
462 int msgid = iter.NextInt();
463 std::string cur = iter.NextString();
464 latency_messages_ += GetTickCount() - time;
465
466 // cout << "perflistener got message" << endl;
467
468 count_down_--;
469 if (count_down_ == 0) {
470 IPC::Message* msg = new IPC::Message(0,
471 2,
472 IPC::Message::PRIORITY_NORMAL);
473 msg->WriteInt(GetTickCount());
474 msg->WriteInt(count_down_);
475 msg->WriteString("quit");
476 channel_->Send(msg);
477 SetTimer(NULL, 1, 250, (TIMERPROC) PostQuitMessage);
478 return;
479 }
480
481 IPC::Message* msg = new IPC::Message(0,
482 2,
483 IPC::Message::PRIORITY_NORMAL);
484 msg->WriteInt(GetTickCount());
485 msg->WriteInt(count_down_);
486 msg->WriteString(payload_);
487 channel_->Send(msg);
488 }
489
490 private:
491 int count_down_;
492 std::string payload_;
493 IPC::Channel *channel_;
494 int count_messages_;
495 int latency_messages_;
496};
497
[email protected]95cb7fb92008-12-09 22:00:47498TEST_F(IPCChannelTest, Performance) {
initial.commit09911bf2008-07-26 23:55:29499 // setup IPC channel
500 IPC::Channel chan(kReflectorChannel, IPC::Channel::MODE_SERVER, NULL);
501 ChannelPerfListener perf_listener(&chan, 10000, 100000);
502 chan.set_listener(&perf_listener);
503 chan.Connect();
504
[email protected]df3c1ca12008-12-19 21:37:01505 HANDLE process = SpawnChild(TEST_REFLECTOR, &chan);
initial.commit09911bf2008-07-26 23:55:29506 ASSERT_TRUE(process);
507
508 Sleep(1000);
509
510 PerfTimeLogger logger("IPC_Perf");
511
512 // this initial message will kick-start the ping-pong of messages
513 IPC::Message* message = new IPC::Message(0,
514 2,
515 IPC::Message::PRIORITY_NORMAL);
516 message->WriteInt(GetTickCount());
517 message->WriteInt(-1);
518 message->WriteString("Hello");
519 chan.Send(message);
520
521 // run message loop
522 MessageLoop::current()->Run();
523
524 // cleanup child process
525 WaitForSingleObject(process, 5000);
526 CloseHandle(process);
527}
528
529// This message loop bounces all messages back to the sender
[email protected]95cb7fb92008-12-09 22:00:47530MULTIPROCESS_TEST_MAIN(RunReflector) {
531 MessageLoopForIO main_message_loop;
initial.commit09911bf2008-07-26 23:55:29532 IPC::Channel chan(kReflectorChannel, IPC::Channel::MODE_CLIENT, NULL);
533 ChannelReflectorListener channel_reflector_listener(&chan);
534 chan.set_listener(&channel_reflector_listener);
535 chan.Connect();
536
537 MessageLoop::current()->Run();
538 return true;
539}
540
541#endif // PERFORMANCE_TEST
542
initial.commit09911bf2008-07-26 23:55:29543int main(int argc, char** argv) {
[email protected]95cb7fb92008-12-09 22:00:47544#ifdef PERFORMANCE_TEST
[email protected]302831b2009-01-13 22:35:10545 int retval = PerfTestSuite(argc, argv).Run();
546#else
547 int retval = TestSuite(argc, argv).Run();
initial.commit09911bf2008-07-26 23:55:29548#endif
[email protected]95cb7fb92008-12-09 22:00:47549 return retval;
initial.commit09911bf2008-07-26 23:55:29550}