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#include "ipc/ipc_test_base.h"
8
9#include "base/command_line.h"
10#include "base/process/kill.h"
11#include "base/threading/thread.h"
12#include "base/time/time.h"
13#include "ipc/ipc_descriptors.h"
14
15#if defined(OS_POSIX)
16#include "base/posix/global_descriptors.h"
17#endif
18
19// static
20std::string IPCTestBase::GetChannelName(const std::string& test_client_name) {
21  DCHECK(!test_client_name.empty());
22  return test_client_name + "__Channel";
23}
24
25IPCTestBase::IPCTestBase()
26    : client_process_(base::kNullProcessHandle) {
27}
28
29IPCTestBase::~IPCTestBase() {
30}
31
32void IPCTestBase::SetUp() {
33  MultiProcessTest::SetUp();
34
35  // Construct a fresh IO Message loop for the duration of each test.
36  DCHECK(!message_loop_.get());
37  message_loop_.reset(new base::MessageLoopForIO());
38}
39
40void IPCTestBase::TearDown() {
41  DCHECK(message_loop_.get());
42  message_loop_.reset();
43  MultiProcessTest::TearDown();
44}
45
46void IPCTestBase::Init(const std::string& test_client_name) {
47  DCHECK(!test_client_name.empty());
48  DCHECK(test_client_name_.empty());
49  test_client_name_ = test_client_name;
50}
51
52void IPCTestBase::CreateChannel(IPC::Listener* listener) {
53  return CreateChannelFromChannelHandle(GetChannelName(test_client_name_),
54                                        listener);
55}
56
57bool IPCTestBase::ConnectChannel() {
58  CHECK(channel_.get());
59  return channel_->Connect();
60}
61
62void IPCTestBase::DestroyChannel() {
63  DCHECK(channel_.get());
64  channel_.reset();
65}
66
67void IPCTestBase::CreateChannelFromChannelHandle(
68    const IPC::ChannelHandle& channel_handle,
69    IPC::Listener* listener) {
70  CHECK(!channel_.get());
71  CHECK(!channel_proxy_.get());
72  channel_ = IPC::Channel::CreateServer(channel_handle, listener);
73}
74
75void IPCTestBase::CreateChannelProxy(
76    IPC::Listener* listener,
77    base::SingleThreadTaskRunner* ipc_task_runner) {
78  CHECK(!channel_.get());
79  CHECK(!channel_proxy_.get());
80  channel_proxy_ = IPC::ChannelProxy::Create(GetChannelName(test_client_name_),
81                                             IPC::Channel::MODE_SERVER,
82                                             listener,
83                                             ipc_task_runner);
84}
85
86void IPCTestBase::DestroyChannelProxy() {
87  CHECK(channel_proxy_.get());
88  channel_proxy_.reset();
89}
90
91bool IPCTestBase::StartClient() {
92  DCHECK(client_process_ == base::kNullProcessHandle);
93
94  std::string test_main = test_client_name_ + "TestClientMain";
95
96#if defined(OS_WIN)
97  client_process_ = SpawnChild(test_main);
98#elif defined(OS_POSIX)
99  base::FileHandleMappingVector fds_to_map;
100  const int ipcfd = channel_.get()
101      ? channel_->GetClientFileDescriptor()
102      : channel_proxy_->GetClientFileDescriptor();
103  if (ipcfd > -1)
104    fds_to_map.push_back(std::pair<int, int>(ipcfd,
105        kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
106  base::LaunchOptions options;
107  options.fds_to_remap = &fds_to_map;
108  client_process_ = SpawnChildWithOptions(test_main, options);
109#endif
110
111  return client_process_ != base::kNullProcessHandle;
112}
113
114bool IPCTestBase::WaitForClientShutdown() {
115  DCHECK(client_process_ != base::kNullProcessHandle);
116
117  bool rv = base::WaitForSingleProcess(client_process_,
118                                       base::TimeDelta::FromSeconds(5));
119  base::CloseProcessHandle(client_process_);
120  client_process_ = base::kNullProcessHandle;
121  return rv;
122}
123