blob: 21507bf214ba5b4831e8bcbd905b2f85047e8454 [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>
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +09009#endif
10
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090011#include <string>
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090012
viettrungluu@chromium.org00155942013-01-26 06:51:35 +090013#include "base/message_loop.h"
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090014#include "base/pickle.h"
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090015#include "base/threading/thread.h"
viettrungluu@chromium.org00155942013-01-26 06:51:35 +090016#include "ipc/ipc_message.h"
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090017#include "ipc/ipc_test_base.h"
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090018
viettrungluu@chromium.org7ca19132013-01-12 05:56:22 +090019namespace {
20
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090021const size_t kLongMessageStringNumBytes = 50000;
22
viettrungluu@chromium.org00155942013-01-26 06:51:35 +090023static void Send(IPC::Sender* sender, const char* text) {
24 static int message_index = 0;
25
26 IPC::Message* message = new IPC::Message(0,
27 2,
28 IPC::Message::PRIORITY_NORMAL);
29 message->WriteInt(message_index++);
30 message->WriteString(std::string(text));
31
32 // Make sure we can handle large messages.
33 char junk[kLongMessageStringNumBytes];
34 memset(junk, 'a', sizeof(junk)-1);
35 junk[sizeof(junk)-1] = 0;
36 message->WriteString(std::string(junk));
37
38 // DEBUG: printf("[%u] sending message [%s]\n", GetCurrentProcessId(), text);
39 sender->Send(message);
40}
41
42// A generic listener that expects messages of a certain type (see
43// OnMessageReceived()), and either sends a generic response or quits after the
44// 50th message (or on channel error).
45class GenericChannelListener : public IPC::Listener {
46 public:
47 GenericChannelListener() : sender_(NULL), messages_left_(50) {}
48 virtual ~GenericChannelListener() {}
49
50 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
51 PickleIterator iter(message);
52
53 int ignored;
54 EXPECT_TRUE(iter.ReadInt(&ignored));
55 std::string data;
56 EXPECT_TRUE(iter.ReadString(&data));
57 std::string big_string;
58 EXPECT_TRUE(iter.ReadString(&big_string));
59 EXPECT_EQ(kLongMessageStringNumBytes - 1, big_string.length());
60
61 SendNextMessage();
62 return true;
63 }
64
65 virtual void OnChannelError() OVERRIDE {
66 // There is a race when closing the channel so the last message may be lost.
67 EXPECT_LE(messages_left_, 1);
xhwang@chromium.org0b2c2a52013-05-01 05:55:03 +090068 base::MessageLoop::current()->Quit();
viettrungluu@chromium.org00155942013-01-26 06:51:35 +090069 }
70
71 void Init(IPC::Sender* s) {
72 sender_ = s;
73 }
74
75 protected:
76 void SendNextMessage() {
77 if (--messages_left_ <= 0)
xhwang@chromium.org0b2c2a52013-05-01 05:55:03 +090078 base::MessageLoop::current()->Quit();
viettrungluu@chromium.org00155942013-01-26 06:51:35 +090079 else
80 Send(sender_, "Foo");
81 }
82
83 private:
84 IPC::Sender* sender_;
85 int messages_left_;
86};
87
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090088class IPCChannelTest : public IPCTestBase {
89};
90
viettrungluu@chromium.org00155942013-01-26 06:51:35 +090091// TODO(viettrungluu): Move to a separate IPCMessageTest.
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090092TEST_F(IPCChannelTest, BasicMessageTest) {
93 int v1 = 10;
94 std::string v2("foobar");
95 std::wstring v3(L"hello world");
96
97 IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
98 EXPECT_TRUE(m.WriteInt(v1));
99 EXPECT_TRUE(m.WriteString(v2));
100 EXPECT_TRUE(m.WriteWString(v3));
101
102 PickleIterator iter(m);
103
104 int vi;
105 std::string vs;
106 std::wstring vw;
107
108 EXPECT_TRUE(m.ReadInt(&iter, &vi));
109 EXPECT_EQ(v1, vi);
110
111 EXPECT_TRUE(m.ReadString(&iter, &vs));
112 EXPECT_EQ(v2, vs);
113
114 EXPECT_TRUE(m.ReadWString(&iter, &vw));
115 EXPECT_EQ(v3, vw);
116
117 // should fail
118 EXPECT_FALSE(m.ReadInt(&iter, &vi));
119 EXPECT_FALSE(m.ReadString(&iter, &vs));
120 EXPECT_FALSE(m.ReadWString(&iter, &vw));
121}
122
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900123TEST_F(IPCChannelTest, ChannelTest) {
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900124 Init("GenericClient");
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900125
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900126 // Set up IPC channel and start client.
127 GenericChannelListener listener;
128 CreateChannel(&listener);
129 listener.Init(sender());
130 ASSERT_TRUE(ConnectChannel());
131 ASSERT_TRUE(StartClient());
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900132
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900133 Send(sender(), "hello from parent");
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900134
135 // Run message loop.
xhwang@chromium.org0b2c2a52013-05-01 05:55:03 +0900136 base::MessageLoop::current()->Run();
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900137
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900138 // Close the channel so the client's OnChannelError() gets fired.
139 channel()->Close();
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900140
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900141 EXPECT_TRUE(WaitForClientShutdown());
142 DestroyChannel();
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900143}
144
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900145// TODO(viettrungluu): Move to a separate IPCChannelWinTest.
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900146#if defined(OS_WIN)
147TEST_F(IPCChannelTest, ChannelTestExistingPipe) {
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900148 Init("GenericClient");
149
150 // Create pipe manually using the standard Chromium name and set up IPC
151 // channel.
152 GenericChannelListener listener;
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900153 std::string name("\\\\.\\pipe\\chrome.");
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900154 name.append(GetChannelName("GenericClient"));
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900155 HANDLE pipe = CreateNamedPipeA(name.c_str(),
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900156 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
157 FILE_FLAG_FIRST_PIPE_INSTANCE,
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900158 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
159 1,
160 4096,
161 4096,
162 5000,
163 NULL);
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900164 CreateChannelFromChannelHandle(IPC::ChannelHandle(pipe), &listener);
165 CloseHandle(pipe); // The channel duplicates the handle.
166 listener.Init(sender());
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900167
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900168 // Connect to channel and start client.
169 ASSERT_TRUE(ConnectChannel());
170 ASSERT_TRUE(StartClient());
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900171
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900172 Send(sender(), "hello from parent");
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900173
174 // Run message loop.
xhwang@chromium.org0b2c2a52013-05-01 05:55:03 +0900175 base::MessageLoop::current()->Run();
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900176
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900177 // Close the channel so the client's OnChannelError() gets fired.
178 channel()->Close();
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900179
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900180 EXPECT_TRUE(WaitForClientShutdown());
181 DestroyChannel();
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900182}
183#endif // defined (OS_WIN)
184
185TEST_F(IPCChannelTest, ChannelProxyTest) {
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900186 Init("GenericClient");
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900187
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900188 base::Thread thread("ChannelProxyTestServer");
189 base::Thread::Options options;
xhwang@chromium.org0b2c2a52013-05-01 05:55:03 +0900190 options.message_loop_type = base::MessageLoop::TYPE_IO;
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900191 thread.StartWithOptions(options);
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900192
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900193 // Set up IPC channel proxy.
194 GenericChannelListener listener;
195 CreateChannelProxy(&listener, thread.message_loop_proxy());
196 listener.Init(sender());
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900197
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900198 ASSERT_TRUE(StartClient());
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900199
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900200 Send(sender(), "hello from parent");
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900201
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900202 // Run message loop.
xhwang@chromium.org0b2c2a52013-05-01 05:55:03 +0900203 base::MessageLoop::current()->Run();
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900204
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900205 EXPECT_TRUE(WaitForClientShutdown());
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900206
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900207 // Destroy the channel proxy before shutting down the thread.
208 DestroyChannelProxy();
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900209 thread.Stop();
210}
211
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900212class ChannelListenerWithOnConnectedSend : public GenericChannelListener {
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900213 public:
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900214 ChannelListenerWithOnConnectedSend() {}
215 virtual ~ChannelListenerWithOnConnectedSend() {}
216
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900217 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
218 SendNextMessage();
219 }
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900220};
221
222#if defined(OS_WIN)
223// Acting flakey in Windows. http://crbug.com/129595
224#define MAYBE_SendMessageInChannelConnected DISABLED_SendMessageInChannelConnected
225#else
226#define MAYBE_SendMessageInChannelConnected SendMessageInChannelConnected
227#endif
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900228// This tests the case of a listener sending back an event in its
229// OnChannelConnected handler.
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900230TEST_F(IPCChannelTest, MAYBE_SendMessageInChannelConnected) {
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900231 Init("GenericClient");
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900232
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900233 // Set up IPC channel and start client.
234 ChannelListenerWithOnConnectedSend listener;
235 CreateChannel(&listener);
236 listener.Init(sender());
237 ASSERT_TRUE(ConnectChannel());
238 ASSERT_TRUE(StartClient());
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900239
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900240 Send(sender(), "hello from parent");
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900241
242 // Run message loop.
xhwang@chromium.org0b2c2a52013-05-01 05:55:03 +0900243 base::MessageLoop::current()->Run();
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900244
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900245 // Close the channel so the client's OnChannelError() gets fired.
246 channel()->Close();
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900247
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900248 EXPECT_TRUE(WaitForClientShutdown());
249 DestroyChannel();
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900250}
251
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900252MULTIPROCESS_IPC_TEST_CLIENT_MAIN(GenericClient) {
xhwang@chromium.org0b2c2a52013-05-01 05:55:03 +0900253 base::MessageLoopForIO main_message_loop;
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900254 GenericChannelListener listener;
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900255
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900256 // Set up IPC channel.
257 IPC::Channel channel(IPCTestBase::GetChannelName("GenericClient"),
258 IPC::Channel::MODE_CLIENT,
259 &listener);
260 CHECK(channel.Connect());
261 listener.Init(&channel);
262 Send(&channel, "hello from child");
263
xhwang@chromium.org0b2c2a52013-05-01 05:55:03 +0900264 base::MessageLoop::current()->Run();
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900265 return 0;
266}
viettrungluu@chromium.org7ca19132013-01-12 05:56:22 +0900267
268} // namespace