Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(743)

Side by Side Diff: ipc/ipc_tests.cc

Issue 11819041: Make ipc_tests file structure a little saner and add an ipc_perftests target. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: ugh Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ipc/ipc_tests.h ('k') | ipc/sync_socket_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 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.
4
5 #include "build/build_config.h"
6
7 #if defined(OS_WIN)
8 #include <windows.h>
9 #elif defined(OS_POSIX)
10 #include <sys/types.h>
11 #include <unistd.h>
12 #endif
13
14 #include <stdio.h>
15 #include <string>
16 #include <utility>
17
18 #include "ipc/ipc_tests.h"
19
20 #include "base/base_switches.h"
21 #include "base/command_line.h"
22 #include "base/debug/debug_on_start_win.h"
23 #include "base/perftimer.h"
24 #include "base/pickle.h"
25 #include "base/test/perf_test_suite.h"
26 #include "base/test/test_suite.h"
27 #include "base/threading/thread.h"
28 #include "base/time.h"
29 #include "ipc/ipc_descriptors.h"
30 #include "ipc/ipc_channel.h"
31 #include "ipc/ipc_channel_proxy.h"
32 #include "ipc/ipc_message_utils.h"
33 #include "ipc/ipc_multiprocess_test.h"
34 #include "ipc/ipc_sender.h"
35 #include "ipc/ipc_switches.h"
36 #include "testing/multiprocess_func_list.h"
37
38 // Define to enable IPC performance testing instead of the regular unit tests
39 // #define PERFORMANCE_TEST
40
41 const char kTestClientChannel[] = "T1";
42 const char kReflectorChannel[] = "T2";
43 const char kFuzzerChannel[] = "F3";
44 const char kSyncSocketChannel[] = "S4";
45
46 const size_t kLongMessageStringNumBytes = 50000;
47
48 void IPCChannelTest::SetUp() {
49 MultiProcessTest::SetUp();
50
51 // Construct a fresh IO Message loop for the duration of each test.
52 message_loop_ = new MessageLoopForIO();
53 }
54
55 void IPCChannelTest::TearDown() {
56 delete message_loop_;
57 message_loop_ = NULL;
58
59 MultiProcessTest::TearDown();
60 }
61
62 #if defined(OS_WIN)
63 base::ProcessHandle IPCChannelTest::SpawnChild(ChildType child_type,
64 IPC::Channel *channel) {
65 // kDebugChildren support.
66 bool debug_on_start =
67 CommandLine::ForCurrentProcess()->HasSwitch(switches::kDebugChildren);
68
69 switch (child_type) {
70 case TEST_CLIENT:
71 return MultiProcessTest::SpawnChild("RunTestClient", debug_on_start);
72 case TEST_REFLECTOR:
73 return MultiProcessTest::SpawnChild("RunReflector", debug_on_start);
74 case FUZZER_SERVER:
75 return MultiProcessTest::SpawnChild("RunFuzzServer", debug_on_start);
76 case SYNC_SOCKET_SERVER:
77 return MultiProcessTest::SpawnChild("RunSyncSocketServer", debug_on_start);
78 default:
79 return NULL;
80 }
81 }
82 #elif defined(OS_POSIX)
83 base::ProcessHandle IPCChannelTest::SpawnChild(ChildType child_type,
84 IPC::Channel *channel) {
85 // kDebugChildren support.
86 bool debug_on_start =
87 CommandLine::ForCurrentProcess()->HasSwitch(switches::kDebugChildren);
88
89 base::FileHandleMappingVector fds_to_map;
90 const int ipcfd = channel->GetClientFileDescriptor();
91 if (ipcfd > -1) {
92 fds_to_map.push_back(std::pair<int, int>(ipcfd, kPrimaryIPCChannel + 3));
93 }
94
95 base::ProcessHandle ret = base::kNullProcessHandle;
96 switch (child_type) {
97 case TEST_CLIENT:
98 ret = MultiProcessTest::SpawnChild("RunTestClient",
99 fds_to_map,
100 debug_on_start);
101 break;
102 case TEST_DESCRIPTOR_CLIENT:
103 ret = MultiProcessTest::SpawnChild("RunTestDescriptorClient",
104 fds_to_map,
105 debug_on_start);
106 break;
107 case TEST_DESCRIPTOR_CLIENT_SANDBOXED:
108 ret = MultiProcessTest::SpawnChild("RunTestDescriptorClientSandboxed",
109 fds_to_map,
110 debug_on_start);
111 break;
112 case TEST_REFLECTOR:
113 ret = MultiProcessTest::SpawnChild("RunReflector",
114 fds_to_map,
115 debug_on_start);
116 break;
117 case FUZZER_SERVER:
118 ret = MultiProcessTest::SpawnChild("RunFuzzServer",
119 fds_to_map,
120 debug_on_start);
121 break;
122 case SYNC_SOCKET_SERVER:
123 ret = MultiProcessTest::SpawnChild("RunSyncSocketServer",
124 fds_to_map,
125 debug_on_start);
126 break;
127 default:
128 return base::kNullProcessHandle;
129 break;
130 }
131 return ret;
132 }
133 #endif // defined(OS_POSIX)
134
135 #ifndef PERFORMANCE_TEST
136 TEST_F(IPCChannelTest, BasicMessageTest) {
137 int v1 = 10;
138 std::string v2("foobar");
139 std::wstring v3(L"hello world");
140
141 IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
142 EXPECT_TRUE(m.WriteInt(v1));
143 EXPECT_TRUE(m.WriteString(v2));
144 EXPECT_TRUE(m.WriteWString(v3));
145
146 PickleIterator iter(m);
147
148 int vi;
149 std::string vs;
150 std::wstring vw;
151
152 EXPECT_TRUE(m.ReadInt(&iter, &vi));
153 EXPECT_EQ(v1, vi);
154
155 EXPECT_TRUE(m.ReadString(&iter, &vs));
156 EXPECT_EQ(v2, vs);
157
158 EXPECT_TRUE(m.ReadWString(&iter, &vw));
159 EXPECT_EQ(v3, vw);
160
161 // should fail
162 EXPECT_FALSE(m.ReadInt(&iter, &vi));
163 EXPECT_FALSE(m.ReadString(&iter, &vs));
164 EXPECT_FALSE(m.ReadWString(&iter, &vw));
165 }
166
167 static void Send(IPC::Sender* sender, const char* text) {
168 static int message_index = 0;
169
170 IPC::Message* message = new IPC::Message(0,
171 2,
172 IPC::Message::PRIORITY_NORMAL);
173 message->WriteInt(message_index++);
174 message->WriteString(std::string(text));
175
176 // Make sure we can handle large messages.
177 char junk[kLongMessageStringNumBytes];
178 memset(junk, 'a', sizeof(junk)-1);
179 junk[sizeof(junk)-1] = 0;
180 message->WriteString(std::string(junk));
181
182 // DEBUG: printf("[%u] sending message [%s]\n", GetCurrentProcessId(), text);
183 sender->Send(message);
184 }
185
186 class MyChannelListener : public IPC::Listener {
187 public:
188 virtual bool OnMessageReceived(const IPC::Message& message) {
189 PickleIterator iter(message);
190
191 int ignored;
192 EXPECT_TRUE(iter.ReadInt(&ignored));
193 std::string data;
194 EXPECT_TRUE(iter.ReadString(&data));
195 std::string big_string;
196 EXPECT_TRUE(iter.ReadString(&big_string));
197 EXPECT_EQ(kLongMessageStringNumBytes - 1, big_string.length());
198
199
200 if (--messages_left_ == 0) {
201 MessageLoop::current()->Quit();
202 } else {
203 Send(sender_, "Foo");
204 }
205 return true;
206 }
207
208 virtual void OnChannelError() {
209 // There is a race when closing the channel so the last message may be lost.
210 EXPECT_LE(messages_left_, 1);
211 MessageLoop::current()->Quit();
212 }
213
214 void Init(IPC::Sender* s) {
215 sender_ = s;
216 messages_left_ = 50;
217 }
218
219 private:
220 IPC::Sender* sender_;
221 int messages_left_;
222 };
223
224 TEST_F(IPCChannelTest, ChannelTest) {
225 MyChannelListener channel_listener;
226 // Setup IPC channel.
227 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
228 &channel_listener);
229 ASSERT_TRUE(chan.Connect());
230
231 channel_listener.Init(&chan);
232
233 base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, &chan);
234 ASSERT_TRUE(process_handle);
235
236 Send(&chan, "hello from parent");
237
238 // Run message loop.
239 MessageLoop::current()->Run();
240
241 // Close Channel so client gets its OnChannelError() callback fired.
242 chan.Close();
243
244 // Cleanup child process.
245 EXPECT_TRUE(base::WaitForSingleProcess(
246 process_handle, base::TimeDelta::FromSeconds(5)));
247 base::CloseProcessHandle(process_handle);
248 }
249
250 #if defined(OS_WIN)
251 TEST_F(IPCChannelTest, ChannelTestExistingPipe) {
252 MyChannelListener channel_listener;
253 // Setup IPC channel with existing pipe. Specify name in Chrome format.
254 std::string name("\\\\.\\pipe\\chrome.");
255 name.append(kTestClientChannel);
256 const DWORD open_mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
257 FILE_FLAG_FIRST_PIPE_INSTANCE;
258 HANDLE pipe = CreateNamedPipeA(name.c_str(),
259 open_mode,
260 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
261 1,
262 4096,
263 4096,
264 5000,
265 NULL);
266 IPC::Channel chan(IPC::ChannelHandle(pipe), IPC::Channel::MODE_SERVER,
267 &channel_listener);
268 // Channel will duplicate the handle.
269 CloseHandle(pipe);
270 ASSERT_TRUE(chan.Connect());
271
272 channel_listener.Init(&chan);
273
274 base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, &chan);
275 ASSERT_TRUE(process_handle);
276
277 Send(&chan, "hello from parent");
278
279 // Run message loop.
280 MessageLoop::current()->Run();
281
282 // Close Channel so client gets its OnChannelError() callback fired.
283 chan.Close();
284
285 // Cleanup child process.
286 EXPECT_TRUE(base::WaitForSingleProcess(
287 process_handle, base::TimeDelta::FromSeconds(5)));
288 base::CloseProcessHandle(process_handle);
289 }
290 #endif // defined (OS_WIN)
291
292 TEST_F(IPCChannelTest, ChannelProxyTest) {
293 MyChannelListener channel_listener;
294
295 // The thread needs to out-live the ChannelProxy.
296 base::Thread thread("ChannelProxyTestServer");
297 base::Thread::Options options;
298 options.message_loop_type = MessageLoop::TYPE_IO;
299 thread.StartWithOptions(options);
300 {
301 // setup IPC channel proxy
302 IPC::ChannelProxy chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
303 &channel_listener, thread.message_loop_proxy());
304
305 channel_listener.Init(&chan);
306
307 #if defined(OS_WIN)
308 base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, NULL);
309 #elif defined(OS_POSIX)
310 bool debug_on_start = CommandLine::ForCurrentProcess()->HasSwitch(
311 switches::kDebugChildren);
312 base::FileHandleMappingVector fds_to_map;
313 const int ipcfd = chan.GetClientFileDescriptor();
314 if (ipcfd > -1) {
315 fds_to_map.push_back(std::pair<int, int>(ipcfd, kPrimaryIPCChannel + 3));
316 }
317
318 base::ProcessHandle process_handle = MultiProcessTest::SpawnChild(
319 "RunTestClient",
320 fds_to_map,
321 debug_on_start);
322 #endif // defined(OS_POSIX)
323
324 ASSERT_TRUE(process_handle);
325
326 Send(&chan, "hello from parent");
327
328 // run message loop
329 MessageLoop::current()->Run();
330
331 // cleanup child process
332 EXPECT_TRUE(base::WaitForSingleProcess(
333 process_handle, base::TimeDelta::FromSeconds(5)));
334 base::CloseProcessHandle(process_handle);
335 }
336 thread.Stop();
337 }
338
339 class ChannelListenerWithOnConnectedSend : public IPC::Listener {
340 public:
341 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
342 SendNextMessage();
343 }
344
345 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
346 PickleIterator iter(message);
347
348 int ignored;
349 EXPECT_TRUE(iter.ReadInt(&ignored));
350 std::string data;
351 EXPECT_TRUE(iter.ReadString(&data));
352 std::string big_string;
353 EXPECT_TRUE(iter.ReadString(&big_string));
354 EXPECT_EQ(kLongMessageStringNumBytes - 1, big_string.length());
355 SendNextMessage();
356 return true;
357 }
358
359 virtual void OnChannelError() OVERRIDE {
360 // There is a race when closing the channel so the last message may be lost.
361 EXPECT_LE(messages_left_, 1);
362 MessageLoop::current()->Quit();
363 }
364
365 void Init(IPC::Sender* s) {
366 sender_ = s;
367 messages_left_ = 50;
368 }
369
370 private:
371 void SendNextMessage() {
372 if (--messages_left_ == 0) {
373 MessageLoop::current()->Quit();
374 } else {
375 Send(sender_, "Foo");
376 }
377 }
378
379 IPC::Sender* sender_;
380 int messages_left_;
381 };
382
383 #if defined(OS_WIN)
384 // Acting flakey in Windows. http://crbug.com/129595
385 #define MAYBE_SendMessageInChannelConnected DISABLED_SendMessageInChannelConnect ed
386 #else
387 #define MAYBE_SendMessageInChannelConnected SendMessageInChannelConnected
388 #endif
389 TEST_F(IPCChannelTest, MAYBE_SendMessageInChannelConnected) {
390 // This tests the case of a listener sending back an event in it's
391 // OnChannelConnected handler.
392
393 ChannelListenerWithOnConnectedSend channel_listener;
394 // Setup IPC channel.
395 IPC::Channel channel(kTestClientChannel, IPC::Channel::MODE_SERVER,
396 &channel_listener);
397 channel_listener.Init(&channel);
398 ASSERT_TRUE(channel.Connect());
399
400 base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, &channel);
401 ASSERT_TRUE(process_handle);
402
403 Send(&channel, "hello from parent");
404
405 // Run message loop.
406 MessageLoop::current()->Run();
407
408 // Close Channel so client gets its OnChannelError() callback fired.
409 channel.Close();
410
411 // Cleanup child process.
412 EXPECT_TRUE(base::WaitForSingleProcess(
413 process_handle, base::TimeDelta::FromSeconds(5)));
414 base::CloseProcessHandle(process_handle);
415 }
416
417 MULTIPROCESS_IPC_TEST_MAIN(RunTestClient) {
418 MessageLoopForIO main_message_loop;
419 MyChannelListener channel_listener;
420
421 // setup IPC channel
422 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_CLIENT,
423 &channel_listener);
424 CHECK(chan.Connect());
425 channel_listener.Init(&chan);
426 Send(&chan, "hello from child");
427 // run message loop
428 MessageLoop::current()->Run();
429 return 0;
430 }
431
432 #endif // !PERFORMANCE_TEST
433
434 #ifdef PERFORMANCE_TEST
435
436 //-----------------------------------------------------------------------------
437 // Manually performance test
438 //
439 // This test times the roundtrip IPC message cycle. It is enabled with a
440 // special preprocessor define to enable it instead of the standard IPC
441 // unit tests. This works around some funny termination conditions in the
442 // regular unit tests.
443 //
444 // This test is not automated. To test, you will want to vary the message
445 // count and message size in TEST to get the numbers you want.
446 //
447 // FIXME(brettw): Automate this test and have it run by default.
448
449 // This channel listener just replies to all messages with the exact same
450 // message. It assumes each message has one string parameter. When the string
451 // "quit" is sent, it will exit.
452 class ChannelReflectorListener : public IPC::Listener {
453 public:
454 explicit ChannelReflectorListener(IPC::Channel *channel) :
455 channel_(channel),
456 count_messages_(0) {
457 std::cout << "Reflector up" << std::endl;
458 }
459
460 ~ChannelReflectorListener() {
461 std::cout << "Client Messages: " << count_messages_ << std::endl;
462 std::cout << "Client Latency: " << latency_messages_.InMilliseconds()
463 << std::endl;
464 }
465
466 virtual bool OnMessageReceived(const IPC::Message& message) {
467 count_messages_++;
468 PickleIterator iter(message);
469 int64 time_internal;
470 EXPECT_TRUE(iter.ReadInt64(&time_internal));
471 int msgid;
472 EXPECT_TRUE(iter.ReadInt(&msgid));
473 std::string payload;
474 EXPECT_TRUE(iter.ReadString(&payload));
475 // TODO(vtl): Should we use |HighResNow()| instead of |Now()|?
476 latency_messages_ += base::TimeTicks::Now() -
477 base::TimeTicks::FromInternalValue(time_internal);
478
479 // cout << "reflector msg received: " << msgid << endl;
480 if (payload == "quit")
481 MessageLoop::current()->Quit();
482
483 IPC::Message* msg = new IPC::Message(0,
484 2,
485 IPC::Message::PRIORITY_NORMAL);
486 msg->WriteInt64(base::TimeTicks::Now().ToInternalValue());
487 msg->WriteInt(msgid);
488 msg->WriteString(payload);
489 channel_->Send(msg);
490 return true;
491 }
492
493 private:
494 IPC::Channel *channel_;
495 int count_messages_;
496 base::TimeDelta latency_messages_;
497 };
498
499 class ChannelPerfListener : public IPC::Listener {
500 public:
501 ChannelPerfListener(IPC::Channel* channel, int msg_count, int msg_size) :
502 count_down_(msg_count),
503 channel_(channel),
504 count_messages_(0) {
505 payload_.resize(msg_size);
506 for (int i = 0; i < static_cast<int>(payload_.size()); i++)
507 payload_[i] = 'a';
508 std::cout << "perflistener up" << std::endl;
509 }
510
511 ~ChannelPerfListener() {
512 std::cout << "Server Messages: " << count_messages_ << std::endl;
513 std::cout << "Server Latency: " << latency_messages_.InMilliseconds()
514 << std::endl;
515 }
516
517 virtual bool OnMessageReceived(const IPC::Message& message) {
518 count_messages_++;
519 // Decode the string so this gets counted in the total time.
520 PickleIterator iter(message);
521 int64 time_internal;
522 EXPECT_TRUE(iter.ReadInt64(&time_internal));
523 int msgid;
524 EXPECT_TRUE(iter.ReadInt(&msgid));
525 std::string cur;
526 EXPECT_TRUE(iter.ReadString(&cur));
527 latency_messages_ += base::TimeTicks::Now() -
528 base::TimeTicks::FromInternalValue(time_internal);
529
530 count_down_--;
531 if (count_down_ == 0) {
532 IPC::Message* msg = new IPC::Message(0,
533 2,
534 IPC::Message::PRIORITY_NORMAL);
535 msg->WriteInt64(base::TimeTicks::Now().ToInternalValue());
536 msg->WriteInt(count_down_);
537 msg->WriteString("quit");
538 channel_->Send(msg);
539
540 MessageLoop::current()->QuitWhenIdle();
541 return true;
542 }
543
544 IPC::Message* msg = new IPC::Message(0,
545 2,
546 IPC::Message::PRIORITY_NORMAL);
547 msg->WriteInt64(base::TimeTicks::Now().ToInternalValue());
548 msg->WriteInt(count_down_);
549 msg->WriteString(payload_);
550 channel_->Send(msg);
551 return true;
552 }
553
554 private:
555 int count_down_;
556 std::string payload_;
557 IPC::Channel *channel_;
558 int count_messages_;
559 base::TimeDelta latency_messages_;
560 };
561
562 TEST_F(IPCChannelTest, Performance) {
563 // setup IPC channel
564 IPC::Channel chan(kReflectorChannel, IPC::Channel::MODE_SERVER, NULL);
565 ChannelPerfListener perf_listener(&chan, 10000, 100000);
566 chan.set_listener(&perf_listener);
567 ASSERT_TRUE(chan.Connect());
568
569 base::ProcessHandle process_handle = SpawnChild(TEST_REFLECTOR, &chan);
570 ASSERT_TRUE(process_handle);
571
572 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
573
574 PerfTimeLogger logger("IPC_Perf");
575
576 // this initial message will kick-start the ping-pong of messages
577 IPC::Message* message = new IPC::Message(0,
578 2,
579 IPC::Message::PRIORITY_NORMAL);
580 message->WriteInt64(base::TimeTicks::Now().ToInternalValue());
581 message->WriteInt(-1);
582 message->WriteString("Hello");
583 chan.Send(message);
584
585 // run message loop
586 MessageLoop::current()->Run();
587
588 // Clean up child process.
589 EXPECT_TRUE(base::WaitForSingleProcess(
590 process_handle, base::TimeDelta::FromSeconds(5)));
591 base::CloseProcessHandle(process_handle);
592 }
593
594 // This message loop bounces all messages back to the sender
595 MULTIPROCESS_IPC_TEST_MAIN(RunReflector) {
596 MessageLoopForIO main_message_loop;
597 IPC::Channel chan(kReflectorChannel, IPC::Channel::MODE_CLIENT, NULL);
598 ChannelReflectorListener channel_reflector_listener(&chan);
599 chan.set_listener(&channel_reflector_listener);
600 CHECK(chan.Connect());
601
602 MessageLoop::current()->Run();
603 return 0;
604 }
605
606 #endif // PERFORMANCE_TEST
607
608 int main(int argc, char** argv) {
609 #ifdef PERFORMANCE_TEST
610 int retval = base::PerfTestSuite(argc, argv).Run();
611 #else
612 int retval = base::TestSuite(argc, argv).Run();
613 #endif
614 return retval;
615 }
OLDNEW
« no previous file with comments | « ipc/ipc_tests.h ('k') | ipc/sync_socket_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698