blob: 3bdded648e18c5596cacdfd5e52f7f75587528ca [file] [log] [blame]
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001/*
2 * Copyright (C) 2017 The Android Open foo Project
3 *
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
24#include "gmock/gmock.h"
25#include "gtest/gtest.h"
Primiano Tucci941b2212018-03-14 22:46:31 +000026#include "perfetto/base/temp_file.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000027#include "perfetto/base/utils.h"
28#include "perfetto/ipc/service_descriptor.h"
29#include "perfetto/ipc/service_proxy.h"
30#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 Tucci4f9b6d72017-12-05 20:59:16 +000033#include "src/ipc/unix_socket.h"
34
35#include "src/ipc/test/client_unittest_messages.pb.h"
36
37namespace perfetto {
38namespace ipc {
39namespace {
40
41using ::testing::_;
42using ::testing::InSequence;
43using ::testing::Invoke;
44using ::testing::Mock;
45
Primiano Tuccib03ba362017-12-06 09:47:41 +000046constexpr char kSockName[] = TEST_SOCK_NAME("client_impl_unittest");
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000047
48// A fake ServiceProxy. This fakes the client-side class that would be
49// auto-generated from .proto-files.
50class FakeProxy : public ServiceProxy {
51 public:
52 FakeProxy(const char* service_name, ServiceProxy::EventListener* el)
53 : ServiceProxy(el), service_name_(service_name) {}
54
55 const ServiceDescriptor& GetDescriptor() override {
56 auto reply_decoder = [](const std::string& proto) {
57 std::unique_ptr<ProtoMessage> reply(new ReplyProto());
58 EXPECT_TRUE(reply->ParseFromString(proto));
59 return reply;
60 };
61 if (!descriptor_.service_name) {
62 descriptor_.service_name = service_name_;
Sami Kyostila2e366832017-12-06 12:17:24 +000063 descriptor_.methods.push_back(
64 {"FakeMethod1", nullptr, reply_decoder, nullptr});
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000065 }
66 return descriptor_;
67 }
68
69 const char* service_name_;
70 ServiceDescriptor descriptor_;
71};
72
73class MockEventListener : public ServiceProxy::EventListener {
74 public:
75 MOCK_METHOD0(OnConnect, void());
76 MOCK_METHOD0(OnDisconnect, void());
77};
78
79// A fake host implementation. Listens on |kSockName| and replies to IPC
80// metohds like a real one.
81class FakeHost : public UnixSocket::EventListener {
82 public:
83 struct FakeMethod {
84 MethodID id;
85 MOCK_METHOD2(OnInvoke,
86 void(const Frame::InvokeMethod&, Frame::InvokeMethodReply*));
87 }; // FakeMethod.
88
89 struct FakeService {
90 FakeMethod* AddFakeMethod(const std::string& name) {
91 auto it_and_inserted =
92 methods.emplace(name, std::unique_ptr<FakeMethod>(new FakeMethod()));
93 EXPECT_TRUE(it_and_inserted.second);
94 FakeMethod* method = it_and_inserted.first->second.get();
95 method->id = ++last_method_id;
96 return method;
97 }
98
99 ServiceID id;
100 std::map<std::string, std::unique_ptr<FakeMethod>> methods;
101 MethodID last_method_id = 0;
102 }; // FakeService.
103
104 explicit FakeHost(base::TaskRunner* task_runner) {
Primiano Tuccib03ba362017-12-06 09:47:41 +0000105 DESTROY_TEST_SOCK(kSockName);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000106 listening_sock = UnixSocket::Listen(kSockName, this, task_runner);
107 EXPECT_TRUE(listening_sock->is_listening());
108 }
Primiano Tuccib03ba362017-12-06 09:47:41 +0000109 ~FakeHost() override { DESTROY_TEST_SOCK(kSockName); }
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000110
111 FakeService* AddFakeService(const std::string& name) {
112 auto it_and_inserted =
113 services.emplace(name, std::unique_ptr<FakeService>(new FakeService()));
114 EXPECT_TRUE(it_and_inserted.second);
115 FakeService* svc = it_and_inserted.first->second.get();
116 svc->id = ++last_service_id;
117 return svc;
118 }
119
120 // UnixSocket::EventListener implementation.
121 void OnNewIncomingConnection(
122 UnixSocket*,
123 std::unique_ptr<UnixSocket> new_connection) override {
124 ASSERT_FALSE(client_sock);
125 client_sock = std::move(new_connection);
126 }
127
128 void OnDataAvailable(UnixSocket* sock) override {
129 if (sock != client_sock.get())
130 return;
131 auto buf = frame_deserializer.BeginReceive();
Florian Mayerd16508e2018-03-02 17:06:40 +0000132 base::ScopedFile fd;
133 size_t rsize = client_sock->Receive(buf.data, buf.size, &fd);
134 if (fd)
135 received_fd_ = std::move(fd);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000136 EXPECT_TRUE(frame_deserializer.EndReceive(rsize));
137 while (std::unique_ptr<Frame> frame = frame_deserializer.PopNextFrame())
138 OnFrameReceived(*frame);
139 }
140
141 void OnFrameReceived(const Frame& req) {
142 if (req.msg_case() == Frame::kMsgBindService) {
143 auto svc_it = services.find(req.msg_bind_service().service_name());
144 ASSERT_NE(services.end(), svc_it);
Florian Mayeraab53552018-01-24 14:13:55 +0000145 const FakeService& svc = *svc_it->second;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000146 Frame reply;
147 reply.set_request_id(req.request_id());
148 reply.mutable_msg_bind_service_reply()->set_success(true);
149 reply.mutable_msg_bind_service_reply()->set_service_id(svc.id);
150 for (const auto& method_it : svc.methods) {
151 auto* method = reply.mutable_msg_bind_service_reply()->add_methods();
152 method->set_name(method_it.first);
153 method->set_id(method_it.second->id);
154 }
Florian Mayer22e4b392018-03-08 10:20:11 +0000155 Reply(reply);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000156 } else if (req.msg_case() == Frame::kMsgInvokeMethod) {
157 // Lookup the service and method.
158 bool has_more = false;
159 do {
160 Frame reply;
161 reply.set_request_id(req.request_id());
162 for (const auto& svc : services) {
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100163 if (svc.second->id != req.msg_invoke_method().service_id())
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000164 continue;
165 for (const auto& method : svc.second->methods) {
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100166 if (method.second->id != req.msg_invoke_method().method_id())
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000167 continue;
168 method.second->OnInvoke(req.msg_invoke_method(),
169 reply.mutable_msg_invoke_method_reply());
170 has_more = reply.mutable_msg_invoke_method_reply()->has_more();
171 }
172 }
173 // If either the method or the service are not found, |success| will be
174 // false by default.
175 Reply(reply);
176 } while (has_more);
177 } else {
178 FAIL() << "Unknown request";
179 }
180 }
181
182 void Reply(const Frame& frame) {
183 auto buf = BufferedFrameDeserializer::Serialize(frame);
184 ASSERT_TRUE(client_sock->is_connected());
185 EXPECT_TRUE(client_sock->Send(buf.data(), buf.size(), next_reply_fd));
186 next_reply_fd = -1;
187 }
188
189 BufferedFrameDeserializer frame_deserializer;
190 std::unique_ptr<UnixSocket> listening_sock;
191 std::unique_ptr<UnixSocket> client_sock;
192 std::map<std::string, std::unique_ptr<FakeService>> services;
193 ServiceID last_service_id = 0;
194 int next_reply_fd = -1;
Florian Mayerd16508e2018-03-02 17:06:40 +0000195 base::ScopedFile received_fd_;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000196}; // FakeHost.
197
198class ClientImplTest : public ::testing::Test {
199 public:
200 void SetUp() override {
201 task_runner_.reset(new base::TestTaskRunner());
202 host_.reset(new FakeHost(task_runner_.get()));
203 cli_ = Client::CreateInstance(kSockName, task_runner_.get());
204 }
205
206 void TearDown() override {
207 cli_.reset();
208 host_.reset();
209 task_runner_->RunUntilIdle();
210 task_runner_.reset();
211 }
212
213 ::testing::StrictMock<MockEventListener> proxy_events_;
214 std::unique_ptr<base::TestTaskRunner> task_runner_;
215 std::unique_ptr<FakeHost> host_;
216 std::unique_ptr<Client> cli_;
217};
218
219TEST_F(ClientImplTest, BindAndInvokeMethod) {
220 auto* host_svc = host_->AddFakeService("FakeSvc");
221 auto* host_method = host_svc->AddFakeMethod("FakeMethod1");
222
223 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
224
225 // Bind |proxy| to the fake host.
226 cli_->BindService(proxy->GetWeakPtr());
227 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
228 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect));
229 task_runner_->RunUntilCheckpoint("on_connect");
230
231 // Invoke a valid method.
232 EXPECT_CALL(*host_method, OnInvoke(_, _))
233 .WillOnce(Invoke(
234 [](const Frame::InvokeMethod& req, Frame::InvokeMethodReply* reply) {
235 RequestProto req_args;
236 EXPECT_TRUE(req_args.ParseFromString(req.args_proto()));
237 EXPECT_EQ("req_data", req_args.data());
238 ReplyProto reply_args;
239 reply->set_reply_proto(reply_args.SerializeAsString());
240 reply->set_success(true);
241 }));
242
243 RequestProto req;
244 req.set_data("req_data");
245 auto on_invoke_reply = task_runner_->CreateCheckpoint("on_invoke_reply");
Primiano Tucci5b65c9f2018-01-29 22:58:25 +0000246 Deferred<ProtoMessage> deferred_reply(
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000247 [on_invoke_reply](AsyncResult<ProtoMessage> reply) {
248 EXPECT_TRUE(reply.success());
249 on_invoke_reply();
250 });
251 proxy->BeginInvoke("FakeMethod1", req, std::move(deferred_reply));
252 task_runner_->RunUntilCheckpoint("on_invoke_reply");
253
254 // Invoke an invalid method.
255 auto on_invalid_invoke = task_runner_->CreateCheckpoint("on_invalid_invoke");
Primiano Tucci5b65c9f2018-01-29 22:58:25 +0000256 Deferred<ProtoMessage> deferred_reply2(
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000257 [on_invalid_invoke](AsyncResult<ProtoMessage> reply) {
258 EXPECT_FALSE(reply.success());
259 on_invalid_invoke();
260 });
261 RequestProto empty_req;
262 proxy->BeginInvoke("InvalidMethod", empty_req, std::move(deferred_reply2));
263 task_runner_->RunUntilCheckpoint("on_invalid_invoke");
264}
265
Primiano Tucci2d0b2252018-01-25 13:37:50 +0000266// Tests that when invoking a method without binding a callback, the resulting
267// request has the |drop_reply| flag set.
268TEST_F(ClientImplTest, InvokeMethodDropReply) {
269 auto* host_svc = host_->AddFakeService("FakeSvc");
270 auto* host_method = host_svc->AddFakeMethod("FakeMethod1");
271
272 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
273
274 // Bind |proxy| to the fake host.
275 cli_->BindService(proxy->GetWeakPtr());
276 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
277 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect));
278 task_runner_->RunUntilCheckpoint("on_connect");
279
280 auto on_req_received = task_runner_->CreateCheckpoint("on_req_received");
281 EXPECT_CALL(*host_method, OnInvoke(_, _))
282 .WillOnce(Invoke([on_req_received](const Frame::InvokeMethod& req,
283 Frame::InvokeMethodReply*) {
284 RequestProto req_args;
285 EXPECT_TRUE(req.drop_reply());
286 on_req_received();
287 }));
288
289 // Invoke a method without binding any callback to the Deferred object.
Primiano Tucci5b65c9f2018-01-29 22:58:25 +0000290 Deferred<ProtoMessage> no_callback;
Primiano Tucci2d0b2252018-01-25 13:37:50 +0000291 proxy->BeginInvoke("FakeMethod1", RequestProto(), std::move(no_callback));
292 task_runner_->RunUntilCheckpoint("on_req_received");
293}
294
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000295// Like BindAndInvokeMethod, but this time invoke a streaming method that
296// provides > 1 reply per invocation.
297TEST_F(ClientImplTest, BindAndInvokeStreamingMethod) {
298 auto* host_svc = host_->AddFakeService("FakeSvc");
299 auto* host_method = host_svc->AddFakeMethod("FakeMethod1");
300 const int kNumReplies = 3;
301
302 // Create and bind |proxy| to the fake host.
303 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
304 cli_->BindService(proxy->GetWeakPtr());
305 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
306 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect));
307 task_runner_->RunUntilCheckpoint("on_connect");
308
309 // Invoke a valid method, reply kNumReplies times.
310 int replies_left = kNumReplies;
311 EXPECT_CALL(*host_method, OnInvoke(_, _))
312 .Times(kNumReplies)
313 .WillRepeatedly(Invoke([&replies_left](const Frame::InvokeMethod& req,
314 Frame::InvokeMethodReply* reply) {
315 RequestProto req_args;
316 EXPECT_TRUE(req_args.ParseFromString(req.args_proto()));
317 reply->set_reply_proto(ReplyProto().SerializeAsString());
318 reply->set_success(true);
319 reply->set_has_more(--replies_left > 0);
320 }));
321
322 RequestProto req;
323 req.set_data("req_data");
324 auto on_last_reply = task_runner_->CreateCheckpoint("on_last_reply");
325 int replies_seen = 0;
Primiano Tucci5b65c9f2018-01-29 22:58:25 +0000326 Deferred<ProtoMessage> deferred_reply(
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000327 [on_last_reply, &replies_seen](AsyncResult<ProtoMessage> reply) {
328 EXPECT_TRUE(reply.success());
329 replies_seen++;
330 if (!reply.has_more())
331 on_last_reply();
332 });
333 proxy->BeginInvoke("FakeMethod1", req, std::move(deferred_reply));
334 task_runner_->RunUntilCheckpoint("on_last_reply");
335 ASSERT_EQ(kNumReplies, replies_seen);
336}
337
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000338TEST_F(ClientImplTest, ReceiveFileDescriptor) {
339 auto* host_svc = host_->AddFakeService("FakeSvc");
340 auto* host_method = host_svc->AddFakeMethod("FakeMethod1");
341
342 // Create and bind |proxy| to the fake host.
343 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
344 cli_->BindService(proxy->GetWeakPtr());
345 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
346 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect));
347 task_runner_->RunUntilCheckpoint("on_connect");
348
Primiano Tucci941b2212018-03-14 22:46:31 +0000349 base::TempFile tx_file = base::TempFile::CreateUnlinked();
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000350 static constexpr char kFileContent[] = "shared file";
Primiano Tucci55e73f32018-03-15 07:32:02 +0000351 base::ignore_result(write(tx_file.fd(), kFileContent, sizeof(kFileContent)));
Primiano Tucci941b2212018-03-14 22:46:31 +0000352 host_->next_reply_fd = tx_file.fd();
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000353
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000354 EXPECT_CALL(*host_method, OnInvoke(_, _))
355 .WillOnce(Invoke(
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100356 [](const Frame::InvokeMethod&, Frame::InvokeMethodReply* reply) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000357 RequestProto req_args;
358 reply->set_reply_proto(ReplyProto().SerializeAsString());
359 reply->set_success(true);
360 }));
361
362 RequestProto req;
363 auto on_reply = task_runner_->CreateCheckpoint("on_reply");
Primiano Tucci5b65c9f2018-01-29 22:58:25 +0000364 Deferred<ProtoMessage> deferred_reply(
365 [on_reply](AsyncResult<ProtoMessage> reply) {
366 EXPECT_TRUE(reply.success());
367 on_reply();
368 });
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000369 proxy->BeginInvoke("FakeMethod1", req, std::move(deferred_reply));
370 task_runner_->RunUntilCheckpoint("on_reply");
371
Primiano Tucci941b2212018-03-14 22:46:31 +0000372 tx_file.ReleaseFD();
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000373 base::ScopedFile rx_fd = cli_->TakeReceivedFD();
374 ASSERT_TRUE(rx_fd);
375 char buf[sizeof(kFileContent)] = {};
376 ASSERT_EQ(0, lseek(*rx_fd, 0, SEEK_SET));
377 ASSERT_EQ(static_cast<long>(sizeof(buf)),
378 PERFETTO_EINTR(read(*rx_fd, buf, sizeof(buf))));
379 ASSERT_STREQ(kFileContent, buf);
380}
381
Florian Mayerd16508e2018-03-02 17:06:40 +0000382TEST_F(ClientImplTest, SendFileDescriptor) {
383 auto* host_svc = host_->AddFakeService("FakeSvc");
384 auto* host_method = host_svc->AddFakeMethod("FakeMethod1");
385
386 // Create and bind |proxy| to the fake host.
387 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
388 cli_->BindService(proxy->GetWeakPtr());
389 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
390 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect));
391 task_runner_->RunUntilCheckpoint("on_connect");
392
Primiano Tucci941b2212018-03-14 22:46:31 +0000393 base::TempFile tx_file = base::TempFile::CreateUnlinked();
Florian Mayerd16508e2018-03-02 17:06:40 +0000394 static constexpr char kFileContent[] = "shared file";
Primiano Tucci55e73f32018-03-15 07:32:02 +0000395 base::ignore_result(write(tx_file.fd(), kFileContent, sizeof(kFileContent)));
Florian Mayerd16508e2018-03-02 17:06:40 +0000396 EXPECT_CALL(*host_method, OnInvoke(_, _))
397 .WillOnce(Invoke(
Primiano Tucci3cbb10a2018-04-10 17:52:40 +0100398 [](const Frame::InvokeMethod&, Frame::InvokeMethodReply* reply) {
Florian Mayerd16508e2018-03-02 17:06:40 +0000399 RequestProto req_args;
400 reply->set_reply_proto(ReplyProto().SerializeAsString());
401 reply->set_success(true);
402 }));
403
404 RequestProto req;
405 auto on_reply = task_runner_->CreateCheckpoint("on_reply");
406 Deferred<ProtoMessage> deferred_reply(
407 [on_reply](AsyncResult<ProtoMessage> reply) {
408 EXPECT_TRUE(reply.success());
409 on_reply();
410 });
411 proxy->BeginInvoke("FakeMethod1", req, std::move(deferred_reply),
Primiano Tucci941b2212018-03-14 22:46:31 +0000412 tx_file.fd());
Florian Mayerd16508e2018-03-02 17:06:40 +0000413 task_runner_->RunUntilCheckpoint("on_reply");
414
415 base::ScopedFile rx_fd = std::move(host_->received_fd_);
416 ASSERT_TRUE(rx_fd);
417 char buf[sizeof(kFileContent)] = {};
418 ASSERT_EQ(0, lseek(*rx_fd, 0, SEEK_SET));
419 ASSERT_EQ(static_cast<long>(sizeof(buf)),
420 PERFETTO_EINTR(read(*rx_fd, buf, sizeof(buf))));
421 ASSERT_STREQ(kFileContent, buf);
422}
423
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000424TEST_F(ClientImplTest, BindSameServiceMultipleTimesShouldFail) {
425 host_->AddFakeService("FakeSvc");
426
427 std::unique_ptr<FakeProxy> proxy[3];
428 for (size_t i = 0; i < base::ArraySize(proxy); i++)
429 proxy[i].reset(new FakeProxy("FakeSvc", &proxy_events_));
430
431 // Bind to the host.
432 for (size_t i = 0; i < base::ArraySize(proxy); i++) {
433 auto checkpoint_name = "on_connect_or_disconnect" + std::to_string(i);
434 auto closure = task_runner_->CreateCheckpoint(checkpoint_name);
435 if (i == 0) {
436 // Only the first call should succeed.
437 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(closure));
438 } else {
439 EXPECT_CALL(proxy_events_, OnDisconnect()).WillOnce(Invoke(closure));
440 }
441 cli_->BindService(proxy[i]->GetWeakPtr());
442 task_runner_->RunUntilCheckpoint(checkpoint_name);
443 }
444}
445
446TEST_F(ClientImplTest, BindRequestsAreQueuedIfNotConnected) {
447 host_->AddFakeService("FakeSvc1");
448 host_->AddFakeService("FakeSvc2");
449
450 std::unique_ptr<FakeProxy> proxy1(new FakeProxy("FakeSvc1", &proxy_events_));
451 std::unique_ptr<FakeProxy> proxy2(new FakeProxy("FakeSvc2", &proxy_events_));
452
453 // Bind the services (in opposite order of creation) before running any task.
454 cli_->BindService(proxy2->GetWeakPtr());
455 cli_->BindService(proxy1->GetWeakPtr());
456
457 InSequence seq;
458 auto on_connect1 = task_runner_->CreateCheckpoint("on_connect1");
459 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect1));
460
461 auto on_connect2 = task_runner_->CreateCheckpoint("on_connect2");
462 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect2));
463
464 task_runner_->RunUntilCheckpoint("on_connect1");
465 task_runner_->RunUntilCheckpoint("on_connect2");
466}
467
468// The deferred callbacks for both binding a service and invoking a method
469// should be dropped if the ServiceProxy object is destroyed prematurely.
470TEST_F(ClientImplTest, DropCallbacksIfServiceProxyIsDestroyed) {
471 auto* host_svc = host_->AddFakeService("FakeSvc");
472 auto* host_method = host_svc->AddFakeMethod("FakeMethod1");
473
474 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
475
476 // First bind the service but destroy it before ClientImpl manages to run any
477 // tasks. No OnConnect() should be called.
478 cli_->BindService(proxy->GetWeakPtr());
479 proxy.reset();
480 task_runner_->RunUntilIdle();
481 ASSERT_TRUE(Mock::VerifyAndClearExpectations(&proxy_events_));
482
483 // Now bind it successfully, invoke a method but destroy the proxy before
484 // the method reply is dispatched. The DeferredReply should be rejected,
485 // despite the fact that the host gave a successful reply.
486 proxy.reset(new FakeProxy("FakeSvc", &proxy_events_));
487 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
488 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect));
489 cli_->BindService(proxy->GetWeakPtr());
490 task_runner_->RunUntilCheckpoint("on_connect");
491
492 RequestProto req;
493 auto on_reply_sent = task_runner_->CreateCheckpoint("on_reply_sent");
494 EXPECT_CALL(*host_method, OnInvoke(_, _))
495 .WillOnce(Invoke([on_reply_sent](const Frame::InvokeMethod&,
496 Frame::InvokeMethodReply* reply) {
497 ReplyProto reply_args;
498 reply->set_success(true);
499 on_reply_sent();
500 }));
501
502 auto on_reject = task_runner_->CreateCheckpoint("on_reject");
Primiano Tucci5b65c9f2018-01-29 22:58:25 +0000503 Deferred<ProtoMessage> deferred_reply(
504 [on_reject](AsyncResult<ProtoMessage> res) {
505 ASSERT_FALSE(res.success());
506 on_reject();
507 });
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000508 proxy->BeginInvoke("FakeMethod1", req, std::move(deferred_reply));
509 proxy.reset();
510 task_runner_->RunUntilCheckpoint("on_reject");
511 task_runner_->RunUntilCheckpoint("on_reply_sent");
512}
513
514// If the Client object is destroyed before the ServiceProxy, the ServiceProxy
515// should see a Disconnect() call and any pending callback should be rejected.
516TEST_F(ClientImplTest, ClientDestroyedBeforeProxy) {
517 auto* host_svc = host_->AddFakeService("FakeSvc");
518 host_svc->AddFakeMethod("FakeMethod1");
519
520 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
521 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
522 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect));
523 cli_->BindService(proxy->GetWeakPtr());
524 task_runner_->RunUntilCheckpoint("on_connect");
525
526 auto on_reject = task_runner_->CreateCheckpoint("on_reject");
527 DeferredBase deferred_reply([on_reject](AsyncResult<ProtoMessage> res) {
528 ASSERT_FALSE(res.success());
529 on_reject();
530 });
531 RequestProto req;
532 proxy->BeginInvoke("FakeMethod1", req, std::move(deferred_reply));
533 EXPECT_CALL(proxy_events_, OnDisconnect());
534 cli_.reset();
Primiano Tuccib03ba362017-12-06 09:47:41 +0000535 host_.reset(); // Prevent spurious OnInvoke callbacks on the fake host.
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000536 task_runner_->RunUntilCheckpoint("on_reject");
537}
538
539// Test that OnDisconnect() is invoked if the host is not reachable.
540TEST_F(ClientImplTest, HostNotReachable) {
541 host_.reset();
542
543 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
544
545 auto on_disconnect = task_runner_->CreateCheckpoint("on_disconnect");
546 EXPECT_CALL(proxy_events_, OnDisconnect()).WillOnce(Invoke(on_disconnect));
547 cli_->BindService(proxy->GetWeakPtr());
548 task_runner_->RunUntilCheckpoint("on_disconnect");
549}
550
551// Test that OnDisconnect() is invoked if the host shuts down prematurely.
552TEST_F(ClientImplTest, HostDisconnection) {
553 host_->AddFakeService("FakeSvc");
554
555 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
556
557 // Bind |proxy| to the fake host.
558 cli_->BindService(proxy->GetWeakPtr());
559 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
560 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect));
561 task_runner_->RunUntilCheckpoint("on_connect");
562
563 auto on_disconnect = task_runner_->CreateCheckpoint("on_disconnect");
564 EXPECT_CALL(proxy_events_, OnDisconnect()).WillOnce(Invoke(on_disconnect));
565 host_.reset();
566 task_runner_->RunUntilCheckpoint("on_disconnect");
567}
568
569// TODO(primiano): add the tests below.
570// TEST(ClientImplTest, UnparsableReply) {}
571
572} // namespace
573} // namespace ipc
574} // namespace perfetto