Refactor (many) IPC tests, notably most of the multiprocess tests.

This factors out common code and, more importantly/usefully, makes test-specific
code more local, and thus easier to add new tests and maintain existing ones. In
particular, this allows you to add a new test "client" (running in another
process) without modifying ipc_test_base.*.

Review URL: https://codereview.chromium.org/12051048

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@178901 0039d316-1c4b-4281-b951-d872f2087c98


CrOS-Libchrome-Original-Commit: 3c78858906d3d0d7f5319d7c993240284b4503b5
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,35 +6,89 @@
 
 #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;
 
+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);
+}
+
+// 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:
+  GenericChannelListener() : sender_(NULL), messages_left_(50) {}
+  virtual ~GenericChannelListener() {}
+
+  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;
+  }
+
+ protected:
+  void SendNextMessage() {
+    if (--messages_left_ <= 0)
+      MessageLoop::current()->Quit();
+    else
+      Send(sender_, "Foo");
+  }
+
+ private:
+  IPC::Sender* sender_;
+  int messages_left_;
+};
+
 class IPCChannelTest : public IPCTestBase {
 };
 
+// TODO(viettrungluu): Move to a separate IPCMessageTest.
 TEST_F(IPCChannelTest, BasicMessageTest) {
   int v1 = 10;
   std::string v2("foobar");
@@ -66,220 +120,103 @@
   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());
+  Init("GenericClient");
 
-  channel_listener.Init(&chan);
+  // Set up IPC channel and start client.
+  GenericChannelListener listener;
+  CreateChannel(&listener);
+  listener.Init(sender());
+  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();
 }
 
+// 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));
-    }
+  ASSERT_TRUE(StartClient());
 
-    base::ProcessHandle process_handle = MultiProcessTest::SpawnChild(
-        "RunTestClient",
-        fds_to_map,
-        debug_on_start);
-#endif  // defined(OS_POSIX)
+  Send(sender(), "hello from parent");
 
-    ASSERT_TRUE(process_handle);
+  // Run message loop.
+  MessageLoop::current()->Run();
 
-    Send(&chan, "hello from parent");
+  EXPECT_TRUE(WaitForClientShutdown());
 
-    // run message loop
-    MessageLoop::current()->Run();
-
-    // cleanup child process
-    EXPECT_TRUE(base::WaitForSingleProcess(
-        process_handle, base::TimeDelta::FromSeconds(5)));
-    base::CloseProcessHandle(process_handle);
-  }
+  // Destroy the channel proxy before shutting down the thread.
+  DestroyChannelProxy();
   thread.Stop();
 }
 
-class ChannelListenerWithOnConnectedSend : public IPC::Listener {
+class ChannelListenerWithOnConnectedSend : public GenericChannelListener {
  public:
+  ChannelListenerWithOnConnectedSend() {}
+  virtual ~ChannelListenerWithOnConnectedSend() {}
+
   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)
@@ -288,45 +225,42 @@
 #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.
+  Init("GenericClient");
 
-  ChannelListenerWithOnConnectedSend channel_listener;
-  // Setup IPC channel.
-  IPC::Channel channel(kTestClientChannel, IPC::Channel::MODE_SERVER,
-                       &channel_listener);
-  channel_listener.Init(&channel);
-  ASSERT_TRUE(channel.Connect());
+  // Set up IPC channel and start client.
+  ChannelListenerWithOnConnectedSend listener;
+  CreateChannel(&listener);
+  listener.Init(sender());
+  ASSERT_TRUE(ConnectChannel());
+  ASSERT_TRUE(StartClient());
 
-  base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, &channel);
-  ASSERT_TRUE(process_handle);
-
-  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;
+  GenericChannelListener 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
+  // 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;
 }