blob: 2442afe34e9937cfc8d56a25364124c90a49f225 [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"
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
dchengef7721a2014-10-22 11:29:52 +090029 ~ListenerThatExpectsOK() override {}
morrita@chromium.org15996aa2014-08-05 08:44:17 +090030
dchengef7721a2014-10-22 11:29:52 +090031 bool OnMessageReceived(const IPC::Message& message) override {
morrita@chromium.org15996aa2014-08-05 08:44:17 +090032 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
dchengef7721a2014-10-22 11:29:52 +090041 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) {
morrita7c48ab82014-09-24 06:16:00 +090062 channel_ = IPC::ChannelMojo::Create(NULL,
63 IPCTestBase::GetChannelName(name),
64 IPC::Channel::MODE_CLIENT,
65 listener);
morrita@chromium.org15996aa2014-08-05 08:44:17 +090066 }
67
68 void Connect() {
69 CHECK(channel_->Connect());
70 }
71
72 IPC::ChannelMojo* channel() const { return channel_.get(); }
73
74 private:
morrita@chromium.org15996aa2014-08-05 08:44:17 +090075 base::MessageLoopForIO main_message_loop_;
morrita7c48ab82014-09-24 06:16:00 +090076 scoped_ptr<IPC::ChannelMojo> channel_;
morrita@chromium.org15996aa2014-08-05 08:44:17 +090077};
78
79class IPCChannelMojoTest : public IPCTestBase {
morrita@chromium.org15996aa2014-08-05 08:44:17 +090080 protected:
dchengef7721a2014-10-22 11:29:52 +090081 scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
morritaab779702014-09-10 04:35:24 +090082 const IPC::ChannelHandle& handle,
mostynbd41cdbb2014-10-07 16:17:16 +090083 base::TaskRunner* runner) override {
morrita7c48ab82014-09-24 06:16:00 +090084 host_.reset(new IPC::ChannelMojoHost(task_runner()));
morrita98b6e4a2014-09-26 12:20:48 +090085 return IPC::ChannelMojo::CreateServerFactory(host_->channel_delegate(),
86 handle);
morrita@chromium.org15996aa2014-08-05 08:44:17 +090087 }
morrita7c48ab82014-09-24 06:16:00 +090088
dchengef7721a2014-10-22 11:29:52 +090089 bool DidStartClient() override {
morrita7c48ab82014-09-24 06:16:00 +090090 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
dchengef7721a2014-10-22 11:29:52 +0900108 void OnChannelConnected(int32 peer_pid) override {
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900109 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 +0900161class ListenerExpectingErrors : public IPC::Listener {
162 public:
163 ListenerExpectingErrors()
164 : has_error_(false) {
165 }
166
dchengef7721a2014-10-22 11:29:52 +0900167 void OnChannelConnected(int32 peer_pid) override {
morrita26b6d752014-09-25 08:38:44 +0900168 base::MessageLoop::current()->Quit();
169 }
170
dchengef7721a2014-10-22 11:29:52 +0900171 bool OnMessageReceived(const IPC::Message& message) override { return true; }
morritafa3ab752014-09-16 12:20:48 +0900172
dchengef7721a2014-10-22 11:29:52 +0900173 void OnChannelError() override {
morritafa3ab752014-09-16 12:20:48 +0900174 has_error_ = true;
175 base::MessageLoop::current()->Quit();
176 }
177
178 bool has_error() const { return has_error_; }
179
180 private:
181 bool has_error_;
182};
183
184
185class IPCChannelMojoErrorTest : public IPCTestBase {
186 protected:
dchengef7721a2014-10-22 11:29:52 +0900187 scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
morritafa3ab752014-09-16 12:20:48 +0900188 const IPC::ChannelHandle& handle,
mostynbd41cdbb2014-10-07 16:17:16 +0900189 base::TaskRunner* runner) override {
morrita7c48ab82014-09-24 06:16:00 +0900190 host_.reset(new IPC::ChannelMojoHost(task_runner()));
morrita98b6e4a2014-09-26 12:20:48 +0900191 return IPC::ChannelMojo::CreateServerFactory(host_->channel_delegate(),
192 handle);
morritafa3ab752014-09-16 12:20:48 +0900193 }
morrita7c48ab82014-09-24 06:16:00 +0900194
dchengef7721a2014-10-22 11:29:52 +0900195 bool DidStartClient() override {
morrita7c48ab82014-09-24 06:16:00 +0900196 bool ok = IPCTestBase::DidStartClient();
197 DCHECK(ok);
198 host_->OnClientLaunched(client_process());
199 return ok;
200 }
201
202 private:
203 scoped_ptr<IPC::ChannelMojoHost> host_;
morritafa3ab752014-09-16 12:20:48 +0900204};
205
206class ListenerThatQuits : public IPC::Listener {
207 public:
208 ListenerThatQuits() {
209 }
210
dchengef7721a2014-10-22 11:29:52 +0900211 bool OnMessageReceived(const IPC::Message& message) override {
dcheng9b01d242014-10-22 03:02:42 +0900212 return true;
213 }
morritafa3ab752014-09-16 12:20:48 +0900214
dchengef7721a2014-10-22 11:29:52 +0900215 void OnChannelConnected(int32 peer_pid) override {
morritafa3ab752014-09-16 12:20:48 +0900216 base::MessageLoop::current()->Quit();
217 }
218};
219
220// A long running process that connects to us.
221MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoErraticTestClient) {
222 ListenerThatQuits listener;
223 ChannelClient client(&listener, "IPCChannelMojoErraticTestClient");
224 client.Connect();
225
226 base::MessageLoop::current()->Run();
227
228 return 0;
229}
230
morrita26b6d752014-09-25 08:38:44 +0900231TEST_F(IPCChannelMojoErrorTest, SendFailWithPendingMessages) {
morritafa3ab752014-09-16 12:20:48 +0900232 Init("IPCChannelMojoErraticTestClient");
233
234 // Set up IPC channel and start client.
235 ListenerExpectingErrors listener;
236 CreateChannel(&listener);
237 ASSERT_TRUE(ConnectChannel());
238
jamesr8dddfa22014-10-03 13:26:48 +0900239 // This matches a value in mojo/edk/system/constants.h
morrita26b6d752014-09-25 08:38:44 +0900240 const int kMaxMessageNumBytes = 4 * 1024 * 1024;
241 std::string overly_large_data(kMaxMessageNumBytes, '*');
morritafa3ab752014-09-16 12:20:48 +0900242 // This messages are queued as pending.
morrita26b6d752014-09-25 08:38:44 +0900243 for (size_t i = 0; i < 10; ++i) {
morritafa3ab752014-09-16 12:20:48 +0900244 IPC::TestChannelListener::SendOneMessage(
morrita26b6d752014-09-25 08:38:44 +0900245 sender(), overly_large_data.c_str());
morritafa3ab752014-09-16 12:20:48 +0900246 }
247
248 ASSERT_TRUE(StartClient());
249 base::MessageLoop::current()->Run();
250
251 this->channel()->Close();
252
253 EXPECT_TRUE(WaitForClientShutdown());
254 EXPECT_TRUE(listener.has_error());
255
256 DestroyChannel();
257}
258
morrita7767a0d2014-10-16 03:50:19 +0900259#if defined(OS_WIN)
260class IPCChannelMojoDeadHandleTest : public IPCTestBase {
261 protected:
262 virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
263 const IPC::ChannelHandle& handle,
264 base::TaskRunner* runner) override {
265 host_.reset(new IPC::ChannelMojoHost(task_runner()));
266 return IPC::ChannelMojo::CreateServerFactory(host_->channel_delegate(),
267 handle);
268 }
269
270 virtual bool DidStartClient() override {
271 IPCTestBase::DidStartClient();
272 base::ProcessHandle client = client_process();
273 // Forces GetFileHandleForProcess() fail. It happens occasionally
274 // in production, so we should exercise it somehow.
275 ::CloseHandle(client);
276 host_->OnClientLaunched(client);
277 return true;
278 }
279
280 private:
281 scoped_ptr<IPC::ChannelMojoHost> host_;
282};
283
284TEST_F(IPCChannelMojoDeadHandleTest, InvalidClientHandle) {
285 // Any client type is fine as it is going to be killed anyway.
286 Init("IPCChannelMojoTestDoNothingClient");
287
288 // Set up IPC channel and start client.
289 ListenerExpectingErrors listener;
290 CreateChannel(&listener);
291 ASSERT_TRUE(ConnectChannel());
292
293 ASSERT_TRUE(StartClient());
294 base::MessageLoop::current()->Run();
295
296 this->channel()->Close();
297
298 // WaitForClientShutdown() fails as client_hanadle() is already
299 // closed.
300 EXPECT_FALSE(WaitForClientShutdown());
301 EXPECT_TRUE(listener.has_error());
302
303 DestroyChannel();
304}
305
306MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestDoNothingClient) {
307 ListenerThatQuits listener;
308 ChannelClient client(&listener, "IPCChannelMojoTestDoNothingClient");
309 client.Connect();
310
311 // Quits without running the message loop as this client won't
312 // receive any messages from the server.
313
314 return 0;
315}
316#endif
morritafa3ab752014-09-16 12:20:48 +0900317
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900318#if defined(OS_POSIX)
319class ListenerThatExpectsFile : public IPC::Listener {
320 public:
321 ListenerThatExpectsFile()
322 : sender_(NULL) {}
323
dchengef7721a2014-10-22 11:29:52 +0900324 ~ListenerThatExpectsFile() override {}
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900325
dchengef7721a2014-10-22 11:29:52 +0900326 bool OnMessageReceived(const IPC::Message& message) override {
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900327 PickleIterator iter(message);
morritaab207252014-09-25 05:11:45 +0900328
329 base::ScopedFD fd;
330 EXPECT_TRUE(message.ReadFile(&iter, &fd));
331 base::File file(fd.release());
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900332 std::string content(GetSendingFileContent().size(), ' ');
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900333 file.Read(0, &content[0], content.size());
334 EXPECT_EQ(content, GetSendingFileContent());
335 base::MessageLoop::current()->Quit();
336 ListenerThatExpectsOK::SendOK(sender_);
337 return true;
338 }
339
dchengef7721a2014-10-22 11:29:52 +0900340 void OnChannelError() override {
dcheng9b01d242014-10-22 03:02:42 +0900341 NOTREACHED();
342 }
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900343
344 static std::string GetSendingFileContent() {
345 return "Hello";
346 }
347
348 static base::FilePath GetSendingFilePath() {
349 base::FilePath path;
350 bool ok = PathService::Get(base::DIR_CACHE, &path);
351 EXPECT_TRUE(ok);
352 return path.Append("ListenerThatExpectsFile.txt");
353 }
354
355 static void WriteAndSendFile(IPC::Sender* sender, base::File& file) {
356 std::string content = GetSendingFileContent();
357 file.WriteAtCurrentPos(content.data(), content.size());
358 file.Flush();
359 IPC::Message* message = new IPC::Message(
360 0, 2, IPC::Message::PRIORITY_NORMAL);
morritaab207252014-09-25 05:11:45 +0900361 message->WriteFile(base::ScopedFD(file.TakePlatformFile()));
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900362 ASSERT_TRUE(sender->Send(message));
363 }
364
365 void set_sender(IPC::Sender* sender) { sender_ = sender; }
366
367 private:
368 IPC::Sender* sender_;
369};
370
371
372TEST_F(IPCChannelMojoTest, SendPlatformHandle) {
373 Init("IPCChannelMojoTestSendPlatformHandleClient");
374
375 ListenerThatExpectsOK listener;
morritaab779702014-09-10 04:35:24 +0900376 CreateChannel(&listener);
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900377 ASSERT_TRUE(ConnectChannel());
378 ASSERT_TRUE(StartClient());
379
380 base::File file(ListenerThatExpectsFile::GetSendingFilePath(),
381 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
382 base::File::FLAG_READ);
383 ListenerThatExpectsFile::WriteAndSendFile(channel(), file);
384 base::MessageLoop::current()->Run();
385
386 this->channel()->Close();
387
388 EXPECT_TRUE(WaitForClientShutdown());
389 DestroyChannel();
390}
391
392MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestSendPlatformHandleClient) {
393 ListenerThatExpectsFile listener;
394 ChannelClient client(
395 &listener, "IPCChannelMojoTestSendPlatformHandleClient");
396 client.Connect();
397 listener.set_sender(client.channel());
398
399 base::MessageLoop::current()->Run();
400
401 return 0;
402}
403#endif
404
405} // namespace