blob: 8ea828f4fb01f131848f65d431df9dfd4aad7d79 [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
morrita@chromium.org15996aa2014-08-05 08:44:17 +090058class ChannelClient {
59 public:
60 explicit ChannelClient(IPC::Listener* listener, const char* name) {
morrita@chromium.org15996aa2014-08-05 08:44:17 +090061 channel_ = IPC::ChannelMojo::Create(
morritaab779702014-09-10 04:35:24 +090062 IPCTestBase::GetChannelName(name), IPC::Channel::MODE_CLIENT, listener,
morrita@chromium.org15996aa2014-08-05 08:44:17 +090063 main_message_loop_.message_loop_proxy());
64 }
65
66 void Connect() {
67 CHECK(channel_->Connect());
68 }
69
70 IPC::ChannelMojo* channel() const { return channel_.get(); }
71
72 private:
73 scoped_ptr<IPC::ChannelMojo> channel_;
morrita@chromium.org15996aa2014-08-05 08:44:17 +090074 base::MessageLoopForIO main_message_loop_;
75};
76
77class IPCChannelMojoTest : public IPCTestBase {
morrita@chromium.org15996aa2014-08-05 08:44:17 +090078 protected:
morritaab779702014-09-10 04:35:24 +090079 virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
80 const IPC::ChannelHandle& handle,
81 base::TaskRunner* runner) OVERRIDE {
82 return IPC::ChannelMojo::CreateFactory(
83 handle, IPC::Channel::MODE_SERVER, runner);
morrita@chromium.org15996aa2014-08-05 08:44:17 +090084 }
morrita@chromium.org15996aa2014-08-05 08:44:17 +090085};
86
87
morrita@chromium.org15996aa2014-08-05 08:44:17 +090088class TestChannelListenerWithExtraExpectations
89 : public IPC::TestChannelListener {
90 public:
91 TestChannelListenerWithExtraExpectations()
92 : is_connected_called_(false) {
93 }
94
95 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
96 IPC::TestChannelListener::OnChannelConnected(peer_pid);
97 EXPECT_TRUE(base::kNullProcessId != peer_pid);
98 is_connected_called_ = true;
99 }
100
101 bool is_connected_called() const { return is_connected_called_; }
102
103 private:
104 bool is_connected_called_;
105};
106
107TEST_F(IPCChannelMojoTest, ConnectedFromClient) {
108 Init("IPCChannelMojoTestClient");
109
110 // Set up IPC channel and start client.
111 TestChannelListenerWithExtraExpectations listener;
morritaab779702014-09-10 04:35:24 +0900112 CreateChannel(&listener);
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900113 listener.Init(sender());
114 ASSERT_TRUE(ConnectChannel());
115 ASSERT_TRUE(StartClient());
116
117 IPC::TestChannelListener::SendOneMessage(
118 sender(), "hello from parent");
119
120 base::MessageLoop::current()->Run();
121 EXPECT_TRUE(base::kNullProcessId != this->channel()->GetPeerPID());
122
123 this->channel()->Close();
124
125 EXPECT_TRUE(WaitForClientShutdown());
126 EXPECT_TRUE(listener.is_connected_called());
127 EXPECT_TRUE(listener.HasSentAll());
128
129 DestroyChannel();
130}
131
132// A long running process that connects to us
133MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestClient) {
134 TestChannelListenerWithExtraExpectations listener;
135 ChannelClient client(&listener, "IPCChannelMojoTestClient");
136 client.Connect();
137 listener.Init(client.channel());
138
139 IPC::TestChannelListener::SendOneMessage(
140 client.channel(), "hello from child");
141 base::MessageLoop::current()->Run();
142 EXPECT_TRUE(listener.is_connected_called());
143 EXPECT_TRUE(listener.HasSentAll());
144
145 return 0;
146}
147
148#if defined(OS_POSIX)
149class ListenerThatExpectsFile : public IPC::Listener {
150 public:
151 ListenerThatExpectsFile()
152 : sender_(NULL) {}
153
154 virtual ~ListenerThatExpectsFile() {}
155
156 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
157 PickleIterator iter(message);
158 base::FileDescriptor desc;
159 EXPECT_TRUE(message.ReadFileDescriptor(&iter, &desc));
160 std::string content(GetSendingFileContent().size(), ' ');
161 base::File file(desc.fd);
162 file.Read(0, &content[0], content.size());
163 EXPECT_EQ(content, GetSendingFileContent());
164 base::MessageLoop::current()->Quit();
165 ListenerThatExpectsOK::SendOK(sender_);
166 return true;
167 }
168
169 virtual void OnChannelError() OVERRIDE {
170 NOTREACHED();
171 }
172
173 static std::string GetSendingFileContent() {
174 return "Hello";
175 }
176
177 static base::FilePath GetSendingFilePath() {
178 base::FilePath path;
179 bool ok = PathService::Get(base::DIR_CACHE, &path);
180 EXPECT_TRUE(ok);
181 return path.Append("ListenerThatExpectsFile.txt");
182 }
183
184 static void WriteAndSendFile(IPC::Sender* sender, base::File& file) {
185 std::string content = GetSendingFileContent();
186 file.WriteAtCurrentPos(content.data(), content.size());
187 file.Flush();
188 IPC::Message* message = new IPC::Message(
189 0, 2, IPC::Message::PRIORITY_NORMAL);
190 message->WriteFileDescriptor(
191 base::FileDescriptor(file.TakePlatformFile(), false));
192 ASSERT_TRUE(sender->Send(message));
193 }
194
195 void set_sender(IPC::Sender* sender) { sender_ = sender; }
196
197 private:
198 IPC::Sender* sender_;
199};
200
201
202TEST_F(IPCChannelMojoTest, SendPlatformHandle) {
203 Init("IPCChannelMojoTestSendPlatformHandleClient");
204
205 ListenerThatExpectsOK listener;
morritaab779702014-09-10 04:35:24 +0900206 CreateChannel(&listener);
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900207 ASSERT_TRUE(ConnectChannel());
208 ASSERT_TRUE(StartClient());
209
210 base::File file(ListenerThatExpectsFile::GetSendingFilePath(),
211 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
212 base::File::FLAG_READ);
213 ListenerThatExpectsFile::WriteAndSendFile(channel(), file);
214 base::MessageLoop::current()->Run();
215
216 this->channel()->Close();
217
218 EXPECT_TRUE(WaitForClientShutdown());
219 DestroyChannel();
220}
221
222MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestSendPlatformHandleClient) {
223 ListenerThatExpectsFile listener;
224 ChannelClient client(
225 &listener, "IPCChannelMojoTestSendPlatformHandleClient");
226 client.Connect();
227 listener.set_sender(client.channel());
228
229 base::MessageLoop::current()->Run();
230
231 return 0;
232}
233#endif
234
235} // namespace