• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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