blob: 2b9a954567fc32eb6d43149c6fa996794450253d [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"
morritafa3ab752014-09-16 12:20:48 +090016#include "ipc/mojo/ipc_channel_mojo_readers.h"
morrita@chromium.org15996aa2014-08-05 08:44:17 +090017
18#if defined(OS_POSIX)
19#include "base/file_descriptor_posix.h"
20#endif
21
22namespace {
23
24class ListenerThatExpectsOK : public IPC::Listener {
25 public:
morrita@chromium.orge2bbe782014-08-09 06:45:13 +090026 ListenerThatExpectsOK()
27 : received_ok_(false) {}
morrita@chromium.org15996aa2014-08-05 08:44:17 +090028
29 virtual ~ListenerThatExpectsOK() {}
30
31 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
32 PickleIterator iter(message);
33 std::string should_be_ok;
34 EXPECT_TRUE(iter.ReadString(&should_be_ok));
35 EXPECT_EQ(should_be_ok, "OK");
morrita@chromium.orge2bbe782014-08-09 06:45:13 +090036 received_ok_ = true;
morrita@chromium.org15996aa2014-08-05 08:44:17 +090037 base::MessageLoop::current()->Quit();
38 return true;
39 }
40
41 virtual void OnChannelError() OVERRIDE {
morrita@chromium.orge2bbe782014-08-09 06:45:13 +090042 // The connection should be healthy while the listener is waiting
43 // message. An error can occur after that because the peer
44 // process dies.
45 DCHECK(received_ok_);
morrita@chromium.org15996aa2014-08-05 08:44:17 +090046 }
47
48 static void SendOK(IPC::Sender* sender) {
49 IPC::Message* message = new IPC::Message(
50 0, 2, IPC::Message::PRIORITY_NORMAL);
51 message->WriteString(std::string("OK"));
52 ASSERT_TRUE(sender->Send(message));
53 }
morrita@chromium.orge2bbe782014-08-09 06:45:13 +090054
55 private:
56 bool received_ok_;
morrita@chromium.org15996aa2014-08-05 08:44:17 +090057};
58
morrita@chromium.org15996aa2014-08-05 08:44:17 +090059class ChannelClient {
60 public:
61 explicit ChannelClient(IPC::Listener* listener, const char* name) {
morrita@chromium.org15996aa2014-08-05 08:44:17 +090062 channel_ = IPC::ChannelMojo::Create(
morritaab779702014-09-10 04:35:24 +090063 IPCTestBase::GetChannelName(name), IPC::Channel::MODE_CLIENT, listener,
morrita@chromium.org15996aa2014-08-05 08:44:17 +090064 main_message_loop_.message_loop_proxy());
65 }
66
67 void Connect() {
68 CHECK(channel_->Connect());
69 }
70
71 IPC::ChannelMojo* channel() const { return channel_.get(); }
72
73 private:
74 scoped_ptr<IPC::ChannelMojo> channel_;
morrita@chromium.org15996aa2014-08-05 08:44:17 +090075 base::MessageLoopForIO main_message_loop_;
76};
77
78class IPCChannelMojoTest : public IPCTestBase {
morrita@chromium.org15996aa2014-08-05 08:44:17 +090079 protected:
morritaab779702014-09-10 04:35:24 +090080 virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
81 const IPC::ChannelHandle& handle,
82 base::TaskRunner* runner) OVERRIDE {
83 return IPC::ChannelMojo::CreateFactory(
84 handle, IPC::Channel::MODE_SERVER, runner);
morrita@chromium.org15996aa2014-08-05 08:44:17 +090085 }
morrita@chromium.org15996aa2014-08-05 08:44:17 +090086};
87
88
morrita@chromium.org15996aa2014-08-05 08:44:17 +090089class TestChannelListenerWithExtraExpectations
90 : public IPC::TestChannelListener {
91 public:
92 TestChannelListenerWithExtraExpectations()
93 : is_connected_called_(false) {
94 }
95
96 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
97 IPC::TestChannelListener::OnChannelConnected(peer_pid);
98 EXPECT_TRUE(base::kNullProcessId != peer_pid);
99 is_connected_called_ = true;
100 }
101
102 bool is_connected_called() const { return is_connected_called_; }
103
104 private:
105 bool is_connected_called_;
106};
107
108TEST_F(IPCChannelMojoTest, ConnectedFromClient) {
109 Init("IPCChannelMojoTestClient");
110
111 // Set up IPC channel and start client.
112 TestChannelListenerWithExtraExpectations listener;
morritaab779702014-09-10 04:35:24 +0900113 CreateChannel(&listener);
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900114 listener.Init(sender());
115 ASSERT_TRUE(ConnectChannel());
116 ASSERT_TRUE(StartClient());
117
118 IPC::TestChannelListener::SendOneMessage(
119 sender(), "hello from parent");
120
121 base::MessageLoop::current()->Run();
122 EXPECT_TRUE(base::kNullProcessId != this->channel()->GetPeerPID());
123
124 this->channel()->Close();
125
126 EXPECT_TRUE(WaitForClientShutdown());
127 EXPECT_TRUE(listener.is_connected_called());
128 EXPECT_TRUE(listener.HasSentAll());
129
130 DestroyChannel();
131}
132
133// A long running process that connects to us
134MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestClient) {
135 TestChannelListenerWithExtraExpectations listener;
136 ChannelClient client(&listener, "IPCChannelMojoTestClient");
137 client.Connect();
138 listener.Init(client.channel());
139
140 IPC::TestChannelListener::SendOneMessage(
141 client.channel(), "hello from child");
142 base::MessageLoop::current()->Run();
143 EXPECT_TRUE(listener.is_connected_called());
144 EXPECT_TRUE(listener.HasSentAll());
145
146 return 0;
147}
148
morritafa3ab752014-09-16 12:20:48 +0900149// Close given handle before use to simulate an error.
150class ErraticChannelMojo : public IPC::ChannelMojo {
151 public:
152 ErraticChannelMojo(
153 const IPC::ChannelHandle& channel_handle,
154 IPC::Channel::Mode mode,
155 IPC::Listener* listener,
156 scoped_refptr<base::TaskRunner> runner)
157 : ChannelMojo(channel_handle, mode, listener, runner) {
158 }
159
160 virtual void OnConnected(mojo::ScopedMessagePipeHandle pipe) {
161 MojoClose(pipe.get().value());
162 OnConnected(pipe.Pass());
163 }
164};
165
166// Exists to create ErraticChannelMojo.
167class ErraticChannelFactory : public IPC::ChannelFactory {
168 public:
169 explicit ErraticChannelFactory(
170 const IPC::ChannelHandle& handle,
171 base::TaskRunner* runner)
172 : handle_(handle), runner_(runner) {
173 }
174
175 virtual std::string GetName() const OVERRIDE {
176 return "";
177 }
178
179 virtual scoped_ptr<IPC::Channel> BuildChannel(
180 IPC::Listener* listener) OVERRIDE {
181 return scoped_ptr<IPC::Channel>(
182 new ErraticChannelMojo(
183 handle_, IPC::Channel::MODE_SERVER, listener, runner_));
184 }
185
186 private:
187 IPC::ChannelHandle handle_;
188 scoped_refptr<base::TaskRunner> runner_;
189};
190
191class ListenerExpectingErrors : public IPC::Listener {
192 public:
193 ListenerExpectingErrors()
194 : has_error_(false) {
195 }
196
197 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
198 return true;
199 }
200
201 virtual void OnChannelError() OVERRIDE {
202 has_error_ = true;
203 base::MessageLoop::current()->Quit();
204 }
205
206 bool has_error() const { return has_error_; }
207
208 private:
209 bool has_error_;
210};
211
212
213class IPCChannelMojoErrorTest : public IPCTestBase {
214 protected:
215 virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
216 const IPC::ChannelHandle& handle,
217 base::TaskRunner* runner) OVERRIDE {
218 return scoped_ptr<IPC::ChannelFactory>(
219 new ErraticChannelFactory(handle, runner));
220 }
221};
222
223class ListenerThatQuits : public IPC::Listener {
224 public:
225 ListenerThatQuits() {
226 }
227
228 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
229 return true;
230 }
231
232 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
233 base::MessageLoop::current()->Quit();
234 }
235};
236
237// A long running process that connects to us.
238MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoErraticTestClient) {
239 ListenerThatQuits listener;
240 ChannelClient client(&listener, "IPCChannelMojoErraticTestClient");
241 client.Connect();
242
243 base::MessageLoop::current()->Run();
244
245 return 0;
246}
247
248TEST_F(IPCChannelMojoErrorTest, SendFailWithPendingMessages) {
249 Init("IPCChannelMojoErraticTestClient");
250
251 // Set up IPC channel and start client.
252 ListenerExpectingErrors listener;
253 CreateChannel(&listener);
254 ASSERT_TRUE(ConnectChannel());
255
256 // This messages are queued as pending.
257 for (size_t i = 0; i < 2; ++i) {
258 IPC::TestChannelListener::SendOneMessage(
259 sender(), "hello from parent");
260 }
261
262 ASSERT_TRUE(StartClient());
263 base::MessageLoop::current()->Run();
264
265 this->channel()->Close();
266
267 EXPECT_TRUE(WaitForClientShutdown());
268 EXPECT_TRUE(listener.has_error());
269
270 DestroyChannel();
271}
272
273
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900274#if defined(OS_POSIX)
275class ListenerThatExpectsFile : public IPC::Listener {
276 public:
277 ListenerThatExpectsFile()
278 : sender_(NULL) {}
279
280 virtual ~ListenerThatExpectsFile() {}
281
282 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
283 PickleIterator iter(message);
284 base::FileDescriptor desc;
285 EXPECT_TRUE(message.ReadFileDescriptor(&iter, &desc));
286 std::string content(GetSendingFileContent().size(), ' ');
287 base::File file(desc.fd);
288 file.Read(0, &content[0], content.size());
289 EXPECT_EQ(content, GetSendingFileContent());
290 base::MessageLoop::current()->Quit();
291 ListenerThatExpectsOK::SendOK(sender_);
292 return true;
293 }
294
295 virtual void OnChannelError() OVERRIDE {
296 NOTREACHED();
297 }
298
299 static std::string GetSendingFileContent() {
300 return "Hello";
301 }
302
303 static base::FilePath GetSendingFilePath() {
304 base::FilePath path;
305 bool ok = PathService::Get(base::DIR_CACHE, &path);
306 EXPECT_TRUE(ok);
307 return path.Append("ListenerThatExpectsFile.txt");
308 }
309
310 static void WriteAndSendFile(IPC::Sender* sender, base::File& file) {
311 std::string content = GetSendingFileContent();
312 file.WriteAtCurrentPos(content.data(), content.size());
313 file.Flush();
314 IPC::Message* message = new IPC::Message(
315 0, 2, IPC::Message::PRIORITY_NORMAL);
316 message->WriteFileDescriptor(
317 base::FileDescriptor(file.TakePlatformFile(), false));
318 ASSERT_TRUE(sender->Send(message));
319 }
320
321 void set_sender(IPC::Sender* sender) { sender_ = sender; }
322
323 private:
324 IPC::Sender* sender_;
325};
326
327
328TEST_F(IPCChannelMojoTest, SendPlatformHandle) {
329 Init("IPCChannelMojoTestSendPlatformHandleClient");
330
331 ListenerThatExpectsOK listener;
morritaab779702014-09-10 04:35:24 +0900332 CreateChannel(&listener);
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900333 ASSERT_TRUE(ConnectChannel());
334 ASSERT_TRUE(StartClient());
335
336 base::File file(ListenerThatExpectsFile::GetSendingFilePath(),
337 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
338 base::File::FLAG_READ);
339 ListenerThatExpectsFile::WriteAndSendFile(channel(), file);
340 base::MessageLoop::current()->Run();
341
342 this->channel()->Close();
343
344 EXPECT_TRUE(WaitForClientShutdown());
345 DestroyChannel();
346}
347
348MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestSendPlatformHandleClient) {
349 ListenerThatExpectsFile listener;
350 ChannelClient client(
351 &listener, "IPCChannelMojoTestSendPlatformHandleClient");
352 client.Connect();
353 listener.set_sender(client.channel());
354
355 base::MessageLoop::current()->Run();
356
357 return 0;
358}
359#endif
360
361} // namespace