blob: 695f0b4d0c19722a601dead50b0a280ed5259bfd [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]d4651ff2008-12-02 16:51:585#if defined(OS_WIN)
initial.commit09911bf2008-07-26 23:55:296#include <windows.h>
[email protected]d4651ff2008-12-02 16:51:587#endif
initial.commit09911bf2008-07-26 23:55:298#include <stdio.h>
9#include <iostream>
10#include <string>
11
12#include "chrome/common/ipc_tests.h"
13
[email protected]ae6454712008-08-01 03:06:2514#include "base/at_exit.h"
initial.commit09911bf2008-07-26 23:55:2915#include "base/base_switches.h"
16#include "base/command_line.h"
17#include "base/debug_on_start.h"
18#include "base/perftimer.h"
[email protected]302831b2009-01-13 22:35:1019#include "base/perf_test_suite.h"
[email protected]95cb7fb92008-12-09 22:00:4720#include "base/test_suite.h"
initial.commit09911bf2008-07-26 23:55:2921#include "base/thread.h"
22#include "chrome/common/chrome_switches.h"
23#include "chrome/common/ipc_channel.h"
24#include "chrome/common/ipc_channel_proxy.h"
25#include "chrome/common/ipc_message_utils.h"
[email protected]95cb7fb92008-12-09 22:00:4726#include "testing/multiprocess_func_list.h"
initial.commit09911bf2008-07-26 23:55:2927
28// Define to enable IPC performance testing instead of the regular unit tests
29// #define PERFORMANCE_TEST
30
31const wchar_t kTestClientChannel[] = L"T1";
32const wchar_t kReflectorChannel[] = L"T2";
33const wchar_t kFuzzerChannel[] = L"F3";
34
initial.commit09911bf2008-07-26 23:55:2935#ifndef PERFORMANCE_TEST
36
[email protected]95cb7fb92008-12-09 22:00:4737void IPCChannelTest::SetUp() {
38 MultiProcessTest::SetUp();
39
40 // Construct a fresh IO Message loop for the duration of each test.
41 message_loop_ = new MessageLoopForIO();
42}
43
44void IPCChannelTest::TearDown() {
45 delete message_loop_;
46 message_loop_ = NULL;
47
48 MultiProcessTest::TearDown();
49}
50
[email protected]df3c1ca12008-12-19 21:37:0151#if defined(OS_WIN)
52base::ProcessHandle IPCChannelTest::SpawnChild(ChildType child_type,
53 IPC::Channel *channel) {
[email protected]95cb7fb92008-12-09 22:00:4754 // kDebugChildren support.
[email protected]bb975362009-01-21 01:00:2255 bool debug_on_start =
56 CommandLine::ForCurrentProcess()->HasSwitch(switches::kDebugChildren);
[email protected]95cb7fb92008-12-09 22:00:4757
58 switch (child_type) {
59 case TEST_CLIENT:
60 return MultiProcessTest::SpawnChild(L"RunTestClient", debug_on_start);
61 break;
62 case TEST_REFLECTOR:
63 return MultiProcessTest::SpawnChild(L"RunReflector", debug_on_start);
64 break;
65 case FUZZER_SERVER:
66 return MultiProcessTest::SpawnChild(L"RunFuzzServer", debug_on_start);
67 break;
68 default:
69 return NULL;
70 break;
71 }
72}
[email protected]df3c1ca12008-12-19 21:37:0173#elif defined(OS_POSIX)
74base::ProcessHandle IPCChannelTest::SpawnChild(ChildType child_type,
75 IPC::Channel *channel) {
76 // kDebugChildren support.
[email protected]bb975362009-01-21 01:00:2277 bool debug_on_start =
78 CommandLine::ForCurrentProcess()->HasSwitch(switches::kDebugChildren);
[email protected]df3c1ca12008-12-19 21:37:0179
80 base::file_handle_mapping_vector fds_to_map;
81 int src_fd;
82 int dest_fd;
83 channel->GetClientFileDescriptorMapping(&src_fd, &dest_fd);
84 if (src_fd > -1) {
85 fds_to_map.push_back(std::pair<int,int>(src_fd, dest_fd));
86 }
87
88 base::ProcessHandle ret = NULL;
89 switch (child_type) {
90 case TEST_CLIENT:
91 ret = MultiProcessTest::SpawnChild(L"RunTestClient",
92 fds_to_map,
93 debug_on_start);
94 channel->OnClientConnected();
95 break;
96 case TEST_REFLECTOR:
97 ret = MultiProcessTest::SpawnChild(L"RunReflector",
98 fds_to_map,
99 debug_on_start);
100 channel->OnClientConnected();
101 break;
102 case FUZZER_SERVER:
103 ret = MultiProcessTest::SpawnChild(L"RunFuzzServer",
104 fds_to_map,
105 debug_on_start);
106 channel->OnClientConnected();
107 break;
108 default:
109 return NULL;
110 break;
111 }
112 return ret;
113}
114#endif // defined(OS_POSIX)
[email protected]95cb7fb92008-12-09 22:00:47115
116TEST_F(IPCChannelTest, BasicMessageTest) {
initial.commit09911bf2008-07-26 23:55:29117 int v1 = 10;
118 std::string v2("foobar");
119 std::wstring v3(L"hello world");
120
121 IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
122 EXPECT_TRUE(m.WriteInt(v1));
123 EXPECT_TRUE(m.WriteString(v2));
124 EXPECT_TRUE(m.WriteWString(v3));
125
126 void* iter = NULL;
127
128 int vi;
129 std::string vs;
130 std::wstring vw;
131
132 EXPECT_TRUE(m.ReadInt(&iter, &vi));
133 EXPECT_EQ(v1, vi);
134
135 EXPECT_TRUE(m.ReadString(&iter, &vs));
136 EXPECT_EQ(v2, vs);
137
138 EXPECT_TRUE(m.ReadWString(&iter, &vw));
139 EXPECT_EQ(v3, vw);
140
141 // should fail
142 EXPECT_FALSE(m.ReadInt(&iter, &vi));
143 EXPECT_FALSE(m.ReadString(&iter, &vs));
144 EXPECT_FALSE(m.ReadWString(&iter, &vw));
145}
146
147static void Send(IPC::Message::Sender* sender, const char* text) {
148 static int message_index = 0;
149
150 IPC::Message* message = new IPC::Message(0,
151 2,
152 IPC::Message::PRIORITY_NORMAL);
153 message->WriteInt(message_index++);
154 message->WriteString(std::string(text));
155
[email protected]3d1b6662009-01-29 17:03:11156 // Make sure we can handle large messages.
initial.commit09911bf2008-07-26 23:55:29157 char junk[50000];
[email protected]3d1b6662009-01-29 17:03:11158 memset(junk, 'a', sizeof(junk)-1);
initial.commit09911bf2008-07-26 23:55:29159 junk[sizeof(junk)-1] = 0;
160 message->WriteString(std::string(junk));
161
162 // DEBUG: printf("[%u] sending message [%s]\n", GetCurrentProcessId(), text);
163 sender->Send(message);
164}
165
166class MyChannelListener : public IPC::Channel::Listener {
167 public:
168 virtual void OnMessageReceived(const IPC::Message& message) {
169 IPC::MessageIterator iter(message);
170
[email protected]d4651ff2008-12-02 16:51:58171 iter.NextInt();
initial.commit09911bf2008-07-26 23:55:29172 const std::string data = iter.NextString();
initial.commit09911bf2008-07-26 23:55:29173 if (--messages_left_ == 0) {
174 MessageLoop::current()->Quit();
175 } else {
176 Send(sender_, "Foo");
177 }
178 }
179
[email protected]b6be5882008-11-07 21:53:03180 virtual void OnChannelError() {
181 // There is a race when closing the channel so the last message may be lost.
182 EXPECT_LE(messages_left_, 1);
183 MessageLoop::current()->Quit();
184 }
185
initial.commit09911bf2008-07-26 23:55:29186 void Init(IPC::Message::Sender* s) {
187 sender_ = s;
188 messages_left_ = 50;
189 }
190
191 private:
192 IPC::Message::Sender* sender_;
193 int messages_left_;
194};
195static MyChannelListener channel_listener;
196
[email protected]95cb7fb92008-12-09 22:00:47197TEST_F(IPCChannelTest, ChannelTest) {
[email protected]3d1b6662009-01-29 17:03:11198 // Setup IPC channel.
initial.commit09911bf2008-07-26 23:55:29199 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
200 &channel_listener);
201 chan.Connect();
202
203 channel_listener.Init(&chan);
204
[email protected]df3c1ca12008-12-19 21:37:01205 base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, &chan);
initial.commit09911bf2008-07-26 23:55:29206 ASSERT_TRUE(process_handle);
207
208 Send(&chan, "hello from parent");
209
[email protected]3d1b6662009-01-29 17:03:11210 // Run message loop.
initial.commit09911bf2008-07-26 23:55:29211 MessageLoop::current()->Run();
212
[email protected]3d1b6662009-01-29 17:03:11213 // Close Channel so client gets its OnChannelError() callback fired.
214 chan.Close();
215
216 // Cleanup child process.
[email protected]95cb7fb92008-12-09 22:00:47217 EXPECT_TRUE(base::WaitForSingleProcess(process_handle, 5000));
initial.commit09911bf2008-07-26 23:55:29218}
219
[email protected]95cb7fb92008-12-09 22:00:47220TEST_F(IPCChannelTest, ChannelProxyTest) {
initial.commit09911bf2008-07-26 23:55:29221 // The thread needs to out-live the ChannelProxy.
[email protected]ab820df2008-08-26 05:55:10222 base::Thread thread("ChannelProxyTestServer");
223 base::Thread::Options options;
224 options.message_loop_type = MessageLoop::TYPE_IO;
225 thread.StartWithOptions(options);
initial.commit09911bf2008-07-26 23:55:29226 {
227 // setup IPC channel proxy
228 IPC::ChannelProxy chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
229 &channel_listener, NULL, thread.message_loop());
230
231 channel_listener.Init(&chan);
232
[email protected]e74488c2008-12-22 22:43:41233#if defined(OS_WIN)
[email protected]bb975362009-01-21 01:00:22234 base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, NULL);
[email protected]e74488c2008-12-22 22:43:41235#elif defined(OS_POSIX)
[email protected]bb975362009-01-21 01:00:22236 bool debug_on_start = CommandLine::ForCurrentProcess()->HasSwitch(
237 switches::kDebugChildren);
[email protected]e74488c2008-12-22 22:43:41238 base::file_handle_mapping_vector fds_to_map;
239 int src_fd;
240 int dest_fd;
241 chan.GetClientFileDescriptorMapping(&src_fd, &dest_fd);
242 if (src_fd > -1) {
243 fds_to_map.push_back(std::pair<int,int>(src_fd, dest_fd));
244 }
245
[email protected]df3c1ca12008-12-19 21:37:01246 base::ProcessHandle process_handle = MultiProcessTest::SpawnChild(
247 L"RunTestClient",
[email protected]e74488c2008-12-22 22:43:41248 fds_to_map,
[email protected]df3c1ca12008-12-19 21:37:01249 debug_on_start);
[email protected]e74488c2008-12-22 22:43:41250 chan.OnClientConnected();
251#endif // defined(OS_POXIX)
252
initial.commit09911bf2008-07-26 23:55:29253 ASSERT_TRUE(process_handle);
254
255 Send(&chan, "hello from parent");
256
257 // run message loop
258 MessageLoop::current()->Run();
259
260 // cleanup child process
[email protected]df3c1ca12008-12-19 21:37:01261 EXPECT_TRUE(base::WaitForSingleProcess(process_handle, 5000));
initial.commit09911bf2008-07-26 23:55:29262 }
263 thread.Stop();
264}
265
[email protected]95cb7fb92008-12-09 22:00:47266MULTIPROCESS_TEST_MAIN(RunTestClient) {
267 MessageLoopForIO main_message_loop;
268
initial.commit09911bf2008-07-26 23:55:29269 // setup IPC channel
270 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_CLIENT,
271 &channel_listener);
272 chan.Connect();
273 channel_listener.Init(&chan);
274 Send(&chan, "hello from child");
275 // run message loop
276 MessageLoop::current()->Run();
[email protected]95cb7fb92008-12-09 22:00:47277 // return true;
278 return NULL;
initial.commit09911bf2008-07-26 23:55:29279}
initial.commit09911bf2008-07-26 23:55:29280#endif // !PERFORMANCE_TEST
281
282#ifdef PERFORMANCE_TEST
283
284//-----------------------------------------------------------------------------
285// Manually performance test
286//
287// This test times the roundtrip IPC message cycle. It is enabled with a
288// special preprocessor define to enable it instead of the standard IPC
289// unit tests. This works around some funny termination conditions in the
290// regular unit tests.
291//
292// This test is not automated. To test, you will want to vary the message
293// count and message size in TEST to get the numbers you want.
294//
295// FIXME(brettw): Automate this test and have it run by default.
296
297// This channel listener just replies to all messages with the exact same
298// message. It assumes each message has one string parameter. When the string
299// "quit" is sent, it will exit.
300class ChannelReflectorListener : public IPC::Channel::Listener {
301 public:
[email protected]95cb7fb92008-12-09 22:00:47302 explicit ChannelReflectorListener(IPC::Channel *channel) :
initial.commit09911bf2008-07-26 23:55:29303 channel_(channel),
304 count_messages_(0),
305 latency_messages_(0) {
306 std::cout << "Reflector up" << std::endl;
307 }
308
309 ~ChannelReflectorListener() {
310 std::cout << "Client Messages: " << count_messages_ << std::endl;
311 std::cout << "Client Latency: " << latency_messages_ << std::endl;
312 }
313
314 virtual void OnMessageReceived(const IPC::Message& message) {
315 count_messages_++;
316 IPC::MessageIterator iter(message);
317 int time = iter.NextInt();
318 int msgid = iter.NextInt();
319 std::string payload = iter.NextString();
320 latency_messages_ += GetTickCount() - time;
321
322 // cout << "reflector msg received: " << msgid << endl;
323 if (payload == "quit")
324 MessageLoop::current()->Quit();
325
326 IPC::Message* msg = new IPC::Message(0,
327 2,
328 IPC::Message::PRIORITY_NORMAL);
329 msg->WriteInt(GetTickCount());
330 msg->WriteInt(msgid);
331 msg->WriteString(payload);
332 channel_->Send(msg);
333 }
334 private:
335 IPC::Channel *channel_;
336 int count_messages_;
337 int latency_messages_;
338};
339
340class ChannelPerfListener : public IPC::Channel::Listener {
341 public:
342 ChannelPerfListener(IPC::Channel* channel, int msg_count, int msg_size) :
343 count_down_(msg_count),
344 channel_(channel),
345 count_messages_(0),
346 latency_messages_(0) {
347 payload_.resize(msg_size);
348 for (int i = 0; i < static_cast<int>(payload_.size()); i++)
349 payload_[i] = 'a';
350 std::cout << "perflistener up" << std::endl;
351 }
352
353 ~ChannelPerfListener() {
354 std::cout << "Server Messages: " << count_messages_ << std::endl;
355 std::cout << "Server Latency: " << latency_messages_ << std::endl;
356 }
357
358 virtual void OnMessageReceived(const IPC::Message& message) {
359 count_messages_++;
360 // decode the string so this gets counted in the total time
361 IPC::MessageIterator iter(message);
362 int time = iter.NextInt();
363 int msgid = iter.NextInt();
364 std::string cur = iter.NextString();
365 latency_messages_ += GetTickCount() - time;
366
367 // cout << "perflistener got message" << endl;
368
369 count_down_--;
370 if (count_down_ == 0) {
371 IPC::Message* msg = new IPC::Message(0,
372 2,
373 IPC::Message::PRIORITY_NORMAL);
374 msg->WriteInt(GetTickCount());
375 msg->WriteInt(count_down_);
376 msg->WriteString("quit");
377 channel_->Send(msg);
378 SetTimer(NULL, 1, 250, (TIMERPROC) PostQuitMessage);
379 return;
380 }
381
382 IPC::Message* msg = new IPC::Message(0,
383 2,
384 IPC::Message::PRIORITY_NORMAL);
385 msg->WriteInt(GetTickCount());
386 msg->WriteInt(count_down_);
387 msg->WriteString(payload_);
388 channel_->Send(msg);
389 }
390
391 private:
392 int count_down_;
393 std::string payload_;
394 IPC::Channel *channel_;
395 int count_messages_;
396 int latency_messages_;
397};
398
[email protected]95cb7fb92008-12-09 22:00:47399TEST_F(IPCChannelTest, Performance) {
initial.commit09911bf2008-07-26 23:55:29400 // setup IPC channel
401 IPC::Channel chan(kReflectorChannel, IPC::Channel::MODE_SERVER, NULL);
402 ChannelPerfListener perf_listener(&chan, 10000, 100000);
403 chan.set_listener(&perf_listener);
404 chan.Connect();
405
[email protected]df3c1ca12008-12-19 21:37:01406 HANDLE process = SpawnChild(TEST_REFLECTOR, &chan);
initial.commit09911bf2008-07-26 23:55:29407 ASSERT_TRUE(process);
408
409 Sleep(1000);
410
411 PerfTimeLogger logger("IPC_Perf");
412
413 // this initial message will kick-start the ping-pong of messages
414 IPC::Message* message = new IPC::Message(0,
415 2,
416 IPC::Message::PRIORITY_NORMAL);
417 message->WriteInt(GetTickCount());
418 message->WriteInt(-1);
419 message->WriteString("Hello");
420 chan.Send(message);
421
422 // run message loop
423 MessageLoop::current()->Run();
424
425 // cleanup child process
426 WaitForSingleObject(process, 5000);
427 CloseHandle(process);
428}
429
430// This message loop bounces all messages back to the sender
[email protected]95cb7fb92008-12-09 22:00:47431MULTIPROCESS_TEST_MAIN(RunReflector) {
432 MessageLoopForIO main_message_loop;
initial.commit09911bf2008-07-26 23:55:29433 IPC::Channel chan(kReflectorChannel, IPC::Channel::MODE_CLIENT, NULL);
434 ChannelReflectorListener channel_reflector_listener(&chan);
435 chan.set_listener(&channel_reflector_listener);
436 chan.Connect();
437
438 MessageLoop::current()->Run();
439 return true;
440}
441
442#endif // PERFORMANCE_TEST
443
initial.commit09911bf2008-07-26 23:55:29444int main(int argc, char** argv) {
[email protected]95cb7fb92008-12-09 22:00:47445#ifdef PERFORMANCE_TEST
[email protected]302831b2009-01-13 22:35:10446 int retval = PerfTestSuite(argc, argv).Run();
447#else
448 int retval = TestSuite(argc, argv).Run();
initial.commit09911bf2008-07-26 23:55:29449#endif
[email protected]95cb7fb92008-12-09 22:00:47450 return retval;
initial.commit09911bf2008-07-26 23:55:29451}