blob: e1adecdf6ca6be778cb2891209d756aeb2ab0e95 [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 +0900161class ListenerExpectingErrors : public IPC::Listener {
162 public:
163 ListenerExpectingErrors()
164 : has_error_(false) {
165 }
166
morrita26b6d752014-09-25 08:38:44 +0900167 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
168 base::MessageLoop::current()->Quit();
169 }
170
morritafa3ab752014-09-16 12:20:48 +0900171 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
172 return true;
173 }
174
175 virtual void OnChannelError() OVERRIDE {
176 has_error_ = true;
177 base::MessageLoop::current()->Quit();
178 }
179
180 bool has_error() const { return has_error_; }
181
182 private:
183 bool has_error_;
184};
185
186
187class IPCChannelMojoErrorTest : public IPCTestBase {
188 protected:
189 virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
190 const IPC::ChannelHandle& handle,
191 base::TaskRunner* runner) OVERRIDE {
morrita7c48ab82014-09-24 06:16:00 +0900192 host_.reset(new IPC::ChannelMojoHost(task_runner()));
morrita26b6d752014-09-25 08:38:44 +0900193 return IPC::ChannelMojo::CreateServerFactory(host_.get(), handle);
morritafa3ab752014-09-16 12:20:48 +0900194 }
morrita7c48ab82014-09-24 06:16:00 +0900195
196 virtual bool DidStartClient() OVERRIDE {
197 bool ok = IPCTestBase::DidStartClient();
198 DCHECK(ok);
199 host_->OnClientLaunched(client_process());
200 return ok;
201 }
202
203 private:
204 scoped_ptr<IPC::ChannelMojoHost> host_;
morritafa3ab752014-09-16 12:20:48 +0900205};
206
207class ListenerThatQuits : public IPC::Listener {
208 public:
209 ListenerThatQuits() {
210 }
211
212 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
213 return true;
214 }
215
216 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
217 base::MessageLoop::current()->Quit();
218 }
219};
220
221// A long running process that connects to us.
222MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoErraticTestClient) {
223 ListenerThatQuits listener;
224 ChannelClient client(&listener, "IPCChannelMojoErraticTestClient");
225 client.Connect();
226
227 base::MessageLoop::current()->Run();
228
229 return 0;
230}
231
morrita26b6d752014-09-25 08:38:44 +0900232TEST_F(IPCChannelMojoErrorTest, SendFailWithPendingMessages) {
morritafa3ab752014-09-16 12:20:48 +0900233 Init("IPCChannelMojoErraticTestClient");
234
235 // Set up IPC channel and start client.
236 ListenerExpectingErrors listener;
237 CreateChannel(&listener);
238 ASSERT_TRUE(ConnectChannel());
239
morrita26b6d752014-09-25 08:38:44 +0900240 // This matches a value in mojo/system/constants.h
241 const int kMaxMessageNumBytes = 4 * 1024 * 1024;
242 std::string overly_large_data(kMaxMessageNumBytes, '*');
morritafa3ab752014-09-16 12:20:48 +0900243 // This messages are queued as pending.
morrita26b6d752014-09-25 08:38:44 +0900244 for (size_t i = 0; i < 10; ++i) {
morritafa3ab752014-09-16 12:20:48 +0900245 IPC::TestChannelListener::SendOneMessage(
morrita26b6d752014-09-25 08:38:44 +0900246 sender(), overly_large_data.c_str());
morritafa3ab752014-09-16 12:20:48 +0900247 }
248
249 ASSERT_TRUE(StartClient());
250 base::MessageLoop::current()->Run();
251
252 this->channel()->Close();
253
254 EXPECT_TRUE(WaitForClientShutdown());
255 EXPECT_TRUE(listener.has_error());
256
257 DestroyChannel();
258}
259
260
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900261#if defined(OS_POSIX)
262class ListenerThatExpectsFile : public IPC::Listener {
263 public:
264 ListenerThatExpectsFile()
265 : sender_(NULL) {}
266
267 virtual ~ListenerThatExpectsFile() {}
268
269 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
270 PickleIterator iter(message);
morritaab207252014-09-25 05:11:45 +0900271
272 base::ScopedFD fd;
273 EXPECT_TRUE(message.ReadFile(&iter, &fd));
274 base::File file(fd.release());
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900275 std::string content(GetSendingFileContent().size(), ' ');
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900276 file.Read(0, &content[0], content.size());
277 EXPECT_EQ(content, GetSendingFileContent());
278 base::MessageLoop::current()->Quit();
279 ListenerThatExpectsOK::SendOK(sender_);
280 return true;
281 }
282
283 virtual void OnChannelError() OVERRIDE {
284 NOTREACHED();
285 }
286
287 static std::string GetSendingFileContent() {
288 return "Hello";
289 }
290
291 static base::FilePath GetSendingFilePath() {
292 base::FilePath path;
293 bool ok = PathService::Get(base::DIR_CACHE, &path);
294 EXPECT_TRUE(ok);
295 return path.Append("ListenerThatExpectsFile.txt");
296 }
297
298 static void WriteAndSendFile(IPC::Sender* sender, base::File& file) {
299 std::string content = GetSendingFileContent();
300 file.WriteAtCurrentPos(content.data(), content.size());
301 file.Flush();
302 IPC::Message* message = new IPC::Message(
303 0, 2, IPC::Message::PRIORITY_NORMAL);
morritaab207252014-09-25 05:11:45 +0900304 message->WriteFile(base::ScopedFD(file.TakePlatformFile()));
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900305 ASSERT_TRUE(sender->Send(message));
306 }
307
308 void set_sender(IPC::Sender* sender) { sender_ = sender; }
309
310 private:
311 IPC::Sender* sender_;
312};
313
314
315TEST_F(IPCChannelMojoTest, SendPlatformHandle) {
316 Init("IPCChannelMojoTestSendPlatformHandleClient");
317
318 ListenerThatExpectsOK listener;
morritaab779702014-09-10 04:35:24 +0900319 CreateChannel(&listener);
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900320 ASSERT_TRUE(ConnectChannel());
321 ASSERT_TRUE(StartClient());
322
323 base::File file(ListenerThatExpectsFile::GetSendingFilePath(),
324 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
325 base::File::FLAG_READ);
326 ListenerThatExpectsFile::WriteAndSendFile(channel(), file);
327 base::MessageLoop::current()->Run();
328
329 this->channel()->Close();
330
331 EXPECT_TRUE(WaitForClientShutdown());
332 DestroyChannel();
333}
334
335MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestSendPlatformHandleClient) {
336 ListenerThatExpectsFile listener;
337 ChannelClient client(
338 &listener, "IPCChannelMojoTestSendPlatformHandleClient");
339 client.Connect();
340 listener.set_sender(client.channel());
341
342 base::MessageLoop::current()->Run();
343
344 return 0;
345}
346#endif
347
348} // namespace