blob: 444824ea66f88c8aef14ab1d2870b98c4458fed3 [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"
19#include "base/process_util.h"
[email protected]d4651ff2008-12-02 16:51:5820#include "base/scoped_nsautorelease_pool.h"
[email protected]95cb7fb92008-12-09 22:00:4721#include "base/test_suite.h"
initial.commit09911bf2008-07-26 23:55:2922#include "base/thread.h"
23#include "chrome/common/chrome_switches.h"
24#include "chrome/common/ipc_channel.h"
25#include "chrome/common/ipc_channel_proxy.h"
26#include "chrome/common/ipc_message_utils.h"
[email protected]95cb7fb92008-12-09 22:00:4727#include "testing/multiprocess_func_list.h"
initial.commit09911bf2008-07-26 23:55:2928
29// Define to enable IPC performance testing instead of the regular unit tests
30// #define PERFORMANCE_TEST
31
32const wchar_t kTestClientChannel[] = L"T1";
33const wchar_t kReflectorChannel[] = L"T2";
34const wchar_t kFuzzerChannel[] = L"F3";
35
initial.commit09911bf2008-07-26 23:55:2936#ifndef PERFORMANCE_TEST
37
[email protected]95cb7fb92008-12-09 22:00:4738void IPCChannelTest::SetUp() {
39 MultiProcessTest::SetUp();
40
41 // Construct a fresh IO Message loop for the duration of each test.
42 message_loop_ = new MessageLoopForIO();
43}
44
45void IPCChannelTest::TearDown() {
46 delete message_loop_;
47 message_loop_ = NULL;
48
49 MultiProcessTest::TearDown();
50}
51
52base::ProcessHandle IPCChannelTest::SpawnChild(ChildType child_type) {
53 // kDebugChildren support.
54 bool debug_on_start = CommandLine().HasSwitch(switches::kDebugChildren);
55
56 switch (child_type) {
57 case TEST_CLIENT:
58 return MultiProcessTest::SpawnChild(L"RunTestClient", debug_on_start);
59 break;
60 case TEST_REFLECTOR:
61 return MultiProcessTest::SpawnChild(L"RunReflector", debug_on_start);
62 break;
63 case FUZZER_SERVER:
64 return MultiProcessTest::SpawnChild(L"RunFuzzServer", debug_on_start);
65 break;
66 default:
67 return NULL;
68 break;
69 }
70}
71
72TEST_F(IPCChannelTest, BasicMessageTest) {
initial.commit09911bf2008-07-26 23:55:2973 int v1 = 10;
74 std::string v2("foobar");
75 std::wstring v3(L"hello world");
76
77 IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
78 EXPECT_TRUE(m.WriteInt(v1));
79 EXPECT_TRUE(m.WriteString(v2));
80 EXPECT_TRUE(m.WriteWString(v3));
81
82 void* iter = NULL;
83
84 int vi;
85 std::string vs;
86 std::wstring vw;
87
88 EXPECT_TRUE(m.ReadInt(&iter, &vi));
89 EXPECT_EQ(v1, vi);
90
91 EXPECT_TRUE(m.ReadString(&iter, &vs));
92 EXPECT_EQ(v2, vs);
93
94 EXPECT_TRUE(m.ReadWString(&iter, &vw));
95 EXPECT_EQ(v3, vw);
96
97 // should fail
98 EXPECT_FALSE(m.ReadInt(&iter, &vi));
99 EXPECT_FALSE(m.ReadString(&iter, &vs));
100 EXPECT_FALSE(m.ReadWString(&iter, &vw));
101}
102
103static void Send(IPC::Message::Sender* sender, const char* text) {
104 static int message_index = 0;
105
106 IPC::Message* message = new IPC::Message(0,
107 2,
108 IPC::Message::PRIORITY_NORMAL);
109 message->WriteInt(message_index++);
110 message->WriteString(std::string(text));
111
112 // make sure we can handle large messages
113 char junk[50000];
114 junk[sizeof(junk)-1] = 0;
115 message->WriteString(std::string(junk));
116
117 // DEBUG: printf("[%u] sending message [%s]\n", GetCurrentProcessId(), text);
118 sender->Send(message);
119}
120
121class MyChannelListener : public IPC::Channel::Listener {
122 public:
123 virtual void OnMessageReceived(const IPC::Message& message) {
124 IPC::MessageIterator iter(message);
125
[email protected]d4651ff2008-12-02 16:51:58126 iter.NextInt();
initial.commit09911bf2008-07-26 23:55:29127 const std::string data = iter.NextString();
initial.commit09911bf2008-07-26 23:55:29128 if (--messages_left_ == 0) {
129 MessageLoop::current()->Quit();
130 } else {
131 Send(sender_, "Foo");
132 }
133 }
134
[email protected]b6be5882008-11-07 21:53:03135 virtual void OnChannelError() {
136 // There is a race when closing the channel so the last message may be lost.
137 EXPECT_LE(messages_left_, 1);
138 MessageLoop::current()->Quit();
139 }
140
initial.commit09911bf2008-07-26 23:55:29141 void Init(IPC::Message::Sender* s) {
142 sender_ = s;
143 messages_left_ = 50;
144 }
145
146 private:
147 IPC::Message::Sender* sender_;
148 int messages_left_;
149};
150static MyChannelListener channel_listener;
151
[email protected]95cb7fb92008-12-09 22:00:47152TEST_F(IPCChannelTest, ChannelTest) {
initial.commit09911bf2008-07-26 23:55:29153 // setup IPC channel
154 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
155 &channel_listener);
156 chan.Connect();
157
158 channel_listener.Init(&chan);
159
[email protected]95cb7fb92008-12-09 22:00:47160 base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT);
initial.commit09911bf2008-07-26 23:55:29161 ASSERT_TRUE(process_handle);
162
163 Send(&chan, "hello from parent");
164
165 // run message loop
166 MessageLoop::current()->Run();
167
168 // cleanup child process
[email protected]95cb7fb92008-12-09 22:00:47169 EXPECT_TRUE(base::WaitForSingleProcess(process_handle, 5000));
initial.commit09911bf2008-07-26 23:55:29170}
171
[email protected]95cb7fb92008-12-09 22:00:47172// TODO(playmobil): Implement
173#if defined(OS_WIN)
174TEST_F(IPCChannelTest, ChannelProxyTest) {
initial.commit09911bf2008-07-26 23:55:29175 // The thread needs to out-live the ChannelProxy.
[email protected]ab820df2008-08-26 05:55:10176 base::Thread thread("ChannelProxyTestServer");
177 base::Thread::Options options;
178 options.message_loop_type = MessageLoop::TYPE_IO;
179 thread.StartWithOptions(options);
initial.commit09911bf2008-07-26 23:55:29180 {
181 // setup IPC channel proxy
182 IPC::ChannelProxy chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
183 &channel_listener, NULL, thread.message_loop());
184
185 channel_listener.Init(&chan);
186
187 HANDLE process_handle = SpawnChild(TEST_CLIENT);
188 ASSERT_TRUE(process_handle);
189
190 Send(&chan, "hello from parent");
191
192 // run message loop
193 MessageLoop::current()->Run();
194
195 // cleanup child process
196 WaitForSingleObject(process_handle, 5000);
197 CloseHandle(process_handle);
198 }
199 thread.Stop();
200}
[email protected]d4651ff2008-12-02 16:51:58201#endif // defined(OS_WIN)
initial.commit09911bf2008-07-26 23:55:29202
[email protected]95cb7fb92008-12-09 22:00:47203MULTIPROCESS_TEST_MAIN(RunTestClient) {
204 MessageLoopForIO main_message_loop;
205
initial.commit09911bf2008-07-26 23:55:29206 // setup IPC channel
207 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_CLIENT,
208 &channel_listener);
209 chan.Connect();
210 channel_listener.Init(&chan);
211 Send(&chan, "hello from child");
212 // run message loop
213 MessageLoop::current()->Run();
[email protected]95cb7fb92008-12-09 22:00:47214 // return true;
215 return NULL;
initial.commit09911bf2008-07-26 23:55:29216}
initial.commit09911bf2008-07-26 23:55:29217#endif // !PERFORMANCE_TEST
218
219#ifdef PERFORMANCE_TEST
220
221//-----------------------------------------------------------------------------
222// Manually performance test
223//
224// This test times the roundtrip IPC message cycle. It is enabled with a
225// special preprocessor define to enable it instead of the standard IPC
226// unit tests. This works around some funny termination conditions in the
227// regular unit tests.
228//
229// This test is not automated. To test, you will want to vary the message
230// count and message size in TEST to get the numbers you want.
231//
232// FIXME(brettw): Automate this test and have it run by default.
233
234// This channel listener just replies to all messages with the exact same
235// message. It assumes each message has one string parameter. When the string
236// "quit" is sent, it will exit.
237class ChannelReflectorListener : public IPC::Channel::Listener {
238 public:
[email protected]95cb7fb92008-12-09 22:00:47239 explicit ChannelReflectorListener(IPC::Channel *channel) :
initial.commit09911bf2008-07-26 23:55:29240 channel_(channel),
241 count_messages_(0),
242 latency_messages_(0) {
243 std::cout << "Reflector up" << std::endl;
244 }
245
246 ~ChannelReflectorListener() {
247 std::cout << "Client Messages: " << count_messages_ << std::endl;
248 std::cout << "Client Latency: " << latency_messages_ << std::endl;
249 }
250
251 virtual void OnMessageReceived(const IPC::Message& message) {
252 count_messages_++;
253 IPC::MessageIterator iter(message);
254 int time = iter.NextInt();
255 int msgid = iter.NextInt();
256 std::string payload = iter.NextString();
257 latency_messages_ += GetTickCount() - time;
258
259 // cout << "reflector msg received: " << msgid << endl;
260 if (payload == "quit")
261 MessageLoop::current()->Quit();
262
263 IPC::Message* msg = new IPC::Message(0,
264 2,
265 IPC::Message::PRIORITY_NORMAL);
266 msg->WriteInt(GetTickCount());
267 msg->WriteInt(msgid);
268 msg->WriteString(payload);
269 channel_->Send(msg);
270 }
271 private:
272 IPC::Channel *channel_;
273 int count_messages_;
274 int latency_messages_;
275};
276
277class ChannelPerfListener : public IPC::Channel::Listener {
278 public:
279 ChannelPerfListener(IPC::Channel* channel, int msg_count, int msg_size) :
280 count_down_(msg_count),
281 channel_(channel),
282 count_messages_(0),
283 latency_messages_(0) {
284 payload_.resize(msg_size);
285 for (int i = 0; i < static_cast<int>(payload_.size()); i++)
286 payload_[i] = 'a';
287 std::cout << "perflistener up" << std::endl;
288 }
289
290 ~ChannelPerfListener() {
291 std::cout << "Server Messages: " << count_messages_ << std::endl;
292 std::cout << "Server Latency: " << latency_messages_ << std::endl;
293 }
294
295 virtual void OnMessageReceived(const IPC::Message& message) {
296 count_messages_++;
297 // decode the string so this gets counted in the total time
298 IPC::MessageIterator iter(message);
299 int time = iter.NextInt();
300 int msgid = iter.NextInt();
301 std::string cur = iter.NextString();
302 latency_messages_ += GetTickCount() - time;
303
304 // cout << "perflistener got message" << endl;
305
306 count_down_--;
307 if (count_down_ == 0) {
308 IPC::Message* msg = new IPC::Message(0,
309 2,
310 IPC::Message::PRIORITY_NORMAL);
311 msg->WriteInt(GetTickCount());
312 msg->WriteInt(count_down_);
313 msg->WriteString("quit");
314 channel_->Send(msg);
315 SetTimer(NULL, 1, 250, (TIMERPROC) PostQuitMessage);
316 return;
317 }
318
319 IPC::Message* msg = new IPC::Message(0,
320 2,
321 IPC::Message::PRIORITY_NORMAL);
322 msg->WriteInt(GetTickCount());
323 msg->WriteInt(count_down_);
324 msg->WriteString(payload_);
325 channel_->Send(msg);
326 }
327
328 private:
329 int count_down_;
330 std::string payload_;
331 IPC::Channel *channel_;
332 int count_messages_;
333 int latency_messages_;
334};
335
[email protected]95cb7fb92008-12-09 22:00:47336TEST_F(IPCChannelTest, Performance) {
initial.commit09911bf2008-07-26 23:55:29337 // setup IPC channel
338 IPC::Channel chan(kReflectorChannel, IPC::Channel::MODE_SERVER, NULL);
339 ChannelPerfListener perf_listener(&chan, 10000, 100000);
340 chan.set_listener(&perf_listener);
341 chan.Connect();
342
343 HANDLE process = SpawnChild(TEST_REFLECTOR);
344 ASSERT_TRUE(process);
345
346 Sleep(1000);
347
348 PerfTimeLogger logger("IPC_Perf");
349
350 // this initial message will kick-start the ping-pong of messages
351 IPC::Message* message = new IPC::Message(0,
352 2,
353 IPC::Message::PRIORITY_NORMAL);
354 message->WriteInt(GetTickCount());
355 message->WriteInt(-1);
356 message->WriteString("Hello");
357 chan.Send(message);
358
359 // run message loop
360 MessageLoop::current()->Run();
361
362 // cleanup child process
363 WaitForSingleObject(process, 5000);
364 CloseHandle(process);
365}
366
367// This message loop bounces all messages back to the sender
[email protected]95cb7fb92008-12-09 22:00:47368MULTIPROCESS_TEST_MAIN(RunReflector) {
369 MessageLoopForIO main_message_loop;
initial.commit09911bf2008-07-26 23:55:29370 IPC::Channel chan(kReflectorChannel, IPC::Channel::MODE_CLIENT, NULL);
371 ChannelReflectorListener channel_reflector_listener(&chan);
372 chan.set_listener(&channel_reflector_listener);
373 chan.Connect();
374
375 MessageLoop::current()->Run();
376 return true;
377}
378
379#endif // PERFORMANCE_TEST
380
[email protected]d4651ff2008-12-02 16:51:58381#if defined(OS_WIN)
initial.commit09911bf2008-07-26 23:55:29382// All fatal log messages (e.g. DCHECK failures) imply unit test failures
383static void IPCTestAssertHandler(const std::string& str) {
384 FAIL() << str;
385}
386
387// Disable crash dialogs so that it doesn't gum up the buildbot
388static void SuppressErrorDialogs() {
389 UINT new_flags = SEM_FAILCRITICALERRORS |
390 SEM_NOGPFAULTERRORBOX |
391 SEM_NOOPENFILEERRORBOX;
392
393 // Preserve existing error mode, as discussed at http://t/dmea
394 UINT existing_flags = SetErrorMode(new_flags);
395 SetErrorMode(existing_flags | new_flags);
396}
[email protected]d4651ff2008-12-02 16:51:58397#endif // defined(OS_WIN)
398
initial.commit09911bf2008-07-26 23:55:29399int main(int argc, char** argv) {
[email protected]d4651ff2008-12-02 16:51:58400 base::ScopedNSAutoreleasePool scoped_pool;
[email protected]176aa482008-11-14 03:25:15401 base::EnableTerminationOnHeapCorruption();
[email protected]95cb7fb92008-12-09 22:00:47402
[email protected]d4651ff2008-12-02 16:51:58403#if defined(OS_WIN)
initial.commit09911bf2008-07-26 23:55:29404 // suppress standard crash dialogs and such unless a debugger is present.
405 if (!IsDebuggerPresent()) {
406 SuppressErrorDialogs();
407 logging::SetLogAssertHandler(IPCTestAssertHandler);
408 }
[email protected]d4651ff2008-12-02 16:51:58409#endif // defined(OS_WIN)
initial.commit09911bf2008-07-26 23:55:29410
[email protected]95cb7fb92008-12-09 22:00:47411 int retval = TestSuite(argc, argv).Run();
initial.commit09911bf2008-07-26 23:55:29412
[email protected]95cb7fb92008-12-09 22:00:47413#ifdef PERFORMANCE_TEST
initial.commit09911bf2008-07-26 23:55:29414 if (!InitPerfLog("ipc_perf_child.log"))
415 return 1;
416#endif
[email protected]95cb7fb92008-12-09 22:00:47417 return retval;
initial.commit09911bf2008-07-26 23:55:29418}