blob: b0add18d98fffc5dcc6ffd52e0a96a9cf5e08fc3 [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
156 // make sure we can handle large messages
157 char junk[50000];
158 junk[sizeof(junk)-1] = 0;
159 message->WriteString(std::string(junk));
160
161 // DEBUG: printf("[%u] sending message [%s]\n", GetCurrentProcessId(), text);
162 sender->Send(message);
163}
164
165class MyChannelListener : public IPC::Channel::Listener {
166 public:
167 virtual void OnMessageReceived(const IPC::Message& message) {
168 IPC::MessageIterator iter(message);
169
[email protected]d4651ff2008-12-02 16:51:58170 iter.NextInt();
initial.commit09911bf2008-07-26 23:55:29171 const std::string data = iter.NextString();
initial.commit09911bf2008-07-26 23:55:29172 if (--messages_left_ == 0) {
173 MessageLoop::current()->Quit();
174 } else {
175 Send(sender_, "Foo");
176 }
177 }
178
[email protected]b6be5882008-11-07 21:53:03179 virtual void OnChannelError() {
180 // There is a race when closing the channel so the last message may be lost.
181 EXPECT_LE(messages_left_, 1);
182 MessageLoop::current()->Quit();
183 }
184
initial.commit09911bf2008-07-26 23:55:29185 void Init(IPC::Message::Sender* s) {
186 sender_ = s;
187 messages_left_ = 50;
188 }
189
190 private:
191 IPC::Message::Sender* sender_;
192 int messages_left_;
193};
194static MyChannelListener channel_listener;
195
[email protected]95cb7fb92008-12-09 22:00:47196TEST_F(IPCChannelTest, ChannelTest) {
initial.commit09911bf2008-07-26 23:55:29197 // setup IPC channel
198 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
199 &channel_listener);
200 chan.Connect();
201
202 channel_listener.Init(&chan);
203
[email protected]df3c1ca12008-12-19 21:37:01204 base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, &chan);
initial.commit09911bf2008-07-26 23:55:29205 ASSERT_TRUE(process_handle);
206
207 Send(&chan, "hello from parent");
208
209 // run message loop
210 MessageLoop::current()->Run();
211
212 // cleanup child process
[email protected]95cb7fb92008-12-09 22:00:47213 EXPECT_TRUE(base::WaitForSingleProcess(process_handle, 5000));
initial.commit09911bf2008-07-26 23:55:29214}
215
[email protected]95cb7fb92008-12-09 22:00:47216TEST_F(IPCChannelTest, ChannelProxyTest) {
initial.commit09911bf2008-07-26 23:55:29217 // The thread needs to out-live the ChannelProxy.
[email protected]ab820df2008-08-26 05:55:10218 base::Thread thread("ChannelProxyTestServer");
219 base::Thread::Options options;
220 options.message_loop_type = MessageLoop::TYPE_IO;
221 thread.StartWithOptions(options);
initial.commit09911bf2008-07-26 23:55:29222 {
223 // setup IPC channel proxy
224 IPC::ChannelProxy chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
225 &channel_listener, NULL, thread.message_loop());
226
227 channel_listener.Init(&chan);
228
[email protected]e74488c2008-12-22 22:43:41229#if defined(OS_WIN)
[email protected]bb975362009-01-21 01:00:22230 base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, NULL);
[email protected]e74488c2008-12-22 22:43:41231#elif defined(OS_POSIX)
[email protected]bb975362009-01-21 01:00:22232 bool debug_on_start = CommandLine::ForCurrentProcess()->HasSwitch(
233 switches::kDebugChildren);
[email protected]e74488c2008-12-22 22:43:41234 base::file_handle_mapping_vector fds_to_map;
235 int src_fd;
236 int dest_fd;
237 chan.GetClientFileDescriptorMapping(&src_fd, &dest_fd);
238 if (src_fd > -1) {
239 fds_to_map.push_back(std::pair<int,int>(src_fd, dest_fd));
240 }
241
[email protected]df3c1ca12008-12-19 21:37:01242 base::ProcessHandle process_handle = MultiProcessTest::SpawnChild(
243 L"RunTestClient",
[email protected]e74488c2008-12-22 22:43:41244 fds_to_map,
[email protected]df3c1ca12008-12-19 21:37:01245 debug_on_start);
[email protected]e74488c2008-12-22 22:43:41246 chan.OnClientConnected();
247#endif // defined(OS_POXIX)
248
initial.commit09911bf2008-07-26 23:55:29249 ASSERT_TRUE(process_handle);
250
251 Send(&chan, "hello from parent");
252
253 // run message loop
254 MessageLoop::current()->Run();
255
256 // cleanup child process
[email protected]df3c1ca12008-12-19 21:37:01257 EXPECT_TRUE(base::WaitForSingleProcess(process_handle, 5000));
initial.commit09911bf2008-07-26 23:55:29258 }
259 thread.Stop();
260}
261
[email protected]95cb7fb92008-12-09 22:00:47262MULTIPROCESS_TEST_MAIN(RunTestClient) {
263 MessageLoopForIO main_message_loop;
264
initial.commit09911bf2008-07-26 23:55:29265 // setup IPC channel
266 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_CLIENT,
267 &channel_listener);
268 chan.Connect();
269 channel_listener.Init(&chan);
270 Send(&chan, "hello from child");
271 // run message loop
272 MessageLoop::current()->Run();
[email protected]95cb7fb92008-12-09 22:00:47273 // return true;
274 return NULL;
initial.commit09911bf2008-07-26 23:55:29275}
initial.commit09911bf2008-07-26 23:55:29276#endif // !PERFORMANCE_TEST
277
278#ifdef PERFORMANCE_TEST
279
280//-----------------------------------------------------------------------------
281// Manually performance test
282//
283// This test times the roundtrip IPC message cycle. It is enabled with a
284// special preprocessor define to enable it instead of the standard IPC
285// unit tests. This works around some funny termination conditions in the
286// regular unit tests.
287//
288// This test is not automated. To test, you will want to vary the message
289// count and message size in TEST to get the numbers you want.
290//
291// FIXME(brettw): Automate this test and have it run by default.
292
293// This channel listener just replies to all messages with the exact same
294// message. It assumes each message has one string parameter. When the string
295// "quit" is sent, it will exit.
296class ChannelReflectorListener : public IPC::Channel::Listener {
297 public:
[email protected]95cb7fb92008-12-09 22:00:47298 explicit ChannelReflectorListener(IPC::Channel *channel) :
initial.commit09911bf2008-07-26 23:55:29299 channel_(channel),
300 count_messages_(0),
301 latency_messages_(0) {
302 std::cout << "Reflector up" << std::endl;
303 }
304
305 ~ChannelReflectorListener() {
306 std::cout << "Client Messages: " << count_messages_ << std::endl;
307 std::cout << "Client Latency: " << latency_messages_ << std::endl;
308 }
309
310 virtual void OnMessageReceived(const IPC::Message& message) {
311 count_messages_++;
312 IPC::MessageIterator iter(message);
313 int time = iter.NextInt();
314 int msgid = iter.NextInt();
315 std::string payload = iter.NextString();
316 latency_messages_ += GetTickCount() - time;
317
318 // cout << "reflector msg received: " << msgid << endl;
319 if (payload == "quit")
320 MessageLoop::current()->Quit();
321
322 IPC::Message* msg = new IPC::Message(0,
323 2,
324 IPC::Message::PRIORITY_NORMAL);
325 msg->WriteInt(GetTickCount());
326 msg->WriteInt(msgid);
327 msg->WriteString(payload);
328 channel_->Send(msg);
329 }
330 private:
331 IPC::Channel *channel_;
332 int count_messages_;
333 int latency_messages_;
334};
335
336class ChannelPerfListener : public IPC::Channel::Listener {
337 public:
338 ChannelPerfListener(IPC::Channel* channel, int msg_count, int msg_size) :
339 count_down_(msg_count),
340 channel_(channel),
341 count_messages_(0),
342 latency_messages_(0) {
343 payload_.resize(msg_size);
344 for (int i = 0; i < static_cast<int>(payload_.size()); i++)
345 payload_[i] = 'a';
346 std::cout << "perflistener up" << std::endl;
347 }
348
349 ~ChannelPerfListener() {
350 std::cout << "Server Messages: " << count_messages_ << std::endl;
351 std::cout << "Server Latency: " << latency_messages_ << std::endl;
352 }
353
354 virtual void OnMessageReceived(const IPC::Message& message) {
355 count_messages_++;
356 // decode the string so this gets counted in the total time
357 IPC::MessageIterator iter(message);
358 int time = iter.NextInt();
359 int msgid = iter.NextInt();
360 std::string cur = iter.NextString();
361 latency_messages_ += GetTickCount() - time;
362
363 // cout << "perflistener got message" << endl;
364
365 count_down_--;
366 if (count_down_ == 0) {
367 IPC::Message* msg = new IPC::Message(0,
368 2,
369 IPC::Message::PRIORITY_NORMAL);
370 msg->WriteInt(GetTickCount());
371 msg->WriteInt(count_down_);
372 msg->WriteString("quit");
373 channel_->Send(msg);
374 SetTimer(NULL, 1, 250, (TIMERPROC) PostQuitMessage);
375 return;
376 }
377
378 IPC::Message* msg = new IPC::Message(0,
379 2,
380 IPC::Message::PRIORITY_NORMAL);
381 msg->WriteInt(GetTickCount());
382 msg->WriteInt(count_down_);
383 msg->WriteString(payload_);
384 channel_->Send(msg);
385 }
386
387 private:
388 int count_down_;
389 std::string payload_;
390 IPC::Channel *channel_;
391 int count_messages_;
392 int latency_messages_;
393};
394
[email protected]95cb7fb92008-12-09 22:00:47395TEST_F(IPCChannelTest, Performance) {
initial.commit09911bf2008-07-26 23:55:29396 // setup IPC channel
397 IPC::Channel chan(kReflectorChannel, IPC::Channel::MODE_SERVER, NULL);
398 ChannelPerfListener perf_listener(&chan, 10000, 100000);
399 chan.set_listener(&perf_listener);
400 chan.Connect();
401
[email protected]df3c1ca12008-12-19 21:37:01402 HANDLE process = SpawnChild(TEST_REFLECTOR, &chan);
initial.commit09911bf2008-07-26 23:55:29403 ASSERT_TRUE(process);
404
405 Sleep(1000);
406
407 PerfTimeLogger logger("IPC_Perf");
408
409 // this initial message will kick-start the ping-pong of messages
410 IPC::Message* message = new IPC::Message(0,
411 2,
412 IPC::Message::PRIORITY_NORMAL);
413 message->WriteInt(GetTickCount());
414 message->WriteInt(-1);
415 message->WriteString("Hello");
416 chan.Send(message);
417
418 // run message loop
419 MessageLoop::current()->Run();
420
421 // cleanup child process
422 WaitForSingleObject(process, 5000);
423 CloseHandle(process);
424}
425
426// This message loop bounces all messages back to the sender
[email protected]95cb7fb92008-12-09 22:00:47427MULTIPROCESS_TEST_MAIN(RunReflector) {
428 MessageLoopForIO main_message_loop;
initial.commit09911bf2008-07-26 23:55:29429 IPC::Channel chan(kReflectorChannel, IPC::Channel::MODE_CLIENT, NULL);
430 ChannelReflectorListener channel_reflector_listener(&chan);
431 chan.set_listener(&channel_reflector_listener);
432 chan.Connect();
433
434 MessageLoop::current()->Run();
435 return true;
436}
437
438#endif // PERFORMANCE_TEST
439
initial.commit09911bf2008-07-26 23:55:29440int main(int argc, char** argv) {
[email protected]95cb7fb92008-12-09 22:00:47441#ifdef PERFORMANCE_TEST
[email protected]302831b2009-01-13 22:35:10442 int retval = PerfTestSuite(argc, argv).Run();
443#else
444 int retval = TestSuite(argc, argv).Run();
initial.commit09911bf2008-07-26 23:55:29445#endif
[email protected]95cb7fb92008-12-09 22:00:47446 return retval;
initial.commit09911bf2008-07-26 23:55:29447}