blob: 31578370399034a094fc188bc1bbe165181e7e1c [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"
16
17#if defined(OS_POSIX)
18#include "base/file_descriptor_posix.h"
19#endif
20
21namespace {
22
23class ListenerThatExpectsOK : public IPC::Listener {
24 public:
morrita@chromium.orge2bbe782014-08-09 06:45:13 +090025 ListenerThatExpectsOK()
26 : received_ok_(false) {}
morrita@chromium.org15996aa2014-08-05 08:44:17 +090027
28 virtual ~ListenerThatExpectsOK() {}
29
30 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
31 PickleIterator iter(message);
32 std::string should_be_ok;
33 EXPECT_TRUE(iter.ReadString(&should_be_ok));
34 EXPECT_EQ(should_be_ok, "OK");
morrita@chromium.orge2bbe782014-08-09 06:45:13 +090035 received_ok_ = true;
morrita@chromium.org15996aa2014-08-05 08:44:17 +090036 base::MessageLoop::current()->Quit();
37 return true;
38 }
39
40 virtual void OnChannelError() OVERRIDE {
morrita@chromium.orge2bbe782014-08-09 06:45:13 +090041 // The connection should be healthy while the listener is waiting
42 // message. An error can occur after that because the peer
43 // process dies.
44 DCHECK(received_ok_);
morrita@chromium.org15996aa2014-08-05 08:44:17 +090045 }
46
47 static void SendOK(IPC::Sender* sender) {
48 IPC::Message* message = new IPC::Message(
49 0, 2, IPC::Message::PRIORITY_NORMAL);
50 message->WriteString(std::string("OK"));
51 ASSERT_TRUE(sender->Send(message));
52 }
morrita@chromium.orge2bbe782014-08-09 06:45:13 +090053
54 private:
55 bool received_ok_;
morrita@chromium.org15996aa2014-08-05 08:44:17 +090056};
57
58class ListenerThatShouldBeNeverCalled : public IPC::Listener {
59 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
60 NOTREACHED();
61 return true;
62 }
63
64 virtual void OnChannelError() OVERRIDE {
65 NOTREACHED();
66 }
67
68 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
69 NOTREACHED();
70 }
71
72 virtual void OnBadMessageReceived(const IPC::Message& message) OVERRIDE {
73 NOTREACHED();
74 }
75};
76
77class ChannelClient {
78 public:
79 explicit ChannelClient(IPC::Listener* listener, const char* name) {
80 scoped_ptr<IPC::Channel> bootstrap(IPC::Channel::CreateClient(
81 IPCTestBase::GetChannelName(name),
82 &never_called_));
83 channel_ = IPC::ChannelMojo::Create(
84 bootstrap.Pass(), IPC::Channel::MODE_CLIENT, listener,
85 main_message_loop_.message_loop_proxy());
86 }
87
88 void Connect() {
89 CHECK(channel_->Connect());
90 }
91
92 IPC::ChannelMojo* channel() const { return channel_.get(); }
93
94 private:
95 scoped_ptr<IPC::ChannelMojo> channel_;
96 ListenerThatShouldBeNeverCalled never_called_;
97 base::MessageLoopForIO main_message_loop_;
98};
99
100class IPCChannelMojoTest : public IPCTestBase {
101 public:
102 void CreateMojoChannel(IPC::Listener* listener);
103
104 protected:
105 virtual void SetUp() OVERRIDE {
106 IPCTestBase::SetUp();
107 }
108
109 ListenerThatShouldBeNeverCalled never_called_;
110};
111
112
113void IPCChannelMojoTest::CreateMojoChannel(IPC::Listener* listener) {
114 CreateChannel(&never_called_);
115 scoped_ptr<IPC::Channel> mojo_channel = IPC::ChannelMojo::Create(
116 ReleaseChannel(), IPC::Channel::MODE_SERVER, listener,
117 io_thread_task_runner()).PassAs<IPC::Channel>();
118 SetChannel(mojo_channel.PassAs<IPC::Channel>());
119}
120
121class TestChannelListenerWithExtraExpectations
122 : public IPC::TestChannelListener {
123 public:
124 TestChannelListenerWithExtraExpectations()
125 : is_connected_called_(false) {
126 }
127
128 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
129 IPC::TestChannelListener::OnChannelConnected(peer_pid);
130 EXPECT_TRUE(base::kNullProcessId != peer_pid);
131 is_connected_called_ = true;
132 }
133
134 bool is_connected_called() const { return is_connected_called_; }
135
136 private:
137 bool is_connected_called_;
138};
139
140TEST_F(IPCChannelMojoTest, ConnectedFromClient) {
141 Init("IPCChannelMojoTestClient");
142
143 // Set up IPC channel and start client.
144 TestChannelListenerWithExtraExpectations listener;
145 CreateMojoChannel(&listener);
146 listener.Init(sender());
147 ASSERT_TRUE(ConnectChannel());
148 ASSERT_TRUE(StartClient());
149
150 IPC::TestChannelListener::SendOneMessage(
151 sender(), "hello from parent");
152
153 base::MessageLoop::current()->Run();
154 EXPECT_TRUE(base::kNullProcessId != this->channel()->GetPeerPID());
155
156 this->channel()->Close();
157
158 EXPECT_TRUE(WaitForClientShutdown());
159 EXPECT_TRUE(listener.is_connected_called());
160 EXPECT_TRUE(listener.HasSentAll());
161
162 DestroyChannel();
163}
164
165// A long running process that connects to us
166MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestClient) {
167 TestChannelListenerWithExtraExpectations listener;
168 ChannelClient client(&listener, "IPCChannelMojoTestClient");
169 client.Connect();
170 listener.Init(client.channel());
171
172 IPC::TestChannelListener::SendOneMessage(
173 client.channel(), "hello from child");
174 base::MessageLoop::current()->Run();
175 EXPECT_TRUE(listener.is_connected_called());
176 EXPECT_TRUE(listener.HasSentAll());
177
178 return 0;
179}
180
181#if defined(OS_POSIX)
182class ListenerThatExpectsFile : public IPC::Listener {
183 public:
184 ListenerThatExpectsFile()
185 : sender_(NULL) {}
186
187 virtual ~ListenerThatExpectsFile() {}
188
189 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
190 PickleIterator iter(message);
191 base::FileDescriptor desc;
192 EXPECT_TRUE(message.ReadFileDescriptor(&iter, &desc));
193 std::string content(GetSendingFileContent().size(), ' ');
194 base::File file(desc.fd);
195 file.Read(0, &content[0], content.size());
196 EXPECT_EQ(content, GetSendingFileContent());
197 base::MessageLoop::current()->Quit();
198 ListenerThatExpectsOK::SendOK(sender_);
199 return true;
200 }
201
202 virtual void OnChannelError() OVERRIDE {
203 NOTREACHED();
204 }
205
206 static std::string GetSendingFileContent() {
207 return "Hello";
208 }
209
210 static base::FilePath GetSendingFilePath() {
211 base::FilePath path;
212 bool ok = PathService::Get(base::DIR_CACHE, &path);
213 EXPECT_TRUE(ok);
214 return path.Append("ListenerThatExpectsFile.txt");
215 }
216
217 static void WriteAndSendFile(IPC::Sender* sender, base::File& file) {
218 std::string content = GetSendingFileContent();
219 file.WriteAtCurrentPos(content.data(), content.size());
220 file.Flush();
221 IPC::Message* message = new IPC::Message(
222 0, 2, IPC::Message::PRIORITY_NORMAL);
223 message->WriteFileDescriptor(
224 base::FileDescriptor(file.TakePlatformFile(), false));
225 ASSERT_TRUE(sender->Send(message));
226 }
227
228 void set_sender(IPC::Sender* sender) { sender_ = sender; }
229
230 private:
231 IPC::Sender* sender_;
232};
233
234
235TEST_F(IPCChannelMojoTest, SendPlatformHandle) {
236 Init("IPCChannelMojoTestSendPlatformHandleClient");
237
238 ListenerThatExpectsOK listener;
239 CreateMojoChannel(&listener);
240 ASSERT_TRUE(ConnectChannel());
241 ASSERT_TRUE(StartClient());
242
243 base::File file(ListenerThatExpectsFile::GetSendingFilePath(),
244 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
245 base::File::FLAG_READ);
246 ListenerThatExpectsFile::WriteAndSendFile(channel(), file);
247 base::MessageLoop::current()->Run();
248
249 this->channel()->Close();
250
251 EXPECT_TRUE(WaitForClientShutdown());
252 DestroyChannel();
253}
254
255MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestSendPlatformHandleClient) {
256 ListenerThatExpectsFile listener;
257 ChannelClient client(
258 &listener, "IPCChannelMojoTestSendPlatformHandleClient");
259 client.Connect();
260 listener.set_sender(client.channel());
261
262 base::MessageLoop::current()->Run();
263
264 return 0;
265}
266#endif
267
268} // namespace