diff options
-rw-r--r-- | ipc/ipc.gyp | 5 | ||||
-rw-r--r-- | ipc/ipc_channel_unittest.cc | 330 | ||||
-rw-r--r-- | ipc/ipc_fuzzing_tests.cc | 102 | ||||
-rw-r--r-- | ipc/ipc_multiprocess_test.cc | 4 | ||||
-rw-r--r-- | ipc/ipc_multiprocess_test.h | 18 | ||||
-rw-r--r-- | ipc/ipc_perftests.cc | 54 | ||||
-rw-r--r-- | ipc/ipc_send_fds_test.cc | 166 | ||||
-rw-r--r-- | ipc/ipc_test_base.cc | 174 | ||||
-rw-r--r-- | ipc/ipc_test_base.h | 99 | ||||
-rw-r--r-- | ipc/sync_socket_unittest.cc | 38 |
10 files changed, 472 insertions, 518 deletions
diff --git a/ipc/ipc.gyp b/ipc/ipc.gyp index edc53a4..5e2f3a7 100644 --- a/ipc/ipc.gyp +++ b/ipc/ipc.gyp @@ -18,7 +18,7 @@ }, 'dependencies': [ '../base/base.gyp:base', - # TODO(vtl): Needed for base/lazy_instance.h, which is suspect. + # TODO(viettrungluu): Needed for base/lazy_instance.h, which is suspect. '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', ], # TODO(gregoryd): direct_dependent_settings should be shared with the @@ -151,7 +151,8 @@ }, 'dependencies': [ '../base/base.gyp:base_nacl_win64', - # TODO(vtl): Needed for base/lazy_instance.h, which is suspect. + # TODO(viettrungluu): Needed for base/lazy_instance.h, which is + # suspect. '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations_win64', ], # TODO(gregoryd): direct_dependent_settings should be shared with the diff --git a/ipc/ipc_channel_unittest.cc b/ipc/ipc_channel_unittest.cc index aa5da15..db9dd3c 100644 --- a/ipc/ipc_channel_unittest.cc +++ b/ipc/ipc_channel_unittest.cc @@ -6,66 +6,20 @@ #if defined(OS_WIN) #include <windows.h> -#elif defined(OS_POSIX) -#include <sys/types.h> -#include <unistd.h> #endif -#include <stdio.h> #include <string> -#include <utility> -#include "base/command_line.h" +#include "base/message_loop.h" #include "base/pickle.h" #include "base/threading/thread.h" -#include "base/time.h" -#include "ipc/ipc_descriptors.h" -#include "ipc/ipc_channel.h" -#include "ipc/ipc_channel_proxy.h" -#include "ipc/ipc_message_utils.h" -#include "ipc/ipc_multiprocess_test.h" -#include "ipc/ipc_sender.h" -#include "ipc/ipc_switches.h" +#include "ipc/ipc_message.h" #include "ipc/ipc_test_base.h" namespace { const size_t kLongMessageStringNumBytes = 50000; -class IPCChannelTest : public IPCTestBase { -}; - -TEST_F(IPCChannelTest, BasicMessageTest) { - int v1 = 10; - std::string v2("foobar"); - std::wstring v3(L"hello world"); - - IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL); - EXPECT_TRUE(m.WriteInt(v1)); - EXPECT_TRUE(m.WriteString(v2)); - EXPECT_TRUE(m.WriteWString(v3)); - - PickleIterator iter(m); - - int vi; - std::string vs; - std::wstring vw; - - EXPECT_TRUE(m.ReadInt(&iter, &vi)); - EXPECT_EQ(v1, vi); - - EXPECT_TRUE(m.ReadString(&iter, &vs)); - EXPECT_EQ(v2, vs); - - EXPECT_TRUE(m.ReadWString(&iter, &vw)); - EXPECT_EQ(v3, vw); - - // should fail - EXPECT_FALSE(m.ReadInt(&iter, &vi)); - EXPECT_FALSE(m.ReadString(&iter, &vs)); - EXPECT_FALSE(m.ReadWString(&iter, &vw)); -} - static void Send(IPC::Sender* sender, const char* text) { static int message_index = 0; @@ -85,9 +39,15 @@ static void Send(IPC::Sender* sender, const char* text) { sender->Send(message); } -class MyChannelListener : public IPC::Listener { +// A generic listener that expects messages of a certain type (see +// OnMessageReceived()), and either sends a generic response or quits after the +// 50th message (or on channel error). +class GenericChannelListener : public IPC::Listener { public: - virtual bool OnMessageReceived(const IPC::Message& message) { + GenericChannelListener() : sender_(NULL), messages_left_(50) {} + virtual ~GenericChannelListener() {} + + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { PickleIterator iter(message); int ignored; @@ -98,16 +58,11 @@ class MyChannelListener : public IPC::Listener { EXPECT_TRUE(iter.ReadString(&big_string)); EXPECT_EQ(kLongMessageStringNumBytes - 1, big_string.length()); - - if (--messages_left_ == 0) { - MessageLoop::current()->Quit(); - } else { - Send(sender_, "Foo"); - } + SendNextMessage(); return true; } - virtual void OnChannelError() { + virtual void OnChannelError() OVERRIDE { // There is a race when closing the channel so the last message may be lost. EXPECT_LE(messages_left_, 1); MessageLoop::current()->Quit(); @@ -115,7 +70,14 @@ class MyChannelListener : public IPC::Listener { void Init(IPC::Sender* s) { sender_ = s; - messages_left_ = 50; + } + + protected: + void SendNextMessage() { + if (--messages_left_ <= 0) + MessageLoop::current()->Quit(); + else + Send(sender_, "Foo"); } private: @@ -123,163 +85,138 @@ class MyChannelListener : public IPC::Listener { int messages_left_; }; -TEST_F(IPCChannelTest, ChannelTest) { - MyChannelListener channel_listener; - // Setup IPC channel. - IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_SERVER, - &channel_listener); - ASSERT_TRUE(chan.Connect()); +class IPCChannelTest : public IPCTestBase { +}; + +// TODO(viettrungluu): Move to a separate IPCMessageTest. +TEST_F(IPCChannelTest, BasicMessageTest) { + int v1 = 10; + std::string v2("foobar"); + std::wstring v3(L"hello world"); + + IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL); + EXPECT_TRUE(m.WriteInt(v1)); + EXPECT_TRUE(m.WriteString(v2)); + EXPECT_TRUE(m.WriteWString(v3)); + + PickleIterator iter(m); + + int vi; + std::string vs; + std::wstring vw; + + EXPECT_TRUE(m.ReadInt(&iter, &vi)); + EXPECT_EQ(v1, vi); + + EXPECT_TRUE(m.ReadString(&iter, &vs)); + EXPECT_EQ(v2, vs); + + EXPECT_TRUE(m.ReadWString(&iter, &vw)); + EXPECT_EQ(v3, vw); + + // should fail + EXPECT_FALSE(m.ReadInt(&iter, &vi)); + EXPECT_FALSE(m.ReadString(&iter, &vs)); + EXPECT_FALSE(m.ReadWString(&iter, &vw)); +} - channel_listener.Init(&chan); +TEST_F(IPCChannelTest, ChannelTest) { + Init("GenericClient"); - base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, &chan); - ASSERT_TRUE(process_handle); + // Set up IPC channel and start client. + GenericChannelListener listener; + CreateChannel(&listener); + listener.Init(sender()); + ASSERT_TRUE(ConnectChannel()); + ASSERT_TRUE(StartClient()); - Send(&chan, "hello from parent"); + Send(sender(), "hello from parent"); // Run message loop. MessageLoop::current()->Run(); - // Close Channel so client gets its OnChannelError() callback fired. - chan.Close(); + // Close the channel so the client's OnChannelError() gets fired. + channel()->Close(); - // Cleanup child process. - EXPECT_TRUE(base::WaitForSingleProcess( - process_handle, base::TimeDelta::FromSeconds(5))); - base::CloseProcessHandle(process_handle); + EXPECT_TRUE(WaitForClientShutdown()); + DestroyChannel(); } +// TODO(viettrungluu): Move to a separate IPCChannelWinTest. #if defined(OS_WIN) TEST_F(IPCChannelTest, ChannelTestExistingPipe) { - MyChannelListener channel_listener; - // Setup IPC channel with existing pipe. Specify name in Chrome format. + Init("GenericClient"); + + // Create pipe manually using the standard Chromium name and set up IPC + // channel. + GenericChannelListener listener; std::string name("\\\\.\\pipe\\chrome."); - name.append(kTestClientChannel); - const DWORD open_mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | - FILE_FLAG_FIRST_PIPE_INSTANCE; + name.append(GetChannelName("GenericClient")); HANDLE pipe = CreateNamedPipeA(name.c_str(), - open_mode, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | + FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, 4096, 4096, 5000, NULL); - IPC::Channel chan(IPC::ChannelHandle(pipe), IPC::Channel::MODE_SERVER, - &channel_listener); - // Channel will duplicate the handle. - CloseHandle(pipe); - ASSERT_TRUE(chan.Connect()); + CreateChannelFromChannelHandle(IPC::ChannelHandle(pipe), &listener); + CloseHandle(pipe); // The channel duplicates the handle. + listener.Init(sender()); - channel_listener.Init(&chan); + // Connect to channel and start client. + ASSERT_TRUE(ConnectChannel()); + ASSERT_TRUE(StartClient()); - base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, &chan); - ASSERT_TRUE(process_handle); - - Send(&chan, "hello from parent"); + Send(sender(), "hello from parent"); // Run message loop. MessageLoop::current()->Run(); - // Close Channel so client gets its OnChannelError() callback fired. - chan.Close(); + // Close the channel so the client's OnChannelError() gets fired. + channel()->Close(); - // Cleanup child process. - EXPECT_TRUE(base::WaitForSingleProcess( - process_handle, base::TimeDelta::FromSeconds(5))); - base::CloseProcessHandle(process_handle); + EXPECT_TRUE(WaitForClientShutdown()); + DestroyChannel(); } #endif // defined (OS_WIN) TEST_F(IPCChannelTest, ChannelProxyTest) { - MyChannelListener channel_listener; + Init("GenericClient"); - // The thread needs to out-live the ChannelProxy. base::Thread thread("ChannelProxyTestServer"); base::Thread::Options options; options.message_loop_type = MessageLoop::TYPE_IO; thread.StartWithOptions(options); - { - // setup IPC channel proxy - IPC::ChannelProxy chan(kTestClientChannel, IPC::Channel::MODE_SERVER, - &channel_listener, thread.message_loop_proxy()); - channel_listener.Init(&chan); + // Set up IPC channel proxy. + GenericChannelListener listener; + CreateChannelProxy(&listener, thread.message_loop_proxy()); + listener.Init(sender()); -#if defined(OS_WIN) - base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, NULL); -#elif defined(OS_POSIX) - bool debug_on_start = CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDebugChildren); - base::FileHandleMappingVector fds_to_map; - const int ipcfd = chan.GetClientFileDescriptor(); - if (ipcfd > -1) { - fds_to_map.push_back(std::pair<int, int>(ipcfd, kPrimaryIPCChannel + 3)); - } - - base::ProcessHandle process_handle = MultiProcessTest::SpawnChild( - "RunTestClient", - fds_to_map, - debug_on_start); -#endif // defined(OS_POSIX) - - ASSERT_TRUE(process_handle); - - Send(&chan, "hello from parent"); - - // run message loop - MessageLoop::current()->Run(); - - // cleanup child process - EXPECT_TRUE(base::WaitForSingleProcess( - process_handle, base::TimeDelta::FromSeconds(5))); - base::CloseProcessHandle(process_handle); - } - thread.Stop(); -} + ASSERT_TRUE(StartClient()); -class ChannelListenerWithOnConnectedSend : public IPC::Listener { - public: - virtual void OnChannelConnected(int32 peer_pid) OVERRIDE { - SendNextMessage(); - } + Send(sender(), "hello from parent"); - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { - PickleIterator iter(message); + // Run message loop. + MessageLoop::current()->Run(); - int ignored; - EXPECT_TRUE(iter.ReadInt(&ignored)); - std::string data; - EXPECT_TRUE(iter.ReadString(&data)); - std::string big_string; - EXPECT_TRUE(iter.ReadString(&big_string)); - EXPECT_EQ(kLongMessageStringNumBytes - 1, big_string.length()); - SendNextMessage(); - return true; - } + EXPECT_TRUE(WaitForClientShutdown()); - virtual void OnChannelError() OVERRIDE { - // There is a race when closing the channel so the last message may be lost. - EXPECT_LE(messages_left_, 1); - MessageLoop::current()->Quit(); - } + // Destroy the channel proxy before shutting down the thread. + DestroyChannelProxy(); + thread.Stop(); +} - void Init(IPC::Sender* s) { - sender_ = s; - messages_left_ = 50; - } +class ChannelListenerWithOnConnectedSend : public GenericChannelListener { + public: + ChannelListenerWithOnConnectedSend() {} + virtual ~ChannelListenerWithOnConnectedSend() {} - private: - void SendNextMessage() { - if (--messages_left_ == 0) { - MessageLoop::current()->Quit(); - } else { - Send(sender_, "Foo"); - } + virtual void OnChannelConnected(int32 peer_pid) OVERRIDE { + SendNextMessage(); } - - IPC::Sender* sender_; - int messages_left_; }; #if defined(OS_WIN) @@ -288,45 +225,42 @@ class ChannelListenerWithOnConnectedSend : public IPC::Listener { #else #define MAYBE_SendMessageInChannelConnected SendMessageInChannelConnected #endif +// This tests the case of a listener sending back an event in its +// OnChannelConnected handler. TEST_F(IPCChannelTest, MAYBE_SendMessageInChannelConnected) { - // This tests the case of a listener sending back an event in it's - // OnChannelConnected handler. - - ChannelListenerWithOnConnectedSend channel_listener; - // Setup IPC channel. - IPC::Channel channel(kTestClientChannel, IPC::Channel::MODE_SERVER, - &channel_listener); - channel_listener.Init(&channel); - ASSERT_TRUE(channel.Connect()); + Init("GenericClient"); - base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, &channel); - ASSERT_TRUE(process_handle); + // Set up IPC channel and start client. + ChannelListenerWithOnConnectedSend listener; + CreateChannel(&listener); + listener.Init(sender()); + ASSERT_TRUE(ConnectChannel()); + ASSERT_TRUE(StartClient()); - Send(&channel, "hello from parent"); + Send(sender(), "hello from parent"); // Run message loop. MessageLoop::current()->Run(); - // Close Channel so client gets its OnChannelError() callback fired. - channel.Close(); + // Close the channel so the client's OnChannelError() gets fired. + channel()->Close(); - // Cleanup child process. - EXPECT_TRUE(base::WaitForSingleProcess( - process_handle, base::TimeDelta::FromSeconds(5))); - base::CloseProcessHandle(process_handle); + EXPECT_TRUE(WaitForClientShutdown()); + DestroyChannel(); } -MULTIPROCESS_IPC_TEST_MAIN(RunTestClient) { +MULTIPROCESS_IPC_TEST_CLIENT_MAIN(GenericClient) { MessageLoopForIO main_message_loop; - MyChannelListener channel_listener; - - // setup IPC channel - IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_CLIENT, - &channel_listener); - CHECK(chan.Connect()); - channel_listener.Init(&chan); - Send(&chan, "hello from child"); - // run message loop + GenericChannelListener listener; + + // Set up IPC channel. + IPC::Channel channel(IPCTestBase::GetChannelName("GenericClient"), + IPC::Channel::MODE_CLIENT, + &listener); + CHECK(channel.Connect()); + listener.Init(&channel); + Send(&channel, "hello from child"); + MessageLoop::current()->Run(); return 0; } diff --git a/ipc/ipc_fuzzing_tests.cc b/ipc/ipc_fuzzing_tests.cc index 080c643..030709e 100644 --- a/ipc/ipc_fuzzing_tests.cc +++ b/ipc/ipc_fuzzing_tests.cc @@ -7,11 +7,7 @@ #include <sstream> #include "base/message_loop.h" -#include "base/process_util.h" #include "base/threading/platform_thread.h" -#include "ipc/ipc_channel.h" -#include "ipc/ipc_channel_proxy.h" -#include "ipc/ipc_multiprocess_test.h" #include "ipc/ipc_test_base.h" #include "testing/gtest/include/gtest/gtest.h" @@ -246,14 +242,16 @@ class FuzzerClientListener : public SimpleListener { IPC::Message* last_msg_; }; -// Runs the fuzzing server child mode. Returns when the preset number -// of messages have been received. -MULTIPROCESS_IPC_TEST_MAIN(RunFuzzServer) { +// Runs the fuzzing server child mode. Returns when the preset number of +// messages have been received. +MULTIPROCESS_IPC_TEST_CLIENT_MAIN(FuzzServerClient) { MessageLoopForIO main_message_loop; FuzzerServerListener listener; - IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_CLIENT, &listener); - CHECK(chan.Connect()); - listener.Init(&chan); + IPC::Channel channel(IPCTestBase::GetChannelName("FuzzServerClient"), + IPC::Channel::MODE_CLIENT, + &listener); + CHECK(channel.Connect()); + listener.Init(&channel); MessageLoop::current()->Run(); return 0; } @@ -264,76 +262,69 @@ class IPCFuzzingTest : public IPCTestBase { // This test makes sure that the FuzzerClientListener and FuzzerServerListener // are working properly by generating two well formed IPC calls. TEST_F(IPCFuzzingTest, SanityTest) { + Init("FuzzServerClient"); + FuzzerClientListener listener; - IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_SERVER, - &listener); - base::ProcessHandle server_process = SpawnChild(FUZZER_SERVER, &chan); - ASSERT_TRUE(server_process); - base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); - ASSERT_TRUE(chan.Connect()); - listener.Init(&chan); + CreateChannel(&listener); + listener.Init(channel()); + ASSERT_TRUE(ConnectChannel()); + ASSERT_TRUE(StartClient()); IPC::Message* msg = NULL; int value = 43; msg = new MsgClassIS(value, L"expect 43"); - chan.Send(msg); + sender()->Send(msg); EXPECT_TRUE(listener.ExpectMessage(value, MsgClassIS::ID)); msg = new MsgClassSI(L"expect 44", ++value); - chan.Send(msg); + sender()->Send(msg); EXPECT_TRUE(listener.ExpectMessage(value, MsgClassSI::ID)); - EXPECT_TRUE(base::WaitForSingleProcess( - server_process, base::TimeDelta::FromSeconds(5))); - base::CloseProcessHandle(server_process); + EXPECT_TRUE(WaitForClientShutdown()); + DestroyChannel(); } -// This test uses a payload that is smaller than expected. -// This generates an error while unpacking the IPC buffer which in -// In debug this triggers an assertion and in release it is ignored(!!). Right -// after we generate another valid IPC to make sure framing is working -// properly. +// This test uses a payload that is smaller than expected. This generates an +// error while unpacking the IPC buffer which in debug trigger an assertion and +// in release is ignored (!). Right after we generate another valid IPC to make +// sure framing is working properly. #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) TEST_F(IPCFuzzingTest, MsgBadPayloadShort) { + Init("FuzzServerClient"); + FuzzerClientListener listener; - IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_SERVER, - &listener); - base::ProcessHandle server_process = SpawnChild(FUZZER_SERVER, &chan); - ASSERT_TRUE(server_process); - base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); - ASSERT_TRUE(chan.Connect()); - listener.Init(&chan); + CreateChannel(&listener); + listener.Init(channel()); + ASSERT_TRUE(ConnectChannel()); + ASSERT_TRUE(StartClient()); IPC::Message* msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassIS::ID, IPC::Message::PRIORITY_NORMAL); msg->WriteInt(666); - chan.Send(msg); + sender()->Send(msg); EXPECT_TRUE(listener.ExpectMsgNotHandled(MsgClassIS::ID)); msg = new MsgClassSI(L"expect one", 1); - chan.Send(msg); + sender()->Send(msg); EXPECT_TRUE(listener.ExpectMessage(1, MsgClassSI::ID)); - EXPECT_TRUE(base::WaitForSingleProcess( - server_process, base::TimeDelta::FromSeconds(5))); - base::CloseProcessHandle(server_process); + EXPECT_TRUE(WaitForClientShutdown()); + DestroyChannel(); } #endif -// This test uses a payload that has too many arguments, but so the payload -// size is big enough so the unpacking routine does not generate an error as -// in the case of MsgBadPayloadShort test. -// This test does not pinpoint a flaw (per se) as by design we don't carry -// type information on the IPC message. +// This test uses a payload that has too many arguments, but so the payload size +// is big enough so the unpacking routine does not generate an error as in the +// case of MsgBadPayloadShort test. This test does not pinpoint a flaw (per se) +// as by design we don't carry type information on the IPC message. TEST_F(IPCFuzzingTest, MsgBadPayloadArgs) { + Init("FuzzServerClient"); + FuzzerClientListener listener; - IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_SERVER, - &listener); - base::ProcessHandle server_process = SpawnChild(FUZZER_SERVER, &chan); - ASSERT_TRUE(server_process); - base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); - ASSERT_TRUE(chan.Connect()); - listener.Init(&chan); + CreateChannel(&listener); + listener.Init(channel()); + ASSERT_TRUE(ConnectChannel()); + ASSERT_TRUE(StartClient()); IPC::Message* msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassSI::ID, IPC::Message::PRIORITY_NORMAL); @@ -341,18 +332,17 @@ TEST_F(IPCFuzzingTest, MsgBadPayloadArgs) { msg->WriteInt(0); msg->WriteInt(0x65); // Extra argument. - chan.Send(msg); + sender()->Send(msg); EXPECT_TRUE(listener.ExpectMessage(0, MsgClassSI::ID)); // Now send a well formed message to make sure the receiver wasn't // thrown out of sync by the extra argument. msg = new MsgClassIS(3, L"expect three"); - chan.Send(msg); + sender()->Send(msg); EXPECT_TRUE(listener.ExpectMessage(3, MsgClassIS::ID)); - EXPECT_TRUE(base::WaitForSingleProcess( - server_process, base::TimeDelta::FromSeconds(5))); - base::CloseProcessHandle(server_process); + EXPECT_TRUE(WaitForClientShutdown()); + DestroyChannel(); } // This class is for testing the IPC_BEGIN_MESSAGE_MAP_EX macros. diff --git a/ipc/ipc_multiprocess_test.cc b/ipc/ipc_multiprocess_test.cc index b13ed7b..8e3c03a 100644 --- a/ipc/ipc_multiprocess_test.cc +++ b/ipc/ipc_multiprocess_test.cc @@ -11,9 +11,13 @@ #include "ipc/ipc_descriptors.h" #endif +namespace internal { + void MultiProcessTestIPCSetUp() { #if defined(OS_POSIX) base::GlobalDescriptors::GetInstance()->Set(kPrimaryIPCChannel, kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor); #endif } + +} // namespace internal diff --git a/ipc/ipc_multiprocess_test.h b/ipc/ipc_multiprocess_test.h index 3bf2ad8..43aaa6b 100644 --- a/ipc/ipc_multiprocess_test.h +++ b/ipc/ipc_multiprocess_test.h @@ -8,15 +8,19 @@ #include "testing/multiprocess_func_list.h" // Use this macro when your sub-process is using an IPCChannel to communicate -// with the test process. -// See comment below for MultiProcessTestIPCSetUp() on why this is needed. +// with the test process. See the comment below for why this is needed. #define MULTIPROCESS_IPC_TEST_MAIN(test_main) \ - MULTIPROCESS_TEST_MAIN_WITH_SETUP(test_main, MultiProcessTestIPCSetUp) + MULTIPROCESS_TEST_MAIN_WITH_SETUP(test_main, \ + internal::MultiProcessTestIPCSetUp) -// Setup function used by MULTIPROCESS_IPC_TEST_MAIN. -// Registers the IPC channel as a global descriptor in the child process. This -// is needed on POSIX as the IPCChannel when created looks for a specific global -// descriptor to establish the connection to the parent process. +namespace internal { + +// Setup function used by MULTIPROCESS_IPC_TEST_MAIN. Registers the IPC channel +// as a global descriptor in the child process. This is needed on POSIX as on +// creation the IPCChannel looks for a specific global descriptor to establish +// the connection to the parent process. void MultiProcessTestIPCSetUp(); +} // namespace internal + #endif // IPC_IPC_MULTIPROCESS_TEST_H_ diff --git a/ipc/ipc_perftests.cc b/ipc/ipc_perftests.cc index 901f07a..a24c47d 100644 --- a/ipc/ipc_perftests.cc +++ b/ipc/ipc_perftests.cc @@ -4,13 +4,6 @@ #include "build/build_config.h" -#if defined(OS_WIN) -#include <windows.h> -#elif defined(OS_POSIX) -#include <sys/types.h> -#include <unistd.h> -#endif - #include <algorithm> #include <string> @@ -26,7 +19,6 @@ #include "ipc/ipc_channel.h" #include "ipc/ipc_channel_proxy.h" #include "ipc/ipc_message_utils.h" -#include "ipc/ipc_multiprocess_test.h" #include "ipc/ipc_sender.h" #include "ipc/ipc_test_base.h" @@ -143,9 +135,9 @@ class ChannelReflectorListener : public IPC::Listener { EventTimeTracker latency_tracker_; }; -class ChannelPerfListener : public IPC::Listener { +class PerformanceChannelListener : public IPC::Listener { public: - ChannelPerfListener() + PerformanceChannelListener() : channel_(NULL), msg_count_(0), msg_size_(0), @@ -154,7 +146,7 @@ class ChannelPerfListener : public IPC::Listener { VLOG(1) << "Server listener up"; } - ~ChannelPerfListener() { + ~PerformanceChannelListener() { VLOG(1) << "Server listener down"; } @@ -229,22 +221,21 @@ class ChannelPerfListener : public IPC::Listener { }; TEST_F(IPCChannelPerfTest, Performance) { - // Setup IPC channel. - ChannelPerfListener perf_listener; - IPC::Channel chan(kReflectorChannel, IPC::Channel::MODE_SERVER, - &perf_listener); - perf_listener.Init(&chan); - ASSERT_TRUE(chan.Connect()); + Init("PerformanceClient"); - base::ProcessHandle process_handle = SpawnChild(TEST_REFLECTOR, &chan); - ASSERT_TRUE(process_handle); + // Set up IPC channel and start client. + PerformanceChannelListener listener; + CreateChannel(&listener); + listener.Init(channel()); + ASSERT_TRUE(ConnectChannel()); + ASSERT_TRUE(StartClient()); const size_t kMsgSizeBase = 12; const int kMsgSizeMaxExp = 5; int msg_count = 100000; size_t msg_size = kMsgSizeBase; for (int i = 1; i <= kMsgSizeMaxExp; i++) { - perf_listener.SetTestParams(msg_count, msg_size); + listener.SetTestParams(msg_count, msg_size); // This initial message will kick-start the ping-pong of messages. IPC::Message* message = @@ -252,7 +243,7 @@ TEST_F(IPCChannelPerfTest, Performance) { message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); message->WriteInt(-1); message->WriteString("hello"); - chan.Send(message); + sender()->Send(message); // Run message loop. MessageLoop::current()->Run(); @@ -265,22 +256,21 @@ TEST_F(IPCChannelPerfTest, Performance) { message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); message->WriteInt(-1); message->WriteString("quit"); - chan.Send(message); + sender()->Send(message); - // Clean up child process. - EXPECT_TRUE(base::WaitForSingleProcess(process_handle, - base::TimeDelta::FromSeconds(5))); - base::CloseProcessHandle(process_handle); + EXPECT_TRUE(WaitForClientShutdown()); + DestroyChannel(); } // This message loop bounces all messages back to the sender. -MULTIPROCESS_IPC_TEST_MAIN(RunReflector) { +MULTIPROCESS_IPC_TEST_CLIENT_MAIN(PerformanceClient) { MessageLoopForIO main_message_loop; - ChannelReflectorListener channel_reflector_listener; - IPC::Channel chan(kReflectorChannel, IPC::Channel::MODE_CLIENT, - &channel_reflector_listener); - channel_reflector_listener.Init(&chan); - CHECK(chan.Connect()); + ChannelReflectorListener listener; + IPC::Channel channel(IPCTestBase::GetChannelName("PerformanceClient"), + IPC::Channel::MODE_CLIENT, + &listener); + listener.Init(&channel); + CHECK(channel.Connect()); MessageLoop::current()->Run(); return 0; diff --git a/ipc/ipc_send_fds_test.cc b/ipc/ipc_send_fds_test.cc index 005103c..5699e6d 100644 --- a/ipc/ipc_send_fds_test.cc +++ b/ipc/ipc_send_fds_test.cc @@ -4,6 +4,7 @@ #include "build/build_config.h" +#if defined(OS_POSIX) #if defined(OS_MACOSX) extern "C" { #include <sandbox.h> @@ -11,18 +12,15 @@ extern "C" { #endif #include <fcntl.h> #include <sys/stat.h> +#include <unistd.h> +#include "base/file_descriptor_posix.h" #include "base/message_loop.h" +#include "base/pickle.h" #include "base/posix/eintr_wrapper.h" -#include "ipc/ipc_channel.h" -#include "ipc/ipc_listener.h" #include "ipc/ipc_message_utils.h" -#include "ipc/ipc_multiprocess_test.h" #include "ipc/ipc_test_base.h" -#if defined(OS_POSIX) -#include "base/file_descriptor_posix.h" - namespace { const unsigned kNumFDsToSend = 20; @@ -33,21 +31,21 @@ static void VerifyAndCloseDescriptor(int fd, ino_t inode_num) { char buf; ssize_t amt_read = read(fd, &buf, 1); ASSERT_EQ(amt_read, 1); - ASSERT_EQ(buf, 0); // /dev/zero always reads NUL bytes. + ASSERT_EQ(buf, 0); // /dev/zero always reads 0 bytes. struct stat st; ASSERT_EQ(fstat(fd, &st), 0); ASSERT_EQ(close(fd), 0); - // We compare iNode numbers to check that the file sent over the wire - // was actually the same physical file as the one we were expecting. + // Compare inode numbers to check that the file sent over the wire is actually + // the one expected. ASSERT_EQ(inode_num, st.st_ino); } class MyChannelDescriptorListener : public IPC::Listener { public: - MyChannelDescriptorListener(ino_t expected_inode_num) + explicit MyChannelDescriptorListener(ino_t expected_inode_num) : expected_inode_num_(expected_inode_num), num_fds_received_(0) {} @@ -57,13 +55,12 @@ class MyChannelDescriptorListener : public IPC::Listener { ++num_fds_received_; base::FileDescriptor descriptor; - IPC::ParamTraits<base::FileDescriptor>::Read( - &message, &iter, &descriptor); + IPC::ParamTraits<base::FileDescriptor>::Read(&message, &iter, &descriptor); VerifyAndCloseDescriptor(descriptor.fd, expected_inode_num_); - if (num_fds_received_ == kNumFDsToSend) { + if (num_fds_received_ == kNumFDsToSend) MessageLoop::current()->Quit(); - } + return true; } @@ -71,8 +68,8 @@ class MyChannelDescriptorListener : public IPC::Listener { MessageLoop::current()->Quit(); } - bool GotExpectedNumberOfDescriptors() { - return kNumFDsToSend == num_fds_received_; + bool GotExpectedNumberOfDescriptors() const { + return num_fds_received_ == kNumFDsToSend; } private: @@ -80,126 +77,107 @@ class MyChannelDescriptorListener : public IPC::Listener { unsigned num_fds_received_; }; -void TestDescriptorServer(IPC::Channel& chan, - base::ProcessHandle process_handle) { - ASSERT_TRUE(process_handle); +class IPCSendFdsTest : public IPCTestBase { + protected: + void RunServer() { + // Set up IPC channel and start client. + MyChannelDescriptorListener listener(-1); + CreateChannel(&listener); + ASSERT_TRUE(ConnectChannel()); + ASSERT_TRUE(StartClient()); + + for (unsigned i = 0; i < kNumFDsToSend; ++i) { + const int fd = open(kDevZeroPath, O_RDONLY); + ASSERT_GE(fd, 0); + base::FileDescriptor descriptor(fd, true); + + IPC::Message* message = + new IPC::Message(0, 3, IPC::Message::PRIORITY_NORMAL); + IPC::ParamTraits<base::FileDescriptor>::Write(message, descriptor); + ASSERT_TRUE(sender()->Send(message)); + } - for (unsigned i = 0; i < kNumFDsToSend; ++i) { - base::FileDescriptor descriptor; - const int fd = open(kDevZeroPath, O_RDONLY); - ASSERT_GE(fd, 0); - descriptor.auto_close = true; - descriptor.fd = fd; - - IPC::Message* message = new IPC::Message(0, // routing_id - 3, // message type - IPC::Message::PRIORITY_NORMAL); - IPC::ParamTraits<base::FileDescriptor>::Write(message, descriptor); - ASSERT_TRUE(chan.Send(message)); - } + // Run message loop. + MessageLoop::current()->Run(); - // Run message loop. - MessageLoop::current()->Run(); + // Close the channel so the client's OnChannelError() gets fired. + channel()->Close(); - // Close Channel so client gets its OnChannelError() callback fired. - chan.Close(); + EXPECT_TRUE(WaitForClientShutdown()); + DestroyChannel(); + } +}; - // Cleanup child process. - EXPECT_TRUE(base::WaitForSingleProcess( - process_handle, base::TimeDelta::FromSeconds(5))); +TEST_F(IPCSendFdsTest, DescriptorTest) { + Init("SendFdsClient"); + RunServer(); } -int TestDescriptorClient(ino_t expected_inode_num) { +int SendFdsClientCommon(const std::string& test_client_name, + ino_t expected_inode_num) { MessageLoopForIO main_message_loop; MyChannelDescriptorListener listener(expected_inode_num); - // Setup IPC channel. - IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_CLIENT, - &listener); - CHECK(chan.Connect()); + // Set up IPC channel. + IPC::Channel channel(IPCTestBase::GetChannelName(test_client_name), + IPC::Channel::MODE_CLIENT, + &listener); + CHECK(channel.Connect()); - // Run message loop so IPC Channel can handle message IO. + // Run message loop. MessageLoop::current()->Run(); - // Verify that the message loop was exited due to getting the correct - // number of descriptors, and not because the channel closing unexpectedly. + // Verify that the message loop was exited due to getting the correct number + // of descriptors, and not because of the channel closing unexpectedly. CHECK(listener.GotExpectedNumberOfDescriptors()); return 0; } -class IPCSendFdsTest : public IPCTestBase { -}; +MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendFdsClient) { + struct stat st; + int fd = open(kDevZeroPath, O_RDONLY); + fstat(fd, &st); + EXPECT_GE(HANDLE_EINTR(close(fd)), 0); + return SendFdsClientCommon("SendFdsClient", st.st_ino); +} #if defined(OS_MACOSX) +// Test that FDs are correctly sent to a sandboxed process. // TODO(port): Make this test cross-platform. -MULTIPROCESS_IPC_TEST_MAIN(RunTestDescriptorClientSandboxed) { +TEST_F(IPCSendFdsTest, DescriptorTestSandboxed) { + Init("SendFdsSandboxedClient"); + RunServer(); +} + +MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendFdsSandboxedClient) { struct stat st; const int fd = open(kDevZeroPath, O_RDONLY); fstat(fd, &st); - if (HANDLE_EINTR(close(fd)) < 0) { + if (HANDLE_EINTR(close(fd)) < 0) return -1; - } - // Enable the Sandbox. + // Enable the sandbox. char* error_buff = NULL; int error = sandbox_init(kSBXProfilePureComputation, SANDBOX_NAMED, &error_buff); bool success = (error == 0 && error_buff == NULL); - if (!success) { + if (!success) return -1; - } sandbox_free_error(error_buff); - // Make sure Sandbox is really enabled. + // Make sure sandbox is really enabled. if (open(kDevZeroPath, O_RDONLY) != -1) { LOG(ERROR) << "Sandbox wasn't properly enabled"; return -1; } // See if we can receive a file descriptor. - return TestDescriptorClient(st.st_ino); -} - -// Test that FDs are correctly sent to a sandboxed process. -TEST_F(IPCSendFdsTest, DescriptorTestSandboxed) { - // Setup IPC channel. - MyChannelDescriptorListener listener(-1); - - IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_SERVER, - &listener); - ASSERT_TRUE(chan.Connect()); - - base::ProcessHandle process_handle = SpawnChild( - TEST_DESCRIPTOR_CLIENT_SANDBOXED, - &chan); - TestDescriptorServer(chan, process_handle); + return SendFdsClientCommon("SendFdsSandboxedClient", st.st_ino); } #endif // defined(OS_MACOSX) -MULTIPROCESS_IPC_TEST_MAIN(RunTestDescriptorClient) { - struct stat st; - const int fd = open(kDevZeroPath, O_RDONLY); - fstat(fd, &st); - EXPECT_GE(HANDLE_EINTR(close(fd)), 0); - - return TestDescriptorClient(st.st_ino); -} - -TEST_F(IPCSendFdsTest, DescriptorTest) { - // Setup IPC channel. - MyChannelDescriptorListener listener(-1); - - IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_SERVER, - &listener); - ASSERT_TRUE(chan.Connect()); - - base::ProcessHandle process_handle = SpawnChild(TEST_DESCRIPTOR_CLIENT, - &chan); - TestDescriptorServer(chan, process_handle); -} - } // namespace #endif // defined(OS_POSIX) diff --git a/ipc/ipc_test_base.cc b/ipc/ipc_test_base.cc index 7503375..2f739f1 100644 --- a/ipc/ipc_test_base.cc +++ b/ipc/ipc_test_base.cc @@ -4,15 +4,6 @@ #include "build/build_config.h" -#if defined(OS_WIN) -#include <windows.h> -#elif defined(OS_POSIX) -#include <sys/types.h> -#include <unistd.h> -#endif - -#include <utility> - #include "ipc/ipc_test_base.h" #include "base/command_line.h" @@ -20,101 +11,112 @@ #include "base/threading/thread.h" #include "base/time.h" #include "ipc/ipc_descriptors.h" -#include "ipc/ipc_channel.h" -#include "ipc/ipc_channel_proxy.h" -#include "ipc/ipc_message_utils.h" -#include "ipc/ipc_multiprocess_test.h" -#include "ipc/ipc_sender.h" #include "ipc/ipc_switches.h" -const char kTestClientChannel[] = "T1"; -const char kReflectorChannel[] = "T2"; -const char kFuzzerChannel[] = "F3"; -const char kSyncSocketChannel[] = "S4"; +// static +std::string IPCTestBase::GetChannelName(const std::string& test_client_name) { + DCHECK(!test_client_name.empty()); + return test_client_name + "__Channel"; +} + +IPCTestBase::IPCTestBase() + : client_process_(base::kNullProcessHandle) { +} + +IPCTestBase::~IPCTestBase() { +} void IPCTestBase::SetUp() { MultiProcessTest::SetUp(); // Construct a fresh IO Message loop for the duration of each test. - message_loop_ = new MessageLoopForIO(); + DCHECK(!message_loop_.get()); + message_loop_.reset(new MessageLoopForIO()); } void IPCTestBase::TearDown() { - delete message_loop_; - message_loop_ = NULL; - + DCHECK(message_loop_.get()); + message_loop_.reset(); MultiProcessTest::TearDown(); } -#if defined(OS_WIN) -base::ProcessHandle IPCTestBase::SpawnChild(IPCTestBase::ChildType child_type, - IPC::Channel* channel) { - // kDebugChildren support. - bool debug_on_start = - CommandLine::ForCurrentProcess()->HasSwitch(switches::kDebugChildren); +void IPCTestBase::Init(const std::string& test_client_name) { + DCHECK(!test_client_name.empty()); + DCHECK(test_client_name_.empty()); + test_client_name_ = test_client_name; +} - switch (child_type) { - case TEST_CLIENT: - return MultiProcessTest::SpawnChild("RunTestClient", debug_on_start); - case TEST_REFLECTOR: - return MultiProcessTest::SpawnChild("RunReflector", debug_on_start); - case FUZZER_SERVER: - return MultiProcessTest::SpawnChild("RunFuzzServer", debug_on_start); - case SYNC_SOCKET_SERVER: - return MultiProcessTest::SpawnChild("RunSyncSocketServer", debug_on_start); - default: - return NULL; - } +void IPCTestBase::CreateChannel(IPC::Listener* listener) { + return CreateChannelFromChannelHandle(GetChannelName(test_client_name_), + listener); } -#elif defined(OS_POSIX) -base::ProcessHandle IPCTestBase::SpawnChild(IPCTestBase::ChildType child_type, - IPC::Channel* channel) { - // kDebugChildren support. + +bool IPCTestBase::ConnectChannel() { + CHECK(channel_.get()); + return channel_->Connect(); +} + +void IPCTestBase::DestroyChannel() { + DCHECK(channel_.get()); + channel_.reset(); +} + +void IPCTestBase::CreateChannelFromChannelHandle( + const IPC::ChannelHandle& channel_handle, + IPC::Listener* listener) { + CHECK(!channel_.get()); + CHECK(!channel_proxy_.get()); + channel_.reset(new IPC::Channel(channel_handle, + IPC::Channel::MODE_SERVER, + listener)); +} + +void IPCTestBase::CreateChannelProxy( + IPC::Listener* listener, + base::SingleThreadTaskRunner* ipc_task_runner) { + CHECK(!channel_.get()); + CHECK(!channel_proxy_.get()); + channel_proxy_.reset(new IPC::ChannelProxy(GetChannelName(test_client_name_), + IPC::Channel::MODE_SERVER, + listener, + ipc_task_runner)); +} + +void IPCTestBase::DestroyChannelProxy() { + CHECK(channel_proxy_.get()); + channel_proxy_.reset(); +} + +bool IPCTestBase::StartClient() { + DCHECK(client_process_ == base::kNullProcessHandle); + + std::string test_main = test_client_name_ + "TestClientMain"; bool debug_on_start = CommandLine::ForCurrentProcess()->HasSwitch(switches::kDebugChildren); +#if defined(OS_WIN) + client_process_ = MultiProcessTest::SpawnChild(test_main, debug_on_start); +#elif defined(OS_POSIX) base::FileHandleMappingVector fds_to_map; - const int ipcfd = channel->GetClientFileDescriptor(); - if (ipcfd > -1) { + const int ipcfd = channel_.get() ? channel_->GetClientFileDescriptor() : + channel_proxy_->GetClientFileDescriptor(); + if (ipcfd > -1) fds_to_map.push_back(std::pair<int, int>(ipcfd, kPrimaryIPCChannel + 3)); - } - - base::ProcessHandle ret = base::kNullProcessHandle; - switch (child_type) { - case TEST_CLIENT: - ret = MultiProcessTest::SpawnChild("RunTestClient", - fds_to_map, - debug_on_start); - break; - case TEST_DESCRIPTOR_CLIENT: - ret = MultiProcessTest::SpawnChild("RunTestDescriptorClient", - fds_to_map, - debug_on_start); - break; - case TEST_DESCRIPTOR_CLIENT_SANDBOXED: - ret = MultiProcessTest::SpawnChild("RunTestDescriptorClientSandboxed", - fds_to_map, - debug_on_start); - break; - case TEST_REFLECTOR: - ret = MultiProcessTest::SpawnChild("RunReflector", - fds_to_map, - debug_on_start); - break; - case FUZZER_SERVER: - ret = MultiProcessTest::SpawnChild("RunFuzzServer", - fds_to_map, - debug_on_start); - break; - case SYNC_SOCKET_SERVER: - ret = MultiProcessTest::SpawnChild("RunSyncSocketServer", - fds_to_map, - debug_on_start); - break; - default: - return base::kNullProcessHandle; - break; - } - return ret; + + client_process_ = MultiProcessTest::SpawnChild(test_main, + fds_to_map, + debug_on_start); +#endif + + return client_process_ != base::kNullProcessHandle; +} + +bool IPCTestBase::WaitForClientShutdown() { + DCHECK(client_process_ != base::kNullProcessHandle); + + bool rv = base::WaitForSingleProcess(client_process_, + base::TimeDelta::FromSeconds(5)); + base::CloseProcessHandle(client_process_); + client_process_ = base::kNullProcessHandle; + return rv; } -#endif // defined(OS_POSIX) diff --git a/ipc/ipc_test_base.h b/ipc/ipc_test_base.h index 08d410c..2afb720 100644 --- a/ipc/ipc_test_base.h +++ b/ipc/ipc_test_base.h @@ -5,42 +5,95 @@ #ifndef IPC_IPC_TEST_BASE_H_ #define IPC_IPC_TEST_BASE_H_ +#include <string> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" #include "base/process.h" #include "base/test/multiprocess_test.h" - -// The different channel names for the child processes. -extern const char kTestClientChannel[]; -extern const char kReflectorChannel[]; -extern const char kFuzzerChannel[]; -extern const char kSyncSocketChannel[]; +#include "ipc/ipc_channel.h" +#include "ipc/ipc_channel_proxy.h" +#include "ipc/ipc_multiprocess_test.h" class MessageLoopForIO; -namespace IPC { -class Channel; -} // namespace IPC -// Base class to facilitate spawning IPC client processes. +// A test fixture for multiprocess IPC tests. Such tests include a "client" side +// (running in a separate process). The same client may be shared between +// several different tests. class IPCTestBase : public base::MultiProcessTest { public: - enum ChildType { - TEST_CLIENT, - TEST_DESCRIPTOR_CLIENT, - TEST_DESCRIPTOR_CLIENT_SANDBOXED, - TEST_REFLECTOR, - FUZZER_SERVER, - SYNC_SOCKET_SERVER - }; + // The channel name is based on the client's name. This is a public static + // helper to be used by the client-side code; server-side test code should + // usually not use this (directly). + static std::string GetChannelName(const std::string& test_client_name); protected: - // Create a new MessageLoopForIO for each test. + IPCTestBase(); + virtual ~IPCTestBase(); + virtual void SetUp() OVERRIDE; virtual void TearDown() OVERRIDE; - // Spawns a child process of the specified type - base::ProcessHandle SpawnChild(ChildType child_type, IPC::Channel* channel); + // Initializes the test to use the given client. + void Init(const std::string& test_client_name); + + // Creates a channel with the given listener and connects to the channel + // (returning true if successful), respectively. Use these to use a channel + // directly. Since the listener must outlive the channel, you must destroy the + // channel before the listener gets destroyed. + void CreateChannel(IPC::Listener* listener); + bool ConnectChannel(); + void DestroyChannel(); + + // Use this instead of CreateChannel() if you want to use some different + // channel specification (then use ConnectChannel() as usual). + void CreateChannelFromChannelHandle(const IPC::ChannelHandle& channel_handle, + IPC::Listener* listener); + + // Creates a channel proxy with the given listener and task runner. (The + // channel proxy will automatically create and connect a channel.) You must + // (manually) destroy the channel proxy before the task runner's thread is + // destroyed. + void CreateChannelProxy(IPC::Listener* listener, + base::SingleThreadTaskRunner* ipc_task_runner); + void DestroyChannelProxy(); + + // Starts the client process, returning true if successful; this should be + // done after connecting to the channel. + bool StartClient(); + + // Waits for the client to shut down, returning true if successful. Note that + // this does not initiate client shutdown; that must be done by the test + // (somehow). This must be called before the end of the test whenever + // StartClient() was called successfully. + bool WaitForClientShutdown(); - // Created around each test instantiation. - MessageLoopForIO* message_loop_; + // Use this to send IPC messages (when you don't care if you're using a + // channel or a proxy). + IPC::Sender* sender() { + return channel_.get() ? static_cast<IPC::Sender*>(channel_.get()) : + static_cast<IPC::Sender*>(channel_proxy_.get()); + } + + IPC::Channel* channel() { return channel_.get(); } + IPC::ChannelProxy* channel_proxy() { return channel_proxy_.get(); } + + const base::ProcessHandle& client_process() const { return client_process_; } + + private: + std::string test_client_name_; + scoped_ptr<MessageLoopForIO> message_loop_; + + scoped_ptr<IPC::Channel> channel_; + scoped_ptr<IPC::ChannelProxy> channel_proxy_; + + base::ProcessHandle client_process_; + + DISALLOW_COPY_AND_ASSIGN(IPCTestBase); }; +// Use this to declare the client side for tests using IPCTestBase. +#define MULTIPROCESS_IPC_TEST_CLIENT_MAIN(test_client_name) \ + MULTIPROCESS_IPC_TEST_MAIN(test_client_name ## TestClientMain) + #endif // IPC_IPC_TEST_BASE_H_ diff --git a/ipc/sync_socket_unittest.cc b/ipc/sync_socket_unittest.cc index 4dba55d..57ba326 100644 --- a/ipc/sync_socket_unittest.cc +++ b/ipc/sync_socket_unittest.cc @@ -12,8 +12,6 @@ #include "base/message_loop.h" #include "base/process_util.h" #include "base/threading/thread.h" -#include "ipc/ipc_channel_proxy.h" -#include "ipc/ipc_multiprocess_test.h" #include "ipc/ipc_test_base.h" #include "testing/gtest/include/gtest/gtest.h" @@ -106,14 +104,16 @@ class SyncSocketServerListener : public IPC::Listener { DISALLOW_COPY_AND_ASSIGN(SyncSocketServerListener); }; -// Runs the fuzzing server child mode. Returns when the preset number -// of messages have been received. -MULTIPROCESS_IPC_TEST_MAIN(RunSyncSocketServer) { +// Runs the fuzzing server child mode. Returns when the preset number of +// messages have been received. +MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SyncSocketServerClient) { MessageLoopForIO main_message_loop; SyncSocketServerListener listener; - IPC::Channel chan(kSyncSocketChannel, IPC::Channel::MODE_CLIENT, &listener); - EXPECT_TRUE(chan.Connect()); - listener.Init(&chan); + IPC::Channel channel(IPCTestBase::GetChannelName("SyncSocketServerClient"), + IPC::Channel::MODE_CLIENT, + &listener); + EXPECT_TRUE(channel.Connect()); + listener.Init(&channel); MessageLoop::current()->Run(); return 0; } @@ -167,11 +167,11 @@ class SyncSocketTest : public IPCTestBase { }; TEST_F(SyncSocketTest, SanityTest) { + Init("SyncSocketServerClient"); + SyncSocketClientListener listener; - IPC::Channel chan(kSyncSocketChannel, IPC::Channel::MODE_SERVER, - &listener); - base::ProcessHandle server_process = SpawnChild(SYNC_SOCKET_SERVER, &chan); - ASSERT_TRUE(server_process); + CreateChannel(&listener); + ASSERT_TRUE(StartClient()); // Create a pair of SyncSockets. base::SyncSocket pair[2]; base::SyncSocket::CreatePair(&pair[0], &pair[1]); @@ -180,12 +180,12 @@ TEST_F(SyncSocketTest, SanityTest) { EXPECT_EQ(0U, pair[1].Peek()); base::SyncSocket::Handle target_handle; // Connect the channel and listener. - ASSERT_TRUE(chan.Connect()); - listener.Init(&pair[0], &chan); + ASSERT_TRUE(ConnectChannel()); + listener.Init(&pair[0], channel()); #if defined(OS_WIN) // On windows we need to duplicate the handle into the server process. BOOL retval = DuplicateHandle(GetCurrentProcess(), pair[1].handle(), - server_process, &target_handle, + client_process(), &target_handle, 0, FALSE, DUPLICATE_SAME_ACCESS); EXPECT_TRUE(retval); // Set up a message to pass the handle to the server. @@ -196,18 +196,16 @@ TEST_F(SyncSocketTest, SanityTest) { base::FileDescriptor filedesc(target_handle, false); IPC::Message* msg = new MsgClassSetHandle(filedesc); #endif // defined(OS_WIN) - EXPECT_TRUE(chan.Send(msg)); + EXPECT_TRUE(sender()->Send(msg)); // Use the current thread as the I/O thread. MessageLoop::current()->Run(); // Shut down. pair[0].Close(); pair[1].Close(); - EXPECT_TRUE(base::WaitForSingleProcess( - server_process, base::TimeDelta::FromSeconds(5))); - base::CloseProcessHandle(server_process); + EXPECT_TRUE(WaitForClientShutdown()); + DestroyChannel(); } - // A blocking read operation that will block the thread until it receives // |length| bytes of packets or Shutdown() is called on another thread. static void BlockingRead(base::SyncSocket* socket, char* buf, |