1 // 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.
5 #include "ipc/mojo/ipc_channel_mojo.h"
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 #include "ipc/mojo/ipc_channel_mojo_host.h"
17 #include "ipc/mojo/ipc_channel_mojo_readers.h"
20 #include "base/file_descriptor_posix.h"
25 class ListenerThatExpectsOK : public IPC::Listener {
27 ListenerThatExpectsOK()
28 : received_ok_(false) {}
30 virtual ~ListenerThatExpectsOK() {}
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");
38 base::MessageLoop::current()->Quit();
42 virtual void OnChannelError() OVERRIDE {
43 // The connection should be healthy while the listener is waiting
44 // message. An error can occur after that because the peer
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));
62 explicit ChannelClient(IPC::Listener* listener, const char* name) {
63 channel_ = IPC::ChannelMojo::Create(NULL,
64 IPCTestBase::GetChannelName(name),
65 IPC::Channel::MODE_CLIENT,
70 CHECK(channel_->Connect());
73 IPC::ChannelMojo* channel() const { return channel_.get(); }
76 base::MessageLoopForIO main_message_loop_;
77 scoped_ptr<IPC::ChannelMojo> channel_;
80 class IPCChannelMojoTest : public IPCTestBase {
82 virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
83 const IPC::ChannelHandle& handle,
84 base::TaskRunner* runner) OVERRIDE {
85 host_.reset(new IPC::ChannelMojoHost(task_runner()));
86 return IPC::ChannelMojo::CreateServerFactory(host_->channel_delegate(),
90 virtual bool DidStartClient() OVERRIDE {
91 bool ok = IPCTestBase::DidStartClient();
93 host_->OnClientLaunched(client_process());
98 scoped_ptr<IPC::ChannelMojoHost> host_;
102 class TestChannelListenerWithExtraExpectations
103 : public IPC::TestChannelListener {
105 TestChannelListenerWithExtraExpectations()
106 : is_connected_called_(false) {
109 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
110 IPC::TestChannelListener::OnChannelConnected(peer_pid);
111 EXPECT_TRUE(base::kNullProcessId != peer_pid);
112 is_connected_called_ = true;
115 bool is_connected_called() const { return is_connected_called_; }
118 bool is_connected_called_;
121 TEST_F(IPCChannelMojoTest, ConnectedFromClient) {
122 Init("IPCChannelMojoTestClient");
124 // Set up IPC channel and start client.
125 TestChannelListenerWithExtraExpectations listener;
126 CreateChannel(&listener);
127 listener.Init(sender());
128 ASSERT_TRUE(ConnectChannel());
129 ASSERT_TRUE(StartClient());
131 IPC::TestChannelListener::SendOneMessage(
132 sender(), "hello from parent");
134 base::MessageLoop::current()->Run();
135 EXPECT_TRUE(base::kNullProcessId != this->channel()->GetPeerPID());
137 this->channel()->Close();
139 EXPECT_TRUE(WaitForClientShutdown());
140 EXPECT_TRUE(listener.is_connected_called());
141 EXPECT_TRUE(listener.HasSentAll());
146 // A long running process that connects to us
147 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestClient) {
148 TestChannelListenerWithExtraExpectations listener;
149 ChannelClient client(&listener, "IPCChannelMojoTestClient");
151 listener.Init(client.channel());
153 IPC::TestChannelListener::SendOneMessage(
154 client.channel(), "hello from child");
155 base::MessageLoop::current()->Run();
156 EXPECT_TRUE(listener.is_connected_called());
157 EXPECT_TRUE(listener.HasSentAll());
162 class ListenerExpectingErrors : public IPC::Listener {
164 ListenerExpectingErrors()
165 : has_error_(false) {
168 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
169 base::MessageLoop::current()->Quit();
172 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
176 virtual void OnChannelError() OVERRIDE {
178 base::MessageLoop::current()->Quit();
181 bool has_error() const { return has_error_; }
188 class IPCChannelMojoErrorTest : public IPCTestBase {
190 virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
191 const IPC::ChannelHandle& handle,
192 base::TaskRunner* runner) OVERRIDE {
193 host_.reset(new IPC::ChannelMojoHost(task_runner()));
194 return IPC::ChannelMojo::CreateServerFactory(host_->channel_delegate(),
198 virtual bool DidStartClient() OVERRIDE {
199 bool ok = IPCTestBase::DidStartClient();
201 host_->OnClientLaunched(client_process());
206 scoped_ptr<IPC::ChannelMojoHost> host_;
209 class ListenerThatQuits : public IPC::Listener {
211 ListenerThatQuits() {
214 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
218 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
219 base::MessageLoop::current()->Quit();
223 // A long running process that connects to us.
224 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoErraticTestClient) {
225 ListenerThatQuits listener;
226 ChannelClient client(&listener, "IPCChannelMojoErraticTestClient");
229 base::MessageLoop::current()->Run();
234 TEST_F(IPCChannelMojoErrorTest, SendFailWithPendingMessages) {
235 Init("IPCChannelMojoErraticTestClient");
237 // Set up IPC channel and start client.
238 ListenerExpectingErrors listener;
239 CreateChannel(&listener);
240 ASSERT_TRUE(ConnectChannel());
242 // This matches a value in mojo/system/constants.h
243 const int kMaxMessageNumBytes = 4 * 1024 * 1024;
244 std::string overly_large_data(kMaxMessageNumBytes, '*');
245 // This messages are queued as pending.
246 for (size_t i = 0; i < 10; ++i) {
247 IPC::TestChannelListener::SendOneMessage(
248 sender(), overly_large_data.c_str());
251 ASSERT_TRUE(StartClient());
252 base::MessageLoop::current()->Run();
254 this->channel()->Close();
256 EXPECT_TRUE(WaitForClientShutdown());
257 EXPECT_TRUE(listener.has_error());
263 #if defined(OS_POSIX)
264 class ListenerThatExpectsFile : public IPC::Listener {
266 ListenerThatExpectsFile()
269 virtual ~ListenerThatExpectsFile() {}
271 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
272 PickleIterator iter(message);
275 EXPECT_TRUE(message.ReadFile(&iter, &fd));
276 base::File file(fd.release());
277 std::string content(GetSendingFileContent().size(), ' ');
278 file.Read(0, &content[0], content.size());
279 EXPECT_EQ(content, GetSendingFileContent());
280 base::MessageLoop::current()->Quit();
281 ListenerThatExpectsOK::SendOK(sender_);
285 virtual void OnChannelError() OVERRIDE {
289 static std::string GetSendingFileContent() {
293 static base::FilePath GetSendingFilePath() {
295 bool ok = PathService::Get(base::DIR_CACHE, &path);
297 return path.Append("ListenerThatExpectsFile.txt");
300 static void WriteAndSendFile(IPC::Sender* sender, base::File& file) {
301 std::string content = GetSendingFileContent();
302 file.WriteAtCurrentPos(content.data(), content.size());
304 IPC::Message* message = new IPC::Message(
305 0, 2, IPC::Message::PRIORITY_NORMAL);
306 message->WriteFile(base::ScopedFD(file.TakePlatformFile()));
307 ASSERT_TRUE(sender->Send(message));
310 void set_sender(IPC::Sender* sender) { sender_ = sender; }
313 IPC::Sender* sender_;
317 TEST_F(IPCChannelMojoTest, SendPlatformHandle) {
318 Init("IPCChannelMojoTestSendPlatformHandleClient");
320 ListenerThatExpectsOK listener;
321 CreateChannel(&listener);
322 ASSERT_TRUE(ConnectChannel());
323 ASSERT_TRUE(StartClient());
325 base::File file(ListenerThatExpectsFile::GetSendingFilePath(),
326 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
327 base::File::FLAG_READ);
328 ListenerThatExpectsFile::WriteAndSendFile(channel(), file);
329 base::MessageLoop::current()->Run();
331 this->channel()->Close();
333 EXPECT_TRUE(WaitForClientShutdown());
337 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestSendPlatformHandleClient) {
338 ListenerThatExpectsFile listener;
339 ChannelClient client(
340 &listener, "IPCChannelMojoTestSendPlatformHandleClient");
342 listener.set_sender(client.channel());
344 base::MessageLoop::current()->Run();