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#if defined(OS_WIN)
8#include <windows.h>
9#endif
10
11#include <string>
12
13#include "base/message_loop/message_loop.h"
14#include "base/pickle.h"
15#include "base/threading/thread.h"
16#include "ipc/ipc_message.h"
17#include "ipc/ipc_test_base.h"
18#include "ipc/ipc_test_channel_listener.h"
19
20namespace {
21
22class IPCChannelTest : public IPCTestBase {
23};
24
25// TODO(viettrungluu): Move to a separate IPCMessageTest.
26TEST_F(IPCChannelTest, BasicMessageTest) {
27  int v1 = 10;
28  std::string v2("foobar");
29  std::wstring v3(L"hello world");
30
31  IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
32  EXPECT_TRUE(m.WriteInt(v1));
33  EXPECT_TRUE(m.WriteString(v2));
34  EXPECT_TRUE(m.WriteWString(v3));
35
36  PickleIterator iter(m);
37
38  int vi;
39  std::string vs;
40  std::wstring vw;
41
42  EXPECT_TRUE(m.ReadInt(&iter, &vi));
43  EXPECT_EQ(v1, vi);
44
45  EXPECT_TRUE(m.ReadString(&iter, &vs));
46  EXPECT_EQ(v2, vs);
47
48  EXPECT_TRUE(m.ReadWString(&iter, &vw));
49  EXPECT_EQ(v3, vw);
50
51  // should fail
52  EXPECT_FALSE(m.ReadInt(&iter, &vi));
53  EXPECT_FALSE(m.ReadString(&iter, &vs));
54  EXPECT_FALSE(m.ReadWString(&iter, &vw));
55}
56
57TEST_F(IPCChannelTest, ChannelTest) {
58  Init("GenericClient");
59
60  // Set up IPC channel and start client.
61  IPC::TestChannelListener listener;
62  CreateChannel(&listener);
63  listener.Init(sender());
64  ASSERT_TRUE(ConnectChannel());
65  ASSERT_TRUE(StartClient());
66
67  IPC::TestChannelListener::SendOneMessage(sender(), "hello from parent");
68
69  // Run message loop.
70  base::MessageLoop::current()->Run();
71
72  // Close the channel so the client's OnChannelError() gets fired.
73  channel()->Close();
74
75  EXPECT_TRUE(WaitForClientShutdown());
76  DestroyChannel();
77}
78
79// TODO(viettrungluu): Move to a separate IPCChannelWinTest.
80#if defined(OS_WIN)
81TEST_F(IPCChannelTest, ChannelTestExistingPipe) {
82  Init("GenericClient");
83
84  // Create pipe manually using the standard Chromium name and set up IPC
85  // channel.
86  IPC::TestChannelListener listener;
87  std::string name("\\\\.\\pipe\\chrome.");
88  name.append(GetChannelName("GenericClient"));
89  HANDLE pipe = CreateNamedPipeA(name.c_str(),
90                                 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
91                                     FILE_FLAG_FIRST_PIPE_INSTANCE,
92                                 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
93                                 1,
94                                 4096,
95                                 4096,
96                                 5000,
97                                 NULL);
98  CreateChannelFromChannelHandle(IPC::ChannelHandle(pipe), &listener);
99  CloseHandle(pipe);  // The channel duplicates the handle.
100  listener.Init(sender());
101
102  // Connect to channel and start client.
103  ASSERT_TRUE(ConnectChannel());
104  ASSERT_TRUE(StartClient());
105
106  IPC::TestChannelListener::SendOneMessage(sender(), "hello from parent");
107
108  // Run message loop.
109  base::MessageLoop::current()->Run();
110
111  // Close the channel so the client's OnChannelError() gets fired.
112  channel()->Close();
113
114  EXPECT_TRUE(WaitForClientShutdown());
115  DestroyChannel();
116}
117#endif  // defined (OS_WIN)
118
119TEST_F(IPCChannelTest, ChannelProxyTest) {
120  Init("GenericClient");
121
122  base::Thread thread("ChannelProxyTestServer");
123  base::Thread::Options options;
124  options.message_loop_type = base::MessageLoop::TYPE_IO;
125  thread.StartWithOptions(options);
126
127  // Set up IPC channel proxy.
128  IPC::TestChannelListener listener;
129  CreateChannelProxy(&listener, thread.message_loop_proxy().get());
130  listener.Init(sender());
131
132  ASSERT_TRUE(StartClient());
133
134  IPC::TestChannelListener::SendOneMessage(sender(), "hello from parent");
135
136  // Run message loop.
137  base::MessageLoop::current()->Run();
138
139  EXPECT_TRUE(WaitForClientShutdown());
140
141  // Destroy the channel proxy before shutting down the thread.
142  DestroyChannelProxy();
143  thread.Stop();
144}
145
146class ChannelListenerWithOnConnectedSend : public IPC::TestChannelListener {
147 public:
148  ChannelListenerWithOnConnectedSend() {}
149  virtual ~ChannelListenerWithOnConnectedSend() {}
150
151  virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
152    SendNextMessage();
153  }
154};
155
156#if defined(OS_WIN)
157// Acting flakey in Windows. http://crbug.com/129595
158#define MAYBE_SendMessageInChannelConnected DISABLED_SendMessageInChannelConnected
159#else
160#define MAYBE_SendMessageInChannelConnected SendMessageInChannelConnected
161#endif
162// This tests the case of a listener sending back an event in its
163// OnChannelConnected handler.
164TEST_F(IPCChannelTest, MAYBE_SendMessageInChannelConnected) {
165  Init("GenericClient");
166
167  // Set up IPC channel and start client.
168  ChannelListenerWithOnConnectedSend listener;
169  CreateChannel(&listener);
170  listener.Init(sender());
171  ASSERT_TRUE(ConnectChannel());
172  ASSERT_TRUE(StartClient());
173
174  IPC::TestChannelListener::SendOneMessage(sender(), "hello from parent");
175
176  // Run message loop.
177  base::MessageLoop::current()->Run();
178
179  // Close the channel so the client's OnChannelError() gets fired.
180  channel()->Close();
181
182  EXPECT_TRUE(WaitForClientShutdown());
183  DestroyChannel();
184}
185
186MULTIPROCESS_IPC_TEST_CLIENT_MAIN(GenericClient) {
187  base::MessageLoopForIO main_message_loop;
188  IPC::TestChannelListener listener;
189
190  // Set up IPC channel.
191  scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient(
192      IPCTestBase::GetChannelName("GenericClient"),
193      &listener));
194  CHECK(channel->Connect());
195  listener.Init(channel.get());
196  IPC::TestChannelListener::SendOneMessage(channel.get(), "hello from child");
197
198  base::MessageLoop::current()->Run();
199  return 0;
200}
201
202}  // namespace
203