blob: 42a5dd25845edbe09180f0546fa8ffa0ff7cc589 [file] [log] [blame]
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001/*
Lalit Magantic6bccda2018-06-25 11:05:24 +01002 * Copyright (C) 2018 The Android Open Source Project
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "src/ipc/client_impl.h"
18
19#include <stdio.h>
20#include <unistd.h>
21
22#include <string>
23
Primiano Tucci2c5488f2019-06-01 03:27:28 +010024#include "perfetto/ext/base/file_utils.h"
25#include "perfetto/ext/base/temp_file.h"
26#include "perfetto/ext/base/unix_socket.h"
27#include "perfetto/ext/base/utils.h"
28#include "perfetto/ext/ipc/service_descriptor.h"
29#include "perfetto/ext/ipc/service_proxy.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000030#include "src/base/test/test_task_runner.h"
31#include "src/ipc/buffered_frame_deserializer.h"
Primiano Tuccib03ba362017-12-06 09:47:41 +000032#include "src/ipc/test/test_socket.h"
Primiano Tucci919ca1e2019-08-21 20:26:58 +020033#include "test/gtest_and_gmock.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000034
Primiano Tuccie8020f92019-11-26 13:24:01 +000035#include "src/ipc/test/client_unittest_messages.gen.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000036
37namespace perfetto {
38namespace ipc {
39namespace {
40
Primiano Tuccie8020f92019-11-26 13:24:01 +000041using ::perfetto::ipc::gen::ReplyProto;
42using ::perfetto::ipc::gen::RequestProto;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000043using ::testing::_;
44using ::testing::InSequence;
45using ::testing::Invoke;
46using ::testing::Mock;
47
Primiano Tuccib03ba362017-12-06 09:47:41 +000048constexpr char kSockName[] = TEST_SOCK_NAME("client_impl_unittest");
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000049
50// A fake ServiceProxy. This fakes the client-side class that would be
51// auto-generated from .proto-files.
52class FakeProxy : public ServiceProxy {
53 public:
54 FakeProxy(const char* service_name, ServiceProxy::EventListener* el)
55 : ServiceProxy(el), service_name_(service_name) {}
56
57 const ServiceDescriptor& GetDescriptor() override {
58 auto reply_decoder = [](const std::string& proto) {
59 std::unique_ptr<ProtoMessage> reply(new ReplyProto());
60 EXPECT_TRUE(reply->ParseFromString(proto));
61 return reply;
62 };
63 if (!descriptor_.service_name) {
64 descriptor_.service_name = service_name_;
Sami Kyostila2e366832017-12-06 12:17:24 +000065 descriptor_.methods.push_back(
66 {"FakeMethod1", nullptr, reply_decoder, nullptr});
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000067 }
68 return descriptor_;
69 }
70
71 const char* service_name_;
72 ServiceDescriptor descriptor_;
73};
74
75class MockEventListener : public ServiceProxy::EventListener {
76 public:
77 MOCK_METHOD0(OnConnect, void());
78 MOCK_METHOD0(OnDisconnect, void());
79};
80
81// A fake host implementation. Listens on |kSockName| and replies to IPC
82// metohds like a real one.
Florian Mayerf7f0def2018-09-27 13:59:24 +010083class FakeHost : public base::UnixSocket::EventListener {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000084 public:
85 struct FakeMethod {
86 MethodID id;
87 MOCK_METHOD2(OnInvoke,
88 void(const Frame::InvokeMethod&, Frame::InvokeMethodReply*));
89 }; // FakeMethod.
90
91 struct FakeService {
92 FakeMethod* AddFakeMethod(const std::string& name) {
93 auto it_and_inserted =
94 methods.emplace(name, std::unique_ptr<FakeMethod>(new FakeMethod()));
95 EXPECT_TRUE(it_and_inserted.second);
96 FakeMethod* method = it_and_inserted.first->second.get();
97 method->id = ++last_method_id;
98 return method;
99 }
100
101 ServiceID id;
102 std::map<std::string, std::unique_ptr<FakeMethod>> methods;
103 MethodID last_method_id = 0;
104 }; // FakeService.
105
106 explicit FakeHost(base::TaskRunner* task_runner) {
Primiano Tuccib03ba362017-12-06 09:47:41 +0000107 DESTROY_TEST_SOCK(kSockName);
Primiano Tuccid4be9662019-10-22 17:45:13 -0400108 listening_sock = base::UnixSocket::Listen(kSockName, this, task_runner,
109 base::SockFamily::kUnix,
110 base::SockType::kStream);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000111 EXPECT_TRUE(listening_sock->is_listening());
112 }
Primiano Tuccib03ba362017-12-06 09:47:41 +0000113 ~FakeHost() override { DESTROY_TEST_SOCK(kSockName); }
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000114
115 FakeService* AddFakeService(const std::string& name) {
116 auto it_and_inserted =
117 services.emplace(name, std::unique_ptr<FakeService>(new FakeService()));
118 EXPECT_TRUE(it_and_inserted.second);
119 FakeService* svc = it_and_inserted.first->second.get();
120 svc->id = ++last_service_id;
121 return svc;
122 }
123
Florian Mayerf7f0def2018-09-27 13:59:24 +0100124 // base::UnixSocket::EventListener implementation.
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000125 void OnNewIncomingConnection(
Florian Mayerf7f0def2018-09-27 13:59:24 +0100126 base::UnixSocket*,
127 std::unique_ptr<base::UnixSocket> new_connection) override {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000128 ASSERT_FALSE(client_sock);
129 client_sock = std::move(new_connection);
130 }
131
Florian Mayerf7f0def2018-09-27 13:59:24 +0100132 void OnDataAvailable(base::UnixSocket* sock) override {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000133 if (sock != client_sock.get())
134 return;
135 auto buf = frame_deserializer.BeginReceive();
Florian Mayerd16508e2018-03-02 17:06:40 +0000136 base::ScopedFile fd;
137 size_t rsize = client_sock->Receive(buf.data, buf.size, &fd);
138 if (fd)
139 received_fd_ = std::move(fd);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000140 EXPECT_TRUE(frame_deserializer.EndReceive(rsize));
141 while (std::unique_ptr<Frame> frame = frame_deserializer.PopNextFrame())
142 OnFrameReceived(*frame);
143 }
144
145 void OnFrameReceived(const Frame& req) {
Primiano Tucciba784e52019-11-13 07:04:52 -0800146 if (req.has_msg_bind_service()) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000147 auto svc_it = services.find(req.msg_bind_service().service_name());
148 ASSERT_NE(services.end(), svc_it);
Florian Mayeraab53552018-01-24 14:13:55 +0000149 const FakeService& svc = *svc_it->second;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000150 Frame reply;
151 reply.set_request_id(req.request_id());
152 reply.mutable_msg_bind_service_reply()->set_success(true);
153 reply.mutable_msg_bind_service_reply()->set_service_id(svc.id);
154 for (const auto& method_it : svc.methods) {
155 auto* method = reply.mutable_msg_bind_service_reply()->add_methods();
156 method->set_name(method_it.first);
157 method->set_id(method_it.second->id);
158 }
Florian Mayer22e4b392018-03-08 10:20:11 +0000159 Reply(reply);
Primiano Tucciba784e52019-11-13 07:04:52 -0800160 } else if (req.has_msg_invoke_method()) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000161 // Lookup the service and method.
162 bool has_more = false;
163 do {
164 Frame reply;
165 reply.set_request_id(req.request_id());
166 for (const auto& svc : services) {
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100167 if (svc.second->id != req.msg_invoke_method().service_id())
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000168 continue;
169 for (const auto& method : svc.second->methods) {
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100170 if (method.second->id != req.msg_invoke_method().method_id())
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000171 continue;
172 method.second->OnInvoke(req.msg_invoke_method(),
173 reply.mutable_msg_invoke_method_reply());
174 has_more = reply.mutable_msg_invoke_method_reply()->has_more();
175 }
176 }
177 // If either the method or the service are not found, |success| will be
178 // false by default.
179 Reply(reply);
180 } while (has_more);
181 } else {
182 FAIL() << "Unknown request";
183 }
184 }
185
186 void Reply(const Frame& frame) {
187 auto buf = BufferedFrameDeserializer::Serialize(frame);
188 ASSERT_TRUE(client_sock->is_connected());
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100189 EXPECT_TRUE(client_sock->Send(buf.data(), buf.size(), next_reply_fd,
190 base::UnixSocket::BlockingMode::kBlocking));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000191 next_reply_fd = -1;
192 }
193
194 BufferedFrameDeserializer frame_deserializer;
Florian Mayerf7f0def2018-09-27 13:59:24 +0100195 std::unique_ptr<base::UnixSocket> listening_sock;
196 std::unique_ptr<base::UnixSocket> client_sock;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000197 std::map<std::string, std::unique_ptr<FakeService>> services;
198 ServiceID last_service_id = 0;
199 int next_reply_fd = -1;
Florian Mayerd16508e2018-03-02 17:06:40 +0000200 base::ScopedFile received_fd_;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000201}; // FakeHost.
202
203class ClientImplTest : public ::testing::Test {
204 public:
205 void SetUp() override {
206 task_runner_.reset(new base::TestTaskRunner());
207 host_.reset(new FakeHost(task_runner_.get()));
208 cli_ = Client::CreateInstance(kSockName, task_runner_.get());
209 }
210
211 void TearDown() override {
212 cli_.reset();
213 host_.reset();
214 task_runner_->RunUntilIdle();
215 task_runner_.reset();
216 }
217
218 ::testing::StrictMock<MockEventListener> proxy_events_;
219 std::unique_ptr<base::TestTaskRunner> task_runner_;
220 std::unique_ptr<FakeHost> host_;
221 std::unique_ptr<Client> cli_;
222};
223
224TEST_F(ClientImplTest, BindAndInvokeMethod) {
225 auto* host_svc = host_->AddFakeService("FakeSvc");
226 auto* host_method = host_svc->AddFakeMethod("FakeMethod1");
227
228 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
229
230 // Bind |proxy| to the fake host.
231 cli_->BindService(proxy->GetWeakPtr());
232 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
233 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect));
234 task_runner_->RunUntilCheckpoint("on_connect");
235
236 // Invoke a valid method.
237 EXPECT_CALL(*host_method, OnInvoke(_, _))
238 .WillOnce(Invoke(
239 [](const Frame::InvokeMethod& req, Frame::InvokeMethodReply* reply) {
240 RequestProto req_args;
241 EXPECT_TRUE(req_args.ParseFromString(req.args_proto()));
242 EXPECT_EQ("req_data", req_args.data());
243 ReplyProto reply_args;
244 reply->set_reply_proto(reply_args.SerializeAsString());
245 reply->set_success(true);
246 }));
247
248 RequestProto req;
249 req.set_data("req_data");
250 auto on_invoke_reply = task_runner_->CreateCheckpoint("on_invoke_reply");
Primiano Tucci5b65c9f2018-01-29 22:58:25 +0000251 Deferred<ProtoMessage> deferred_reply(
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000252 [on_invoke_reply](AsyncResult<ProtoMessage> reply) {
253 EXPECT_TRUE(reply.success());
254 on_invoke_reply();
255 });
256 proxy->BeginInvoke("FakeMethod1", req, std::move(deferred_reply));
257 task_runner_->RunUntilCheckpoint("on_invoke_reply");
258
259 // Invoke an invalid method.
260 auto on_invalid_invoke = task_runner_->CreateCheckpoint("on_invalid_invoke");
Primiano Tucci5b65c9f2018-01-29 22:58:25 +0000261 Deferred<ProtoMessage> deferred_reply2(
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000262 [on_invalid_invoke](AsyncResult<ProtoMessage> reply) {
263 EXPECT_FALSE(reply.success());
264 on_invalid_invoke();
265 });
266 RequestProto empty_req;
267 proxy->BeginInvoke("InvalidMethod", empty_req, std::move(deferred_reply2));
268 task_runner_->RunUntilCheckpoint("on_invalid_invoke");
269}
270
Primiano Tucci2d0b2252018-01-25 13:37:50 +0000271// Tests that when invoking a method without binding a callback, the resulting
272// request has the |drop_reply| flag set.
273TEST_F(ClientImplTest, InvokeMethodDropReply) {
274 auto* host_svc = host_->AddFakeService("FakeSvc");
275 auto* host_method = host_svc->AddFakeMethod("FakeMethod1");
276
277 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
278
279 // Bind |proxy| to the fake host.
280 cli_->BindService(proxy->GetWeakPtr());
281 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
282 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect));
283 task_runner_->RunUntilCheckpoint("on_connect");
284
285 auto on_req_received = task_runner_->CreateCheckpoint("on_req_received");
286 EXPECT_CALL(*host_method, OnInvoke(_, _))
287 .WillOnce(Invoke([on_req_received](const Frame::InvokeMethod& req,
288 Frame::InvokeMethodReply*) {
289 RequestProto req_args;
290 EXPECT_TRUE(req.drop_reply());
291 on_req_received();
292 }));
293
294 // Invoke a method without binding any callback to the Deferred object.
Primiano Tucci5b65c9f2018-01-29 22:58:25 +0000295 Deferred<ProtoMessage> no_callback;
Primiano Tucci2d0b2252018-01-25 13:37:50 +0000296 proxy->BeginInvoke("FakeMethod1", RequestProto(), std::move(no_callback));
297 task_runner_->RunUntilCheckpoint("on_req_received");
298}
299
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000300// Like BindAndInvokeMethod, but this time invoke a streaming method that
301// provides > 1 reply per invocation.
302TEST_F(ClientImplTest, BindAndInvokeStreamingMethod) {
303 auto* host_svc = host_->AddFakeService("FakeSvc");
304 auto* host_method = host_svc->AddFakeMethod("FakeMethod1");
305 const int kNumReplies = 3;
306
307 // Create and bind |proxy| to the fake host.
308 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
309 cli_->BindService(proxy->GetWeakPtr());
310 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
311 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect));
312 task_runner_->RunUntilCheckpoint("on_connect");
313
314 // Invoke a valid method, reply kNumReplies times.
315 int replies_left = kNumReplies;
316 EXPECT_CALL(*host_method, OnInvoke(_, _))
317 .Times(kNumReplies)
318 .WillRepeatedly(Invoke([&replies_left](const Frame::InvokeMethod& req,
319 Frame::InvokeMethodReply* reply) {
320 RequestProto req_args;
321 EXPECT_TRUE(req_args.ParseFromString(req.args_proto()));
322 reply->set_reply_proto(ReplyProto().SerializeAsString());
323 reply->set_success(true);
324 reply->set_has_more(--replies_left > 0);
325 }));
326
327 RequestProto req;
328 req.set_data("req_data");
329 auto on_last_reply = task_runner_->CreateCheckpoint("on_last_reply");
330 int replies_seen = 0;
Primiano Tucci5b65c9f2018-01-29 22:58:25 +0000331 Deferred<ProtoMessage> deferred_reply(
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000332 [on_last_reply, &replies_seen](AsyncResult<ProtoMessage> reply) {
333 EXPECT_TRUE(reply.success());
334 replies_seen++;
335 if (!reply.has_more())
336 on_last_reply();
337 });
338 proxy->BeginInvoke("FakeMethod1", req, std::move(deferred_reply));
339 task_runner_->RunUntilCheckpoint("on_last_reply");
340 ASSERT_EQ(kNumReplies, replies_seen);
341}
342
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000343TEST_F(ClientImplTest, ReceiveFileDescriptor) {
344 auto* host_svc = host_->AddFakeService("FakeSvc");
345 auto* host_method = host_svc->AddFakeMethod("FakeMethod1");
346
347 // Create and bind |proxy| to the fake host.
348 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
349 cli_->BindService(proxy->GetWeakPtr());
350 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
351 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect));
352 task_runner_->RunUntilCheckpoint("on_connect");
353
Primiano Tucci941b2212018-03-14 22:46:31 +0000354 base::TempFile tx_file = base::TempFile::CreateUnlinked();
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000355 static constexpr char kFileContent[] = "shared file";
Stephen Nusko5da63f32019-04-25 17:06:26 +0100356 ASSERT_EQ(static_cast<size_t>(base::WriteAll(tx_file.fd(), kFileContent,
357 sizeof(kFileContent))),
Florian Mayer21e418f2018-10-04 11:07:45 +0100358 sizeof(kFileContent));
Primiano Tucci941b2212018-03-14 22:46:31 +0000359 host_->next_reply_fd = tx_file.fd();
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000360
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000361 EXPECT_CALL(*host_method, OnInvoke(_, _))
362 .WillOnce(Invoke(
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100363 [](const Frame::InvokeMethod&, Frame::InvokeMethodReply* reply) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000364 RequestProto req_args;
365 reply->set_reply_proto(ReplyProto().SerializeAsString());
366 reply->set_success(true);
367 }));
368
369 RequestProto req;
370 auto on_reply = task_runner_->CreateCheckpoint("on_reply");
Primiano Tucci5b65c9f2018-01-29 22:58:25 +0000371 Deferred<ProtoMessage> deferred_reply(
372 [on_reply](AsyncResult<ProtoMessage> reply) {
373 EXPECT_TRUE(reply.success());
374 on_reply();
375 });
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000376 proxy->BeginInvoke("FakeMethod1", req, std::move(deferred_reply));
377 task_runner_->RunUntilCheckpoint("on_reply");
378
Primiano Tucci941b2212018-03-14 22:46:31 +0000379 tx_file.ReleaseFD();
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000380 base::ScopedFile rx_fd = cli_->TakeReceivedFD();
381 ASSERT_TRUE(rx_fd);
382 char buf[sizeof(kFileContent)] = {};
383 ASSERT_EQ(0, lseek(*rx_fd, 0, SEEK_SET));
384 ASSERT_EQ(static_cast<long>(sizeof(buf)),
385 PERFETTO_EINTR(read(*rx_fd, buf, sizeof(buf))));
386 ASSERT_STREQ(kFileContent, buf);
387}
388
Florian Mayerd16508e2018-03-02 17:06:40 +0000389TEST_F(ClientImplTest, SendFileDescriptor) {
390 auto* host_svc = host_->AddFakeService("FakeSvc");
391 auto* host_method = host_svc->AddFakeMethod("FakeMethod1");
392
393 // Create and bind |proxy| to the fake host.
394 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
395 cli_->BindService(proxy->GetWeakPtr());
396 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
397 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect));
398 task_runner_->RunUntilCheckpoint("on_connect");
399
Primiano Tucci941b2212018-03-14 22:46:31 +0000400 base::TempFile tx_file = base::TempFile::CreateUnlinked();
Florian Mayerd16508e2018-03-02 17:06:40 +0000401 static constexpr char kFileContent[] = "shared file";
Stephen Nusko5da63f32019-04-25 17:06:26 +0100402 ASSERT_EQ(static_cast<size_t>(base::WriteAll(tx_file.fd(), kFileContent,
403 sizeof(kFileContent))),
Florian Mayer21e418f2018-10-04 11:07:45 +0100404 sizeof(kFileContent));
Florian Mayerd16508e2018-03-02 17:06:40 +0000405 EXPECT_CALL(*host_method, OnInvoke(_, _))
406 .WillOnce(Invoke(
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100407 [](const Frame::InvokeMethod&, Frame::InvokeMethodReply* reply) {
Florian Mayerd16508e2018-03-02 17:06:40 +0000408 RequestProto req_args;
409 reply->set_reply_proto(ReplyProto().SerializeAsString());
410 reply->set_success(true);
411 }));
412
413 RequestProto req;
414 auto on_reply = task_runner_->CreateCheckpoint("on_reply");
415 Deferred<ProtoMessage> deferred_reply(
416 [on_reply](AsyncResult<ProtoMessage> reply) {
417 EXPECT_TRUE(reply.success());
418 on_reply();
419 });
420 proxy->BeginInvoke("FakeMethod1", req, std::move(deferred_reply),
Primiano Tucci941b2212018-03-14 22:46:31 +0000421 tx_file.fd());
Florian Mayerd16508e2018-03-02 17:06:40 +0000422 task_runner_->RunUntilCheckpoint("on_reply");
423
424 base::ScopedFile rx_fd = std::move(host_->received_fd_);
425 ASSERT_TRUE(rx_fd);
426 char buf[sizeof(kFileContent)] = {};
427 ASSERT_EQ(0, lseek(*rx_fd, 0, SEEK_SET));
428 ASSERT_EQ(static_cast<long>(sizeof(buf)),
429 PERFETTO_EINTR(read(*rx_fd, buf, sizeof(buf))));
430 ASSERT_STREQ(kFileContent, buf);
431}
432
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000433TEST_F(ClientImplTest, BindSameServiceMultipleTimesShouldFail) {
434 host_->AddFakeService("FakeSvc");
435
436 std::unique_ptr<FakeProxy> proxy[3];
437 for (size_t i = 0; i < base::ArraySize(proxy); i++)
438 proxy[i].reset(new FakeProxy("FakeSvc", &proxy_events_));
439
440 // Bind to the host.
441 for (size_t i = 0; i < base::ArraySize(proxy); i++) {
442 auto checkpoint_name = "on_connect_or_disconnect" + std::to_string(i);
443 auto closure = task_runner_->CreateCheckpoint(checkpoint_name);
444 if (i == 0) {
445 // Only the first call should succeed.
446 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(closure));
447 } else {
448 EXPECT_CALL(proxy_events_, OnDisconnect()).WillOnce(Invoke(closure));
449 }
450 cli_->BindService(proxy[i]->GetWeakPtr());
451 task_runner_->RunUntilCheckpoint(checkpoint_name);
452 }
453}
454
455TEST_F(ClientImplTest, BindRequestsAreQueuedIfNotConnected) {
456 host_->AddFakeService("FakeSvc1");
457 host_->AddFakeService("FakeSvc2");
458
459 std::unique_ptr<FakeProxy> proxy1(new FakeProxy("FakeSvc1", &proxy_events_));
460 std::unique_ptr<FakeProxy> proxy2(new FakeProxy("FakeSvc2", &proxy_events_));
461
462 // Bind the services (in opposite order of creation) before running any task.
463 cli_->BindService(proxy2->GetWeakPtr());
464 cli_->BindService(proxy1->GetWeakPtr());
465
466 InSequence seq;
467 auto on_connect1 = task_runner_->CreateCheckpoint("on_connect1");
468 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect1));
469
470 auto on_connect2 = task_runner_->CreateCheckpoint("on_connect2");
471 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect2));
472
473 task_runner_->RunUntilCheckpoint("on_connect1");
474 task_runner_->RunUntilCheckpoint("on_connect2");
475}
476
477// The deferred callbacks for both binding a service and invoking a method
478// should be dropped if the ServiceProxy object is destroyed prematurely.
479TEST_F(ClientImplTest, DropCallbacksIfServiceProxyIsDestroyed) {
480 auto* host_svc = host_->AddFakeService("FakeSvc");
481 auto* host_method = host_svc->AddFakeMethod("FakeMethod1");
482
483 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
484
485 // First bind the service but destroy it before ClientImpl manages to run any
486 // tasks. No OnConnect() should be called.
487 cli_->BindService(proxy->GetWeakPtr());
488 proxy.reset();
489 task_runner_->RunUntilIdle();
490 ASSERT_TRUE(Mock::VerifyAndClearExpectations(&proxy_events_));
491
492 // Now bind it successfully, invoke a method but destroy the proxy before
493 // the method reply is dispatched. The DeferredReply should be rejected,
494 // despite the fact that the host gave a successful reply.
495 proxy.reset(new FakeProxy("FakeSvc", &proxy_events_));
496 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
497 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect));
498 cli_->BindService(proxy->GetWeakPtr());
499 task_runner_->RunUntilCheckpoint("on_connect");
500
501 RequestProto req;
502 auto on_reply_sent = task_runner_->CreateCheckpoint("on_reply_sent");
503 EXPECT_CALL(*host_method, OnInvoke(_, _))
504 .WillOnce(Invoke([on_reply_sent](const Frame::InvokeMethod&,
505 Frame::InvokeMethodReply* reply) {
506 ReplyProto reply_args;
507 reply->set_success(true);
508 on_reply_sent();
509 }));
510
511 auto on_reject = task_runner_->CreateCheckpoint("on_reject");
Primiano Tucci5b65c9f2018-01-29 22:58:25 +0000512 Deferred<ProtoMessage> deferred_reply(
513 [on_reject](AsyncResult<ProtoMessage> res) {
514 ASSERT_FALSE(res.success());
515 on_reject();
516 });
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000517 proxy->BeginInvoke("FakeMethod1", req, std::move(deferred_reply));
518 proxy.reset();
519 task_runner_->RunUntilCheckpoint("on_reject");
520 task_runner_->RunUntilCheckpoint("on_reply_sent");
521}
522
523// If the Client object is destroyed before the ServiceProxy, the ServiceProxy
524// should see a Disconnect() call and any pending callback should be rejected.
525TEST_F(ClientImplTest, ClientDestroyedBeforeProxy) {
526 auto* host_svc = host_->AddFakeService("FakeSvc");
527 host_svc->AddFakeMethod("FakeMethod1");
528
529 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
530 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
531 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect));
532 cli_->BindService(proxy->GetWeakPtr());
533 task_runner_->RunUntilCheckpoint("on_connect");
534
535 auto on_reject = task_runner_->CreateCheckpoint("on_reject");
536 DeferredBase deferred_reply([on_reject](AsyncResult<ProtoMessage> res) {
537 ASSERT_FALSE(res.success());
538 on_reject();
539 });
540 RequestProto req;
541 proxy->BeginInvoke("FakeMethod1", req, std::move(deferred_reply));
542 EXPECT_CALL(proxy_events_, OnDisconnect());
543 cli_.reset();
Primiano Tuccib03ba362017-12-06 09:47:41 +0000544 host_.reset(); // Prevent spurious OnInvoke callbacks on the fake host.
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000545 task_runner_->RunUntilCheckpoint("on_reject");
546}
547
548// Test that OnDisconnect() is invoked if the host is not reachable.
549TEST_F(ClientImplTest, HostNotReachable) {
550 host_.reset();
551
552 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
553
554 auto on_disconnect = task_runner_->CreateCheckpoint("on_disconnect");
555 EXPECT_CALL(proxy_events_, OnDisconnect()).WillOnce(Invoke(on_disconnect));
556 cli_->BindService(proxy->GetWeakPtr());
557 task_runner_->RunUntilCheckpoint("on_disconnect");
558}
559
560// Test that OnDisconnect() is invoked if the host shuts down prematurely.
561TEST_F(ClientImplTest, HostDisconnection) {
562 host_->AddFakeService("FakeSvc");
563
564 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
565
566 // Bind |proxy| to the fake host.
567 cli_->BindService(proxy->GetWeakPtr());
568 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
569 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect));
570 task_runner_->RunUntilCheckpoint("on_connect");
571
572 auto on_disconnect = task_runner_->CreateCheckpoint("on_disconnect");
573 EXPECT_CALL(proxy_events_, OnDisconnect()).WillOnce(Invoke(on_disconnect));
574 host_.reset();
575 task_runner_->RunUntilCheckpoint("on_disconnect");
576}
577
578// TODO(primiano): add the tests below.
579// TEST(ClientImplTest, UnparsableReply) {}
580
581} // namespace
582} // namespace ipc
583} // namespace perfetto