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