blob: 4645443cabfdde8af58adbdcabe39272a6ed2857 [file] [log] [blame]
Primiano Tuccied0ce252017-11-09 19:35:10 +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 "ipc/src/client_impl.h"
18
Primiano Tuccif54cae42017-11-21 19:37:13 +000019#include <stdio.h>
20#include <unistd.h>
21
Primiano Tucci3052b1a2017-11-14 10:51:01 +000022#include <string>
23
Primiano Tuccied0ce252017-11-09 19:35:10 +000024#include "gmock/gmock.h"
25#include "gtest/gtest.h"
26#include "ipc/service_descriptor.h"
27#include "ipc/service_proxy.h"
28#include "ipc/src/buffered_frame_deserializer.h"
29#include "ipc/src/unix_socket.h"
Oystein Eftevaagdd727e42017-12-05 08:49:55 -080030#include "perfetto_base/test/test_task_runner.h"
31#include "perfetto_base/utils.h"
Primiano Tuccied0ce252017-11-09 19:35:10 +000032
Primiano Tucci2ee254a2017-11-15 00:38:48 +000033#include "ipc/src/test/client_unittest_messages.pb.h"
Primiano Tuccied0ce252017-11-09 19:35:10 +000034
35namespace perfetto {
36namespace ipc {
37namespace {
38
39using ::testing::_;
Primiano Tucci3052b1a2017-11-14 10:51:01 +000040using ::testing::InSequence;
Primiano Tuccied0ce252017-11-09 19:35:10 +000041using ::testing::Invoke;
Primiano Tucci3052b1a2017-11-14 10:51:01 +000042using ::testing::Mock;
Primiano Tuccied0ce252017-11-09 19:35:10 +000043
44constexpr char kSockName[] = "/tmp/perfetto_client_impl_unittest.sock";
45
Primiano Tucci3052b1a2017-11-14 10:51:01 +000046// A fake ServiceProxy. This fakes the client-side class that would be
47// auto-generated from .proto-files.
Primiano Tuccied0ce252017-11-09 19:35:10 +000048class FakeProxy : public ServiceProxy {
49 public:
Primiano Tuccied0ce252017-11-09 19:35:10 +000050 FakeProxy(const char* service_name, ServiceProxy::EventListener* el)
51 : ServiceProxy(el), service_name_(service_name) {}
52
53 const ServiceDescriptor& GetDescriptor() override {
Primiano Tucci3052b1a2017-11-14 10:51:01 +000054 auto reply_decoder = [](const std::string& proto) {
55 std::unique_ptr<ProtoMessage> reply(new ReplyProto());
56 EXPECT_TRUE(reply->ParseFromString(proto));
57 return reply;
58 };
Primiano Tuccied0ce252017-11-09 19:35:10 +000059 if (!descriptor_.service_name) {
60 descriptor_.service_name = service_name_;
Primiano Tucci3052b1a2017-11-14 10:51:01 +000061 descriptor_.methods.push_back({"FakeMethod1", nullptr, reply_decoder});
Primiano Tuccied0ce252017-11-09 19:35:10 +000062 }
63 return descriptor_;
64 }
65
66 const char* service_name_;
67 ServiceDescriptor descriptor_;
68};
69
70class MockEventListener : public ServiceProxy::EventListener {
71 public:
Primiano Tucci3052b1a2017-11-14 10:51:01 +000072 MOCK_METHOD0(OnConnect, void());
Primiano Tuccied0ce252017-11-09 19:35:10 +000073 MOCK_METHOD0(OnDisconnect, void());
74};
75
Primiano Tucci3052b1a2017-11-14 10:51:01 +000076// A fake host implementation. Listens on |kSockName| and replies to IPC
77// metohds like a real one.
Primiano Tuccied0ce252017-11-09 19:35:10 +000078class FakeHost : public UnixSocket::EventListener {
79 public:
Primiano Tucci3052b1a2017-11-14 10:51:01 +000080 struct FakeMethod {
81 MethodID id;
82 MOCK_METHOD2(OnInvoke,
83 void(const Frame::InvokeMethod&, Frame::InvokeMethodReply*));
84 }; // FakeMethod.
85
86 struct FakeService {
87 FakeMethod* AddFakeMethod(const std::string& name) {
88 auto it_and_inserted =
89 methods.emplace(name, std::unique_ptr<FakeMethod>(new FakeMethod()));
90 EXPECT_TRUE(it_and_inserted.second);
91 FakeMethod* method = it_and_inserted.first->second.get();
92 method->id = ++last_method_id;
93 return method;
94 }
95
96 ServiceID id;
97 std::map<std::string, std::unique_ptr<FakeMethod>> methods;
98 MethodID last_method_id = 0;
99 }; // FakeService.
Primiano Tuccied0ce252017-11-09 19:35:10 +0000100
101 explicit FakeHost(base::TaskRunner* task_runner) {
102 unlink(kSockName);
103 listening_sock = UnixSocket::Listen(kSockName, this, task_runner);
104 EXPECT_TRUE(listening_sock->is_listening());
105 }
Primiano Tuccied0ce252017-11-09 19:35:10 +0000106 ~FakeHost() override { unlink(kSockName); }
107
Primiano Tucci3052b1a2017-11-14 10:51:01 +0000108 FakeService* AddFakeService(const std::string& name) {
109 auto it_and_inserted =
110 services.emplace(name, std::unique_ptr<FakeService>(new FakeService()));
111 EXPECT_TRUE(it_and_inserted.second);
112 FakeService* svc = it_and_inserted.first->second.get();
113 svc->id = ++last_service_id;
114 return svc;
115 }
116
Primiano Tuccied0ce252017-11-09 19:35:10 +0000117 // UnixSocket::EventListener implementation.
118 void OnNewIncomingConnection(
119 UnixSocket*,
120 std::unique_ptr<UnixSocket> new_connection) override {
121 ASSERT_FALSE(client_sock);
122 client_sock = std::move(new_connection);
123 }
124
Primiano Tuccied0ce252017-11-09 19:35:10 +0000125 void OnDataAvailable(UnixSocket* sock) override {
126 if (sock != client_sock.get())
127 return;
128 auto buf = frame_deserializer.BeginReceive();
129 size_t rsize = client_sock->Receive(buf.data, buf.size);
130 EXPECT_TRUE(frame_deserializer.EndReceive(rsize));
Primiano Tucci3052b1a2017-11-14 10:51:01 +0000131 while (std::unique_ptr<Frame> frame = frame_deserializer.PopNextFrame())
132 OnFrameReceived(*frame);
133 }
134
135 void OnFrameReceived(const Frame& req) {
136 if (req.msg_case() == Frame::kMsgBindService) {
137 auto svc_it = services.find(req.msg_bind_service().service_name());
138 ASSERT_NE(services.end(), svc_it);
139 const FakeService& svc = *svc_it->second.get();
140 Frame reply;
141 reply.set_request_id(req.request_id());
142 reply.mutable_msg_bind_service_reply()->set_success(true);
143 reply.mutable_msg_bind_service_reply()->set_service_id(svc.id);
144 for (const auto& method_it : svc.methods) {
145 auto* method = reply.mutable_msg_bind_service_reply()->add_methods();
146 method->set_name(method_it.first);
147 method->set_id(method_it.second->id);
148 }
149 return Reply(reply);
150 } else if (req.msg_case() == Frame::kMsgInvokeMethod) {
151 // Lookup the service and method.
Primiano Tuccic2025af2017-11-20 12:47:49 +0000152 bool has_more = false;
153 do {
154 Frame reply;
155 reply.set_request_id(req.request_id());
156 for (const auto& svc : services) {
Oystein Eftevaagdd727e42017-12-05 08:49:55 -0800157 if (static_cast<int32_t>(svc.second->id) !=
158 req.msg_invoke_method().service_id())
Primiano Tucci3052b1a2017-11-14 10:51:01 +0000159 continue;
Primiano Tuccic2025af2017-11-20 12:47:49 +0000160 for (const auto& method : svc.second->methods) {
Oystein Eftevaagdd727e42017-12-05 08:49:55 -0800161 if (static_cast<int32_t>(method.second->id) !=
162 req.msg_invoke_method().method_id())
Primiano Tuccic2025af2017-11-20 12:47:49 +0000163 continue;
164 method.second->OnInvoke(req.msg_invoke_method(),
165 reply.mutable_msg_invoke_method_reply());
166 has_more = reply.mutable_msg_invoke_method_reply()->has_more();
167 }
Primiano Tucci3052b1a2017-11-14 10:51:01 +0000168 }
Primiano Tuccic2025af2017-11-20 12:47:49 +0000169 // If either the method or the service are not found, |success| will be
170 // false by default.
171 Reply(reply);
172 } while (has_more);
Primiano Tucci3052b1a2017-11-14 10:51:01 +0000173 } else {
174 FAIL() << "Unknown request";
Primiano Tuccied0ce252017-11-09 19:35:10 +0000175 }
176 }
177
178 void Reply(const Frame& frame) {
179 auto buf = BufferedFrameDeserializer::Serialize(frame);
180 ASSERT_TRUE(client_sock->is_connected());
Primiano Tuccif54cae42017-11-21 19:37:13 +0000181 EXPECT_TRUE(client_sock->Send(buf.data(), buf.size(), next_reply_fd));
182 next_reply_fd = -1;
Primiano Tuccied0ce252017-11-09 19:35:10 +0000183 }
184
185 BufferedFrameDeserializer frame_deserializer;
186 std::unique_ptr<UnixSocket> listening_sock;
187 std::unique_ptr<UnixSocket> client_sock;
Primiano Tucci3052b1a2017-11-14 10:51:01 +0000188 std::map<std::string, std::unique_ptr<FakeService>> services;
189 ServiceID last_service_id = 0;
Primiano Tuccif54cae42017-11-21 19:37:13 +0000190 int next_reply_fd = -1;
Primiano Tucci3052b1a2017-11-14 10:51:01 +0000191}; // FakeHost.
192
193class ClientImplTest : public ::testing::Test {
194 public:
195 void SetUp() override {
196 task_runner_.reset(new base::TestTaskRunner());
197 host_.reset(new FakeHost(task_runner_.get()));
198 cli_ = Client::CreateInstance(kSockName, task_runner_.get());
199 }
200
201 void TearDown() override {
202 cli_.reset();
203 host_.reset();
204 task_runner_->RunUntilIdle();
205 task_runner_.reset();
206 }
207
208 ::testing::StrictMock<MockEventListener> proxy_events_;
209 std::unique_ptr<base::TestTaskRunner> task_runner_;
210 std::unique_ptr<FakeHost> host_;
211 std::unique_ptr<Client> cli_;
Primiano Tuccied0ce252017-11-09 19:35:10 +0000212};
213
Primiano Tucci3052b1a2017-11-14 10:51:01 +0000214TEST_F(ClientImplTest, BindAndInvokeMethod) {
215 auto* host_svc = host_->AddFakeService("FakeSvc");
216 auto* host_method = host_svc->AddFakeMethod("FakeMethod1");
Primiano Tuccied0ce252017-11-09 19:35:10 +0000217
Primiano Tucci3052b1a2017-11-14 10:51:01 +0000218 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
Primiano Tuccied0ce252017-11-09 19:35:10 +0000219
Primiano Tucci3052b1a2017-11-14 10:51:01 +0000220 // Bind |proxy| to the fake host.
221 cli_->BindService(proxy->GetWeakPtr());
222 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
223 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect));
224 task_runner_->RunUntilCheckpoint("on_connect");
Primiano Tuccied0ce252017-11-09 19:35:10 +0000225
226 // Invoke a valid method.
Primiano Tucci3052b1a2017-11-14 10:51:01 +0000227 EXPECT_CALL(*host_method, OnInvoke(_, _))
228 .WillOnce(Invoke(
229 [](const Frame::InvokeMethod& req, Frame::InvokeMethodReply* reply) {
230 RequestProto req_args;
231 EXPECT_TRUE(req_args.ParseFromString(req.args_proto()));
232 EXPECT_EQ("req_data", req_args.data());
233 ReplyProto reply_args;
234 reply->set_reply_proto(reply_args.SerializeAsString());
235 reply->set_success(true);
236 }));
Primiano Tuccied0ce252017-11-09 19:35:10 +0000237
238 RequestProto req;
239 req.set_data("req_data");
Primiano Tucci3052b1a2017-11-14 10:51:01 +0000240 auto on_invoke_reply = task_runner_->CreateCheckpoint("on_invoke_reply");
Primiano Tuccied0ce252017-11-09 19:35:10 +0000241 DeferredBase deferred_reply(
242 [on_invoke_reply](AsyncResult<ProtoMessage> reply) {
243 EXPECT_TRUE(reply.success());
244 on_invoke_reply();
245 });
246 proxy->BeginInvoke("FakeMethod1", req, std::move(deferred_reply));
Primiano Tucci3052b1a2017-11-14 10:51:01 +0000247 task_runner_->RunUntilCheckpoint("on_invoke_reply");
Primiano Tuccied0ce252017-11-09 19:35:10 +0000248
249 // Invoke an invalid method.
Primiano Tucci3052b1a2017-11-14 10:51:01 +0000250 auto on_invalid_invoke = task_runner_->CreateCheckpoint("on_invalid_invoke");
Primiano Tuccied0ce252017-11-09 19:35:10 +0000251 DeferredBase deferred_reply2(
252 [on_invalid_invoke](AsyncResult<ProtoMessage> reply) {
253 EXPECT_FALSE(reply.success());
254 on_invalid_invoke();
255 });
256 RequestProto empty_req;
Primiano Tucci3052b1a2017-11-14 10:51:01 +0000257 proxy->BeginInvoke("InvalidMethod", empty_req, std::move(deferred_reply2));
258 task_runner_->RunUntilCheckpoint("on_invalid_invoke");
Primiano Tuccied0ce252017-11-09 19:35:10 +0000259}
260
Primiano Tuccic2025af2017-11-20 12:47:49 +0000261// Like BindAndInvokeMethod, but this time invoke a streaming method that
262// provides > 1 reply per invocation.
263TEST_F(ClientImplTest, BindAndInvokeStreamingMethod) {
264 auto* host_svc = host_->AddFakeService("FakeSvc");
265 auto* host_method = host_svc->AddFakeMethod("FakeMethod1");
266 const int kNumReplies = 3;
267
268 // Create and bind |proxy| to the fake host.
269 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
270 cli_->BindService(proxy->GetWeakPtr());
271 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
272 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect));
273 task_runner_->RunUntilCheckpoint("on_connect");
274
275 // Invoke a valid method, reply kNumReplies times.
276 int replies_left = kNumReplies;
277 EXPECT_CALL(*host_method, OnInvoke(_, _))
278 .Times(kNumReplies)
279 .WillRepeatedly(Invoke([&replies_left](const Frame::InvokeMethod& req,
280 Frame::InvokeMethodReply* reply) {
281 RequestProto req_args;
282 EXPECT_TRUE(req_args.ParseFromString(req.args_proto()));
283 reply->set_reply_proto(ReplyProto().SerializeAsString());
284 reply->set_success(true);
285 reply->set_has_more(--replies_left > 0);
286 }));
287
288 RequestProto req;
289 req.set_data("req_data");
290 auto on_last_reply = task_runner_->CreateCheckpoint("on_last_reply");
291 int replies_seen = 0;
292 DeferredBase deferred_reply(
293 [on_last_reply, &replies_seen](AsyncResult<ProtoMessage> reply) {
294 EXPECT_TRUE(reply.success());
295 replies_seen++;
296 if (!reply.has_more())
297 on_last_reply();
298 });
299 proxy->BeginInvoke("FakeMethod1", req, std::move(deferred_reply));
300 task_runner_->RunUntilCheckpoint("on_last_reply");
301 ASSERT_EQ(kNumReplies, replies_seen);
302}
303
Primiano Tuccif54cae42017-11-21 19:37:13 +0000304// Like BindAndInvokeMethod, but this time invoke a streaming method that
305// provides > 1 reply per invocation.
306TEST_F(ClientImplTest, ReceiveFileDescriptor) {
307 auto* host_svc = host_->AddFakeService("FakeSvc");
308 auto* host_method = host_svc->AddFakeMethod("FakeMethod1");
309
310 // Create and bind |proxy| to the fake host.
311 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
312 cli_->BindService(proxy->GetWeakPtr());
313 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
314 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect));
315 task_runner_->RunUntilCheckpoint("on_connect");
316
317 FILE* tx_file = tmpfile(); // Automatically unlinked from the filesystem.
318 static constexpr char kFileContent[] = "shared file";
319 fwrite(kFileContent, sizeof(kFileContent), 1, tx_file);
320 fflush(tx_file);
321 host_->next_reply_fd = fileno(tx_file);
322
323 // Invoke a valid method, reply kNumReplies times.
324 EXPECT_CALL(*host_method, OnInvoke(_, _))
325 .WillOnce(Invoke(
326 [](const Frame::InvokeMethod& req, Frame::InvokeMethodReply* reply) {
327 RequestProto req_args;
328 reply->set_reply_proto(ReplyProto().SerializeAsString());
329 reply->set_success(true);
330 }));
331
332 RequestProto req;
333 auto on_reply = task_runner_->CreateCheckpoint("on_reply");
334 DeferredBase deferred_reply([on_reply](AsyncResult<ProtoMessage> reply) {
335 EXPECT_TRUE(reply.success());
336 on_reply();
337 });
338 proxy->BeginInvoke("FakeMethod1", req, std::move(deferred_reply));
339 task_runner_->RunUntilCheckpoint("on_reply");
340
341 fclose(tx_file);
342 base::ScopedFile rx_fd = cli_->TakeReceivedFD();
343 ASSERT_TRUE(rx_fd);
344 char buf[sizeof(kFileContent)] = {};
345 ASSERT_EQ(0, lseek(*rx_fd, 0, SEEK_SET));
Oystein Eftevaagdd727e42017-12-05 08:49:55 -0800346 ASSERT_EQ(static_cast<long>(sizeof(buf)),
347 PERFETTO_EINTR(read(*rx_fd, buf, sizeof(buf))));
Primiano Tuccif54cae42017-11-21 19:37:13 +0000348 ASSERT_STREQ(kFileContent, buf);
349}
350
Primiano Tucci3052b1a2017-11-14 10:51:01 +0000351TEST_F(ClientImplTest, BindSameServiceMultipleTimesShouldFail) {
352 host_->AddFakeService("FakeSvc");
353
354 std::unique_ptr<FakeProxy> proxy[3];
355 for (size_t i = 0; i < base::ArraySize(proxy); i++)
356 proxy[i].reset(new FakeProxy("FakeSvc", &proxy_events_));
357
358 // Bind to the host.
359 for (size_t i = 0; i < base::ArraySize(proxy); i++) {
360 auto checkpoint_name = "on_connect_or_disconnect" + std::to_string(i);
361 auto closure = task_runner_->CreateCheckpoint(checkpoint_name);
362 if (i == 0) {
363 // Only the first call should succeed.
364 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(closure));
365 } else {
366 EXPECT_CALL(proxy_events_, OnDisconnect()).WillOnce(Invoke(closure));
367 }
368 cli_->BindService(proxy[i]->GetWeakPtr());
369 task_runner_->RunUntilCheckpoint(checkpoint_name);
370 }
371}
372
373TEST_F(ClientImplTest, BindRequestsAreQueuedIfNotConnected) {
374 host_->AddFakeService("FakeSvc1");
375 host_->AddFakeService("FakeSvc2");
376
377 std::unique_ptr<FakeProxy> proxy1(new FakeProxy("FakeSvc1", &proxy_events_));
378 std::unique_ptr<FakeProxy> proxy2(new FakeProxy("FakeSvc2", &proxy_events_));
379
380 // Bind the services (in opposite order of creation) before running any task.
381 cli_->BindService(proxy2->GetWeakPtr());
382 cli_->BindService(proxy1->GetWeakPtr());
383
384 InSequence seq;
385 auto on_connect1 = task_runner_->CreateCheckpoint("on_connect1");
386 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect1));
387
388 auto on_connect2 = task_runner_->CreateCheckpoint("on_connect2");
389 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect2));
390
391 task_runner_->RunUntilCheckpoint("on_connect1");
392 task_runner_->RunUntilCheckpoint("on_connect2");
393}
394
395// The deferred callbacks for both binding a service and invoking a method
396// should be dropped if the ServiceProxy object is destroyed prematurely.
397TEST_F(ClientImplTest, DropCallbacksIfServiceProxyIsDestroyed) {
398 auto* host_svc = host_->AddFakeService("FakeSvc");
399 auto* host_method = host_svc->AddFakeMethod("FakeMethod1");
400
401 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
402
403 // First bind the service but destroy it before ClientImpl manages to run any
404 // tasks. No OnConnect() should be called.
405 cli_->BindService(proxy->GetWeakPtr());
406 proxy.reset();
407 task_runner_->RunUntilIdle();
408 ASSERT_TRUE(Mock::VerifyAndClearExpectations(&proxy_events_));
409
410 // Now bind it successfully, invoke a method but destroy the proxy before
411 // the method reply is dispatched. The DeferredReply should be rejected,
412 // despite the fact that the host gave a successful reply.
413 proxy.reset(new FakeProxy("FakeSvc", &proxy_events_));
414 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
415 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect));
416 cli_->BindService(proxy->GetWeakPtr());
417 task_runner_->RunUntilCheckpoint("on_connect");
418
419 RequestProto req;
420 auto on_reply_sent = task_runner_->CreateCheckpoint("on_reply_sent");
421 EXPECT_CALL(*host_method, OnInvoke(_, _))
422 .WillOnce(Invoke([on_reply_sent](const Frame::InvokeMethod&,
423 Frame::InvokeMethodReply* reply) {
424 ReplyProto reply_args;
425 reply->set_success(true);
426 on_reply_sent();
427 }));
428
429 auto on_reject = task_runner_->CreateCheckpoint("on_reject");
430 DeferredBase deferred_reply([on_reject](AsyncResult<ProtoMessage> res) {
431 ASSERT_FALSE(res.success());
432 on_reject();
433 });
434 proxy->BeginInvoke("FakeMethod1", req, std::move(deferred_reply));
435 proxy.reset();
436 task_runner_->RunUntilCheckpoint("on_reject");
437 task_runner_->RunUntilCheckpoint("on_reply_sent");
438}
439
440// If the Client object is destroyed before the ServiceProxy, the ServiceProxy
441// should see a Disconnect() call and any pending callback should be rejected.
442TEST_F(ClientImplTest, ClientDestroyedBeforeProxy) {
443 auto* host_svc = host_->AddFakeService("FakeSvc");
444 host_svc->AddFakeMethod("FakeMethod1");
445
446 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
447 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
448 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect));
449 cli_->BindService(proxy->GetWeakPtr());
450 task_runner_->RunUntilCheckpoint("on_connect");
451
452 auto on_reject = task_runner_->CreateCheckpoint("on_reject");
453 DeferredBase deferred_reply([on_reject](AsyncResult<ProtoMessage> res) {
454 ASSERT_FALSE(res.success());
455 on_reject();
456 });
457 RequestProto req;
458 proxy->BeginInvoke("FakeMethod1", req, std::move(deferred_reply));
459 EXPECT_CALL(proxy_events_, OnDisconnect());
460 cli_.reset();
461 task_runner_->RunUntilCheckpoint("on_reject");
462}
463
464// Test that OnDisconnect() is invoked if the host is not reachable.
465TEST_F(ClientImplTest, HostNotReachable) {
466 host_.reset();
467
468 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
469
470 auto on_disconnect = task_runner_->CreateCheckpoint("on_disconnect");
471 EXPECT_CALL(proxy_events_, OnDisconnect()).WillOnce(Invoke(on_disconnect));
472 cli_->BindService(proxy->GetWeakPtr());
473 task_runner_->RunUntilCheckpoint("on_disconnect");
474}
475
476// Test that OnDisconnect() is invoked if the host shuts down prematurely.
477TEST_F(ClientImplTest, HostDisconnection) {
478 host_->AddFakeService("FakeSvc");
479
480 std::unique_ptr<FakeProxy> proxy(new FakeProxy("FakeSvc", &proxy_events_));
481
482 // Bind |proxy| to the fake host.
483 cli_->BindService(proxy->GetWeakPtr());
484 auto on_connect = task_runner_->CreateCheckpoint("on_connect");
485 EXPECT_CALL(proxy_events_, OnConnect()).WillOnce(Invoke(on_connect));
486 task_runner_->RunUntilCheckpoint("on_connect");
487
488 auto on_disconnect = task_runner_->CreateCheckpoint("on_disconnect");
489 EXPECT_CALL(proxy_events_, OnDisconnect()).WillOnce(Invoke(on_disconnect));
490 host_.reset();
491 task_runner_->RunUntilCheckpoint("on_disconnect");
492}
493
494// TODO(primiano): add the tests below.
Primiano Tuccied0ce252017-11-09 19:35:10 +0000495// TEST(ClientImplTest, UnparsableReply) {}
Primiano Tuccied0ce252017-11-09 19:35:10 +0000496
497} // namespace
498} // namespace ipc
499} // namespace perfetto