blob: 076353302fc4671d70a81ba6d81ccde5659bd401 [file] [log] [blame]
morrita@chromium.org15996aa2014-08-05 08:44:17 +09001// Copyright 2014 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 "ipc/mojo/ipc_channel_mojo.h"
6
7#include "base/base_paths.h"
8#include "base/files/file.h"
9#include "base/message_loop/message_loop.h"
10#include "base/path_service.h"
11#include "base/pickle.h"
12#include "base/threading/thread.h"
13#include "ipc/ipc_message.h"
14#include "ipc/ipc_test_base.h"
15#include "ipc/ipc_test_channel_listener.h"
morrita7c48ab82014-09-24 06:16:00 +090016#include "ipc/mojo/ipc_channel_mojo_host.h"
morritafa3ab752014-09-16 12:20:48 +090017#include "ipc/mojo/ipc_channel_mojo_readers.h"
morrita@chromium.org15996aa2014-08-05 08:44:17 +090018
19#if defined(OS_POSIX)
20#include "base/file_descriptor_posix.h"
21#endif
22
23namespace {
24
25class ListenerThatExpectsOK : public IPC::Listener {
26 public:
morrita@chromium.orge2bbe782014-08-09 06:45:13 +090027 ListenerThatExpectsOK()
28 : received_ok_(false) {}
morrita@chromium.org15996aa2014-08-05 08:44:17 +090029
30 virtual ~ListenerThatExpectsOK() {}
31
32 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
33 PickleIterator iter(message);
34 std::string should_be_ok;
35 EXPECT_TRUE(iter.ReadString(&should_be_ok));
36 EXPECT_EQ(should_be_ok, "OK");
morrita@chromium.orge2bbe782014-08-09 06:45:13 +090037 received_ok_ = true;
morrita@chromium.org15996aa2014-08-05 08:44:17 +090038 base::MessageLoop::current()->Quit();
39 return true;
40 }
41
42 virtual void OnChannelError() OVERRIDE {
morrita@chromium.orge2bbe782014-08-09 06:45:13 +090043 // The connection should be healthy while the listener is waiting
44 // message. An error can occur after that because the peer
45 // process dies.
46 DCHECK(received_ok_);
morrita@chromium.org15996aa2014-08-05 08:44:17 +090047 }
48
49 static void SendOK(IPC::Sender* sender) {
50 IPC::Message* message = new IPC::Message(
51 0, 2, IPC::Message::PRIORITY_NORMAL);
52 message->WriteString(std::string("OK"));
53 ASSERT_TRUE(sender->Send(message));
54 }
morrita@chromium.orge2bbe782014-08-09 06:45:13 +090055
56 private:
57 bool received_ok_;
morrita@chromium.org15996aa2014-08-05 08:44:17 +090058};
59
morrita@chromium.org15996aa2014-08-05 08:44:17 +090060class ChannelClient {
61 public:
62 explicit ChannelClient(IPC::Listener* listener, const char* name) {
morrita7c48ab82014-09-24 06:16:00 +090063 channel_ = IPC::ChannelMojo::Create(NULL,
64 IPCTestBase::GetChannelName(name),
65 IPC::Channel::MODE_CLIENT,
66 listener);
morrita@chromium.org15996aa2014-08-05 08:44:17 +090067 }
68
69 void Connect() {
70 CHECK(channel_->Connect());
71 }
72
73 IPC::ChannelMojo* channel() const { return channel_.get(); }
74
75 private:
morrita@chromium.org15996aa2014-08-05 08:44:17 +090076 base::MessageLoopForIO main_message_loop_;
morrita7c48ab82014-09-24 06:16:00 +090077 scoped_ptr<IPC::ChannelMojo> channel_;
morrita@chromium.org15996aa2014-08-05 08:44:17 +090078};
79
80class IPCChannelMojoTest : public IPCTestBase {
morrita@chromium.org15996aa2014-08-05 08:44:17 +090081 protected:
morritaab779702014-09-10 04:35:24 +090082 virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
83 const IPC::ChannelHandle& handle,
84 base::TaskRunner* runner) OVERRIDE {
morrita7c48ab82014-09-24 06:16:00 +090085 host_.reset(new IPC::ChannelMojoHost(task_runner()));
86 return IPC::ChannelMojo::CreateServerFactory(host_.get(), handle);
morrita@chromium.org15996aa2014-08-05 08:44:17 +090087 }
morrita7c48ab82014-09-24 06:16:00 +090088
89 virtual bool DidStartClient() OVERRIDE {
90 bool ok = IPCTestBase::DidStartClient();
91 DCHECK(ok);
92 host_->OnClientLaunched(client_process());
93 return ok;
94 }
95
96 private:
97 scoped_ptr<IPC::ChannelMojoHost> host_;
morrita@chromium.org15996aa2014-08-05 08:44:17 +090098};
99
100
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900101class TestChannelListenerWithExtraExpectations
102 : public IPC::TestChannelListener {
103 public:
104 TestChannelListenerWithExtraExpectations()
105 : is_connected_called_(false) {
106 }
107
108 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
109 IPC::TestChannelListener::OnChannelConnected(peer_pid);
110 EXPECT_TRUE(base::kNullProcessId != peer_pid);
111 is_connected_called_ = true;
112 }
113
114 bool is_connected_called() const { return is_connected_called_; }
115
116 private:
117 bool is_connected_called_;
118};
119
120TEST_F(IPCChannelMojoTest, ConnectedFromClient) {
121 Init("IPCChannelMojoTestClient");
122
123 // Set up IPC channel and start client.
124 TestChannelListenerWithExtraExpectations listener;
morritaab779702014-09-10 04:35:24 +0900125 CreateChannel(&listener);
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900126 listener.Init(sender());
127 ASSERT_TRUE(ConnectChannel());
128 ASSERT_TRUE(StartClient());
129
130 IPC::TestChannelListener::SendOneMessage(
131 sender(), "hello from parent");
132
133 base::MessageLoop::current()->Run();
134 EXPECT_TRUE(base::kNullProcessId != this->channel()->GetPeerPID());
135
136 this->channel()->Close();
137
138 EXPECT_TRUE(WaitForClientShutdown());
139 EXPECT_TRUE(listener.is_connected_called());
140 EXPECT_TRUE(listener.HasSentAll());
141
142 DestroyChannel();
143}
144
145// A long running process that connects to us
146MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestClient) {
147 TestChannelListenerWithExtraExpectations listener;
148 ChannelClient client(&listener, "IPCChannelMojoTestClient");
149 client.Connect();
150 listener.Init(client.channel());
151
152 IPC::TestChannelListener::SendOneMessage(
153 client.channel(), "hello from child");
154 base::MessageLoop::current()->Run();
155 EXPECT_TRUE(listener.is_connected_called());
156 EXPECT_TRUE(listener.HasSentAll());
157
158 return 0;
159}
160
morritafa3ab752014-09-16 12:20:48 +0900161// Close given handle before use to simulate an error.
162class ErraticChannelMojo : public IPC::ChannelMojo {
163 public:
morrita7c48ab82014-09-24 06:16:00 +0900164 ErraticChannelMojo(IPC::ChannelMojoHost* host,
165 const IPC::ChannelHandle& channel_handle,
166 IPC::Channel::Mode mode,
167 IPC::Listener* listener,
168 scoped_refptr<base::TaskRunner> runner)
169 : ChannelMojo(host, channel_handle, mode, listener) {}
morritafa3ab752014-09-16 12:20:48 +0900170
171 virtual void OnConnected(mojo::ScopedMessagePipeHandle pipe) {
172 MojoClose(pipe.get().value());
173 OnConnected(pipe.Pass());
174 }
175};
176
177// Exists to create ErraticChannelMojo.
178class ErraticChannelFactory : public IPC::ChannelFactory {
179 public:
morrita7c48ab82014-09-24 06:16:00 +0900180 explicit ErraticChannelFactory(IPC::ChannelMojoHost* host,
181 const IPC::ChannelHandle& handle,
182 base::TaskRunner* runner)
183 : host_(host), handle_(handle), runner_(runner) {}
morritafa3ab752014-09-16 12:20:48 +0900184
185 virtual std::string GetName() const OVERRIDE {
186 return "";
187 }
188
189 virtual scoped_ptr<IPC::Channel> BuildChannel(
190 IPC::Listener* listener) OVERRIDE {
morrita7c48ab82014-09-24 06:16:00 +0900191 return scoped_ptr<IPC::Channel>(new ErraticChannelMojo(
192 host_, handle_, IPC::Channel::MODE_SERVER, listener, runner_));
morritafa3ab752014-09-16 12:20:48 +0900193 }
194
195 private:
morrita7c48ab82014-09-24 06:16:00 +0900196 IPC::ChannelMojoHost* host_;
morritafa3ab752014-09-16 12:20:48 +0900197 IPC::ChannelHandle handle_;
198 scoped_refptr<base::TaskRunner> runner_;
199};
200
201class ListenerExpectingErrors : public IPC::Listener {
202 public:
203 ListenerExpectingErrors()
204 : has_error_(false) {
205 }
206
207 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
208 return true;
209 }
210
211 virtual void OnChannelError() OVERRIDE {
212 has_error_ = true;
213 base::MessageLoop::current()->Quit();
214 }
215
216 bool has_error() const { return has_error_; }
217
218 private:
219 bool has_error_;
220};
221
222
223class IPCChannelMojoErrorTest : public IPCTestBase {
224 protected:
225 virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
226 const IPC::ChannelHandle& handle,
227 base::TaskRunner* runner) OVERRIDE {
morrita7c48ab82014-09-24 06:16:00 +0900228 host_.reset(new IPC::ChannelMojoHost(task_runner()));
morritafa3ab752014-09-16 12:20:48 +0900229 return scoped_ptr<IPC::ChannelFactory>(
morrita7c48ab82014-09-24 06:16:00 +0900230 new ErraticChannelFactory(host_.get(), handle, runner));
morritafa3ab752014-09-16 12:20:48 +0900231 }
morrita7c48ab82014-09-24 06:16:00 +0900232
233 virtual bool DidStartClient() OVERRIDE {
234 bool ok = IPCTestBase::DidStartClient();
235 DCHECK(ok);
236 host_->OnClientLaunched(client_process());
237 return ok;
238 }
239
240 private:
241 scoped_ptr<IPC::ChannelMojoHost> host_;
morritafa3ab752014-09-16 12:20:48 +0900242};
243
244class ListenerThatQuits : public IPC::Listener {
245 public:
246 ListenerThatQuits() {
247 }
248
249 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
250 return true;
251 }
252
253 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
254 base::MessageLoop::current()->Quit();
255 }
256};
257
258// A long running process that connects to us.
259MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoErraticTestClient) {
260 ListenerThatQuits listener;
261 ChannelClient client(&listener, "IPCChannelMojoErraticTestClient");
262 client.Connect();
263
264 base::MessageLoop::current()->Run();
265
266 return 0;
267}
268
269TEST_F(IPCChannelMojoErrorTest, SendFailWithPendingMessages) {
270 Init("IPCChannelMojoErraticTestClient");
271
272 // Set up IPC channel and start client.
273 ListenerExpectingErrors listener;
274 CreateChannel(&listener);
275 ASSERT_TRUE(ConnectChannel());
276
277 // This messages are queued as pending.
278 for (size_t i = 0; i < 2; ++i) {
279 IPC::TestChannelListener::SendOneMessage(
280 sender(), "hello from parent");
281 }
282
283 ASSERT_TRUE(StartClient());
284 base::MessageLoop::current()->Run();
285
286 this->channel()->Close();
287
288 EXPECT_TRUE(WaitForClientShutdown());
289 EXPECT_TRUE(listener.has_error());
290
291 DestroyChannel();
292}
293
294
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900295#if defined(OS_POSIX)
296class ListenerThatExpectsFile : public IPC::Listener {
297 public:
298 ListenerThatExpectsFile()
299 : sender_(NULL) {}
300
301 virtual ~ListenerThatExpectsFile() {}
302
303 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
304 PickleIterator iter(message);
305 base::FileDescriptor desc;
306 EXPECT_TRUE(message.ReadFileDescriptor(&iter, &desc));
307 std::string content(GetSendingFileContent().size(), ' ');
308 base::File file(desc.fd);
309 file.Read(0, &content[0], content.size());
310 EXPECT_EQ(content, GetSendingFileContent());
311 base::MessageLoop::current()->Quit();
312 ListenerThatExpectsOK::SendOK(sender_);
313 return true;
314 }
315
316 virtual void OnChannelError() OVERRIDE {
317 NOTREACHED();
318 }
319
320 static std::string GetSendingFileContent() {
321 return "Hello";
322 }
323
324 static base::FilePath GetSendingFilePath() {
325 base::FilePath path;
326 bool ok = PathService::Get(base::DIR_CACHE, &path);
327 EXPECT_TRUE(ok);
328 return path.Append("ListenerThatExpectsFile.txt");
329 }
330
331 static void WriteAndSendFile(IPC::Sender* sender, base::File& file) {
332 std::string content = GetSendingFileContent();
333 file.WriteAtCurrentPos(content.data(), content.size());
334 file.Flush();
335 IPC::Message* message = new IPC::Message(
336 0, 2, IPC::Message::PRIORITY_NORMAL);
337 message->WriteFileDescriptor(
338 base::FileDescriptor(file.TakePlatformFile(), false));
339 ASSERT_TRUE(sender->Send(message));
340 }
341
342 void set_sender(IPC::Sender* sender) { sender_ = sender; }
343
344 private:
345 IPC::Sender* sender_;
346};
347
348
349TEST_F(IPCChannelMojoTest, SendPlatformHandle) {
350 Init("IPCChannelMojoTestSendPlatformHandleClient");
351
352 ListenerThatExpectsOK listener;
morritaab779702014-09-10 04:35:24 +0900353 CreateChannel(&listener);
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900354 ASSERT_TRUE(ConnectChannel());
355 ASSERT_TRUE(StartClient());
356
357 base::File file(ListenerThatExpectsFile::GetSendingFilePath(),
358 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
359 base::File::FLAG_READ);
360 ListenerThatExpectsFile::WriteAndSendFile(channel(), file);
361 base::MessageLoop::current()->Run();
362
363 this->channel()->Close();
364
365 EXPECT_TRUE(WaitForClientShutdown());
366 DestroyChannel();
367}
368
369MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestSendPlatformHandleClient) {
370 ListenerThatExpectsFile listener;
371 ChannelClient client(
372 &listener, "IPCChannelMojoTestSendPlatformHandleClient");
373 client.Connect();
374 listener.set_sender(client.channel());
375
376 base::MessageLoop::current()->Run();
377
378 return 0;
379}
380#endif
381
382} // namespace