OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "build/build_config.h" | 5 #include "build/build_config.h" |
6 | 6 |
7 #if defined(OS_WIN) | 7 #if defined(OS_WIN) |
8 #include <windows.h> | 8 #include <windows.h> |
9 #elif defined(OS_POSIX) | 9 #elif defined(OS_POSIX) |
10 #include <sys/types.h> | 10 #include <sys/types.h> |
11 #include <unistd.h> | 11 #include <unistd.h> |
12 #endif | 12 #endif |
13 | 13 |
14 #include <stdio.h> | 14 #include <stdio.h> |
15 #include <string> | 15 #include <string> |
16 #include <utility> | 16 #include <utility> |
17 | 17 |
18 #include "ipc/ipc_tests.h" | |
19 | |
20 #include "base/base_switches.h" | 18 #include "base/base_switches.h" |
21 #include "base/command_line.h" | 19 #include "base/command_line.h" |
22 #include "base/debug/debug_on_start_win.h" | 20 #include "base/debug/debug_on_start_win.h" |
23 #include "base/perftimer.h" | 21 #include "base/perftimer.h" |
24 #include "base/pickle.h" | 22 #include "base/pickle.h" |
25 #include "base/test/perf_test_suite.h" | 23 #include "base/test/perf_test_suite.h" |
26 #include "base/test/test_suite.h" | 24 #include "base/test/test_suite.h" |
27 #include "base/threading/thread.h" | 25 #include "base/threading/thread.h" |
28 #include "base/time.h" | 26 #include "base/time.h" |
29 #include "ipc/ipc_descriptors.h" | 27 #include "ipc/ipc_descriptors.h" |
30 #include "ipc/ipc_channel.h" | 28 #include "ipc/ipc_channel.h" |
31 #include "ipc/ipc_channel_proxy.h" | 29 #include "ipc/ipc_channel_proxy.h" |
32 #include "ipc/ipc_message_utils.h" | 30 #include "ipc/ipc_message_utils.h" |
33 #include "ipc/ipc_multiprocess_test.h" | 31 #include "ipc/ipc_multiprocess_test.h" |
34 #include "ipc/ipc_sender.h" | 32 #include "ipc/ipc_sender.h" |
35 #include "ipc/ipc_switches.h" | 33 #include "ipc/ipc_switches.h" |
| 34 #include "ipc/ipc_test_base.h" |
36 #include "testing/multiprocess_func_list.h" | 35 #include "testing/multiprocess_func_list.h" |
37 | 36 |
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; | 37 const size_t kLongMessageStringNumBytes = 50000; |
47 | 38 |
48 void IPCChannelTest::SetUp() { | 39 class IPCChannelTest : public IPCTestBase { |
49 MultiProcessTest::SetUp(); | 40 }; |
50 | 41 |
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) { | 42 TEST_F(IPCChannelTest, BasicMessageTest) { |
137 int v1 = 10; | 43 int v1 = 10; |
138 std::string v2("foobar"); | 44 std::string v2("foobar"); |
139 std::wstring v3(L"hello world"); | 45 std::wstring v3(L"hello world"); |
140 | 46 |
141 IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL); | 47 IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL); |
142 EXPECT_TRUE(m.WriteInt(v1)); | 48 EXPECT_TRUE(m.WriteInt(v1)); |
143 EXPECT_TRUE(m.WriteString(v2)); | 49 EXPECT_TRUE(m.WriteString(v2)); |
144 EXPECT_TRUE(m.WriteWString(v3)); | 50 EXPECT_TRUE(m.WriteWString(v3)); |
145 | 51 |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
421 // setup IPC channel | 327 // setup IPC channel |
422 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_CLIENT, | 328 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_CLIENT, |
423 &channel_listener); | 329 &channel_listener); |
424 CHECK(chan.Connect()); | 330 CHECK(chan.Connect()); |
425 channel_listener.Init(&chan); | 331 channel_listener.Init(&chan); |
426 Send(&chan, "hello from child"); | 332 Send(&chan, "hello from child"); |
427 // run message loop | 333 // run message loop |
428 MessageLoop::current()->Run(); | 334 MessageLoop::current()->Run(); |
429 return 0; | 335 return 0; |
430 } | 336 } |
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 } | |
OLD | NEW |