summaryrefslogtreecommitdiffstats
path: root/ipc/ipc_channel_unittest.cc
diff options
context:
space:
mode:
authorviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-11 15:13:37 +0000
committerviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-11 15:13:37 +0000
commit0cb7d8c8ce8a7261743dbe613ad93495457dd174 (patch)
tree1b7fe8dc10f5b0c06c40466d2c7ecfe7466352a8 /ipc/ipc_channel_unittest.cc
parenta3c07c2082a2347b5c74d8b0c0bb9240812d331e (diff)
downloadchromium_src-0cb7d8c8ce8a7261743dbe613ad93495457dd174.zip
chromium_src-0cb7d8c8ce8a7261743dbe613ad93495457dd174.tar.gz
chromium_src-0cb7d8c8ce8a7261743dbe613ad93495457dd174.tar.bz2
Make ipc_tests file structure a little saner and add an ipc_perftests target.
This means that the (one, semi-manual) IPC perf test that we have will build without manual hackery (and do so separately from the ipc_tests target). Review URL: https://chromiumcodereview.appspot.com/11819041 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@176341 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ipc/ipc_channel_unittest.cc')
-rw-r--r--ipc/ipc_channel_unittest.cc336
1 files changed, 336 insertions, 0 deletions
diff --git a/ipc/ipc_channel_unittest.cc b/ipc/ipc_channel_unittest.cc
new file mode 100644
index 0000000..6b63ae0
--- /dev/null
+++ b/ipc/ipc_channel_unittest.cc
@@ -0,0 +1,336 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#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 <stdio.h>
+#include <string>
+#include <utility>
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/debug/debug_on_start_win.h"
+#include "base/perftimer.h"
+#include "base/pickle.h"
+#include "base/test/perf_test_suite.h"
+#include "base/test/test_suite.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_test_base.h"
+#include "testing/multiprocess_func_list.h"
+
+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;
+
+ IPC::Message* message = new IPC::Message(0,
+ 2,
+ IPC::Message::PRIORITY_NORMAL);
+ message->WriteInt(message_index++);
+ message->WriteString(std::string(text));
+
+ // Make sure we can handle large messages.
+ char junk[kLongMessageStringNumBytes];
+ memset(junk, 'a', sizeof(junk)-1);
+ junk[sizeof(junk)-1] = 0;
+ message->WriteString(std::string(junk));
+
+ // DEBUG: printf("[%u] sending message [%s]\n", GetCurrentProcessId(), text);
+ sender->Send(message);
+}
+
+class MyChannelListener : public IPC::Listener {
+ public:
+ virtual bool OnMessageReceived(const IPC::Message& message) {
+ PickleIterator iter(message);
+
+ 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());
+
+
+ if (--messages_left_ == 0) {
+ MessageLoop::current()->Quit();
+ } else {
+ Send(sender_, "Foo");
+ }
+ return true;
+ }
+
+ virtual void OnChannelError() {
+ // There is a race when closing the channel so the last message may be lost.
+ EXPECT_LE(messages_left_, 1);
+ MessageLoop::current()->Quit();
+ }
+
+ void Init(IPC::Sender* s) {
+ sender_ = s;
+ messages_left_ = 50;
+ }
+
+ private:
+ IPC::Sender* sender_;
+ 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());
+
+ channel_listener.Init(&chan);
+
+ base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, &chan);
+ ASSERT_TRUE(process_handle);
+
+ Send(&chan, "hello from parent");
+
+ // Run message loop.
+ MessageLoop::current()->Run();
+
+ // Close Channel so client gets its OnChannelError() callback fired.
+ chan.Close();
+
+ // Cleanup child process.
+ EXPECT_TRUE(base::WaitForSingleProcess(
+ process_handle, base::TimeDelta::FromSeconds(5)));
+ base::CloseProcessHandle(process_handle);
+}
+
+#if defined(OS_WIN)
+TEST_F(IPCChannelTest, ChannelTestExistingPipe) {
+ MyChannelListener channel_listener;
+ // Setup IPC channel with existing pipe. Specify name in Chrome format.
+ std::string name("\\\\.\\pipe\\chrome.");
+ name.append(kTestClientChannel);
+ const DWORD open_mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
+ FILE_FLAG_FIRST_PIPE_INSTANCE;
+ HANDLE pipe = CreateNamedPipeA(name.c_str(),
+ open_mode,
+ 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());
+
+ channel_listener.Init(&chan);
+
+ base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, &chan);
+ ASSERT_TRUE(process_handle);
+
+ Send(&chan, "hello from parent");
+
+ // Run message loop.
+ MessageLoop::current()->Run();
+
+ // Close Channel so client gets its OnChannelError() callback fired.
+ chan.Close();
+
+ // Cleanup child process.
+ EXPECT_TRUE(base::WaitForSingleProcess(
+ process_handle, base::TimeDelta::FromSeconds(5)));
+ base::CloseProcessHandle(process_handle);
+}
+#endif // defined (OS_WIN)
+
+TEST_F(IPCChannelTest, ChannelProxyTest) {
+ MyChannelListener channel_listener;
+
+ // 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);
+
+#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();
+}
+
+class ChannelListenerWithOnConnectedSend : public IPC::Listener {
+ public:
+ virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
+ SendNextMessage();
+ }
+
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
+ PickleIterator iter(message);
+
+ 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;
+ }
+
+ 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();
+ }
+
+ void Init(IPC::Sender* s) {
+ sender_ = s;
+ messages_left_ = 50;
+ }
+
+ private:
+ void SendNextMessage() {
+ if (--messages_left_ == 0) {
+ MessageLoop::current()->Quit();
+ } else {
+ Send(sender_, "Foo");
+ }
+ }
+
+ IPC::Sender* sender_;
+ int messages_left_;
+};
+
+#if defined(OS_WIN)
+// Acting flakey in Windows. http://crbug.com/129595
+#define MAYBE_SendMessageInChannelConnected DISABLED_SendMessageInChannelConnected
+#else
+#define MAYBE_SendMessageInChannelConnected SendMessageInChannelConnected
+#endif
+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());
+
+ base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, &channel);
+ ASSERT_TRUE(process_handle);
+
+ Send(&channel, "hello from parent");
+
+ // Run message loop.
+ MessageLoop::current()->Run();
+
+ // Close Channel so client gets its OnChannelError() callback fired.
+ channel.Close();
+
+ // Cleanup child process.
+ EXPECT_TRUE(base::WaitForSingleProcess(
+ process_handle, base::TimeDelta::FromSeconds(5)));
+ base::CloseProcessHandle(process_handle);
+}
+
+MULTIPROCESS_IPC_TEST_MAIN(RunTestClient) {
+ 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
+ MessageLoop::current()->Run();
+ return 0;
+}