blob: bb7403f3329bae1581d44ca62636a335942f28b3 [file] [log] [blame]
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +09001// 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#elif defined(OS_POSIX)
10#include <sys/types.h>
11#include <unistd.h>
12#endif
13
14#include <stdio.h>
15#include <string>
16#include <utility>
17
18#include "base/base_switches.h"
19#include "base/command_line.h"
20#include "base/debug/debug_on_start_win.h"
21#include "base/perftimer.h"
22#include "base/pickle.h"
23#include "base/test/perf_test_suite.h"
24#include "base/test/test_suite.h"
25#include "base/threading/thread.h"
26#include "base/time.h"
27#include "ipc/ipc_descriptors.h"
28#include "ipc/ipc_channel.h"
29#include "ipc/ipc_channel_proxy.h"
30#include "ipc/ipc_message_utils.h"
31#include "ipc/ipc_multiprocess_test.h"
32#include "ipc/ipc_sender.h"
33#include "ipc/ipc_switches.h"
34#include "ipc/ipc_test_base.h"
35#include "testing/multiprocess_func_list.h"
36
viettrungluu@chromium.org7ca19132013-01-12 05:56:22 +090037namespace {
38
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090039const size_t kLongMessageStringNumBytes = 50000;
40
41class IPCChannelTest : public IPCTestBase {
42};
43
44TEST_F(IPCChannelTest, BasicMessageTest) {
45 int v1 = 10;
46 std::string v2("foobar");
47 std::wstring v3(L"hello world");
48
49 IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
50 EXPECT_TRUE(m.WriteInt(v1));
51 EXPECT_TRUE(m.WriteString(v2));
52 EXPECT_TRUE(m.WriteWString(v3));
53
54 PickleIterator iter(m);
55
56 int vi;
57 std::string vs;
58 std::wstring vw;
59
60 EXPECT_TRUE(m.ReadInt(&iter, &vi));
61 EXPECT_EQ(v1, vi);
62
63 EXPECT_TRUE(m.ReadString(&iter, &vs));
64 EXPECT_EQ(v2, vs);
65
66 EXPECT_TRUE(m.ReadWString(&iter, &vw));
67 EXPECT_EQ(v3, vw);
68
69 // should fail
70 EXPECT_FALSE(m.ReadInt(&iter, &vi));
71 EXPECT_FALSE(m.ReadString(&iter, &vs));
72 EXPECT_FALSE(m.ReadWString(&iter, &vw));
73}
74
75static void Send(IPC::Sender* sender, const char* text) {
76 static int message_index = 0;
77
78 IPC::Message* message = new IPC::Message(0,
79 2,
80 IPC::Message::PRIORITY_NORMAL);
81 message->WriteInt(message_index++);
82 message->WriteString(std::string(text));
83
84 // Make sure we can handle large messages.
85 char junk[kLongMessageStringNumBytes];
86 memset(junk, 'a', sizeof(junk)-1);
87 junk[sizeof(junk)-1] = 0;
88 message->WriteString(std::string(junk));
89
90 // DEBUG: printf("[%u] sending message [%s]\n", GetCurrentProcessId(), text);
91 sender->Send(message);
92}
93
94class MyChannelListener : public IPC::Listener {
95 public:
96 virtual bool OnMessageReceived(const IPC::Message& message) {
97 PickleIterator iter(message);
98
99 int ignored;
100 EXPECT_TRUE(iter.ReadInt(&ignored));
101 std::string data;
102 EXPECT_TRUE(iter.ReadString(&data));
103 std::string big_string;
104 EXPECT_TRUE(iter.ReadString(&big_string));
105 EXPECT_EQ(kLongMessageStringNumBytes - 1, big_string.length());
106
107
108 if (--messages_left_ == 0) {
109 MessageLoop::current()->Quit();
110 } else {
111 Send(sender_, "Foo");
112 }
113 return true;
114 }
115
116 virtual void OnChannelError() {
117 // There is a race when closing the channel so the last message may be lost.
118 EXPECT_LE(messages_left_, 1);
119 MessageLoop::current()->Quit();
120 }
121
122 void Init(IPC::Sender* s) {
123 sender_ = s;
124 messages_left_ = 50;
125 }
126
127 private:
128 IPC::Sender* sender_;
129 int messages_left_;
130};
131
132TEST_F(IPCChannelTest, ChannelTest) {
133 MyChannelListener channel_listener;
134 // Setup IPC channel.
135 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
136 &channel_listener);
137 ASSERT_TRUE(chan.Connect());
138
139 channel_listener.Init(&chan);
140
141 base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, &chan);
142 ASSERT_TRUE(process_handle);
143
144 Send(&chan, "hello from parent");
145
146 // Run message loop.
147 MessageLoop::current()->Run();
148
149 // Close Channel so client gets its OnChannelError() callback fired.
150 chan.Close();
151
152 // Cleanup child process.
153 EXPECT_TRUE(base::WaitForSingleProcess(
154 process_handle, base::TimeDelta::FromSeconds(5)));
155 base::CloseProcessHandle(process_handle);
156}
157
158#if defined(OS_WIN)
159TEST_F(IPCChannelTest, ChannelTestExistingPipe) {
160 MyChannelListener channel_listener;
161 // Setup IPC channel with existing pipe. Specify name in Chrome format.
162 std::string name("\\\\.\\pipe\\chrome.");
163 name.append(kTestClientChannel);
164 const DWORD open_mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
165 FILE_FLAG_FIRST_PIPE_INSTANCE;
166 HANDLE pipe = CreateNamedPipeA(name.c_str(),
167 open_mode,
168 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
169 1,
170 4096,
171 4096,
172 5000,
173 NULL);
174 IPC::Channel chan(IPC::ChannelHandle(pipe), IPC::Channel::MODE_SERVER,
175 &channel_listener);
176 // Channel will duplicate the handle.
177 CloseHandle(pipe);
178 ASSERT_TRUE(chan.Connect());
179
180 channel_listener.Init(&chan);
181
182 base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, &chan);
183 ASSERT_TRUE(process_handle);
184
185 Send(&chan, "hello from parent");
186
187 // Run message loop.
188 MessageLoop::current()->Run();
189
190 // Close Channel so client gets its OnChannelError() callback fired.
191 chan.Close();
192
193 // Cleanup child process.
194 EXPECT_TRUE(base::WaitForSingleProcess(
195 process_handle, base::TimeDelta::FromSeconds(5)));
196 base::CloseProcessHandle(process_handle);
197}
198#endif // defined (OS_WIN)
199
200TEST_F(IPCChannelTest, ChannelProxyTest) {
201 MyChannelListener channel_listener;
202
203 // The thread needs to out-live the ChannelProxy.
204 base::Thread thread("ChannelProxyTestServer");
205 base::Thread::Options options;
206 options.message_loop_type = MessageLoop::TYPE_IO;
207 thread.StartWithOptions(options);
208 {
209 // setup IPC channel proxy
210 IPC::ChannelProxy chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
211 &channel_listener, thread.message_loop_proxy());
212
213 channel_listener.Init(&chan);
214
215#if defined(OS_WIN)
216 base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, NULL);
217#elif defined(OS_POSIX)
218 bool debug_on_start = CommandLine::ForCurrentProcess()->HasSwitch(
219 switches::kDebugChildren);
220 base::FileHandleMappingVector fds_to_map;
221 const int ipcfd = chan.GetClientFileDescriptor();
222 if (ipcfd > -1) {
223 fds_to_map.push_back(std::pair<int, int>(ipcfd, kPrimaryIPCChannel + 3));
224 }
225
226 base::ProcessHandle process_handle = MultiProcessTest::SpawnChild(
227 "RunTestClient",
228 fds_to_map,
229 debug_on_start);
230#endif // defined(OS_POSIX)
231
232 ASSERT_TRUE(process_handle);
233
234 Send(&chan, "hello from parent");
235
236 // run message loop
237 MessageLoop::current()->Run();
238
239 // cleanup child process
240 EXPECT_TRUE(base::WaitForSingleProcess(
241 process_handle, base::TimeDelta::FromSeconds(5)));
242 base::CloseProcessHandle(process_handle);
243 }
244 thread.Stop();
245}
246
247class ChannelListenerWithOnConnectedSend : public IPC::Listener {
248 public:
249 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
250 SendNextMessage();
251 }
252
253 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
254 PickleIterator iter(message);
255
256 int ignored;
257 EXPECT_TRUE(iter.ReadInt(&ignored));
258 std::string data;
259 EXPECT_TRUE(iter.ReadString(&data));
260 std::string big_string;
261 EXPECT_TRUE(iter.ReadString(&big_string));
262 EXPECT_EQ(kLongMessageStringNumBytes - 1, big_string.length());
263 SendNextMessage();
264 return true;
265 }
266
267 virtual void OnChannelError() OVERRIDE {
268 // There is a race when closing the channel so the last message may be lost.
269 EXPECT_LE(messages_left_, 1);
270 MessageLoop::current()->Quit();
271 }
272
273 void Init(IPC::Sender* s) {
274 sender_ = s;
275 messages_left_ = 50;
276 }
277
278 private:
279 void SendNextMessage() {
280 if (--messages_left_ == 0) {
281 MessageLoop::current()->Quit();
282 } else {
283 Send(sender_, "Foo");
284 }
285 }
286
287 IPC::Sender* sender_;
288 int messages_left_;
289};
290
291#if defined(OS_WIN)
292// Acting flakey in Windows. http://crbug.com/129595
293#define MAYBE_SendMessageInChannelConnected DISABLED_SendMessageInChannelConnected
294#else
295#define MAYBE_SendMessageInChannelConnected SendMessageInChannelConnected
296#endif
297TEST_F(IPCChannelTest, MAYBE_SendMessageInChannelConnected) {
298 // This tests the case of a listener sending back an event in it's
299 // OnChannelConnected handler.
300
301 ChannelListenerWithOnConnectedSend channel_listener;
302 // Setup IPC channel.
303 IPC::Channel channel(kTestClientChannel, IPC::Channel::MODE_SERVER,
304 &channel_listener);
305 channel_listener.Init(&channel);
306 ASSERT_TRUE(channel.Connect());
307
308 base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, &channel);
309 ASSERT_TRUE(process_handle);
310
311 Send(&channel, "hello from parent");
312
313 // Run message loop.
314 MessageLoop::current()->Run();
315
316 // Close Channel so client gets its OnChannelError() callback fired.
317 channel.Close();
318
319 // Cleanup child process.
320 EXPECT_TRUE(base::WaitForSingleProcess(
321 process_handle, base::TimeDelta::FromSeconds(5)));
322 base::CloseProcessHandle(process_handle);
323}
324
325MULTIPROCESS_IPC_TEST_MAIN(RunTestClient) {
326 MessageLoopForIO main_message_loop;
327 MyChannelListener channel_listener;
328
329 // setup IPC channel
330 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_CLIENT,
331 &channel_listener);
332 CHECK(chan.Connect());
333 channel_listener.Init(&chan);
334 Send(&chan, "hello from child");
335 // run message loop
336 MessageLoop::current()->Run();
337 return 0;
338}
viettrungluu@chromium.org7ca19132013-01-12 05:56:22 +0900339
340} // namespace