1 // Copyright 2024 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/gatt2_server_server.h"
16
17 #include <fuchsia/bluetooth/gatt2/cpp/fidl_test_base.h>
18 #include <gmock/gmock.h>
19 #include <zircon/status.h>
20
21 #include <algorithm>
22 #include <optional>
23
24 #include "fuchsia/bluetooth/cpp/fidl.h"
25 #include "fuchsia/bluetooth/gatt2/cpp/fidl.h"
26 #include "lib/fidl/cpp/interface_handle.h"
27 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/fake_gatt_fixture.h"
28 #include "pw_unit_test/framework.h"
29
30 namespace bthost {
31 namespace {
32
33 namespace fbg = fuchsia::bluetooth::gatt2;
34 namespace fbt = fuchsia::bluetooth;
35
36 const std::vector<uint8_t> kBuffer = {0x00, 0x01, 0x02};
37
BuildSimpleCharacteristic(uint64_t handle)38 fbg::Characteristic BuildSimpleCharacteristic(uint64_t handle) {
39 fbg::Characteristic chrc;
40 fbg::Handle chrc_handle{handle};
41 chrc.set_handle(chrc_handle);
42 chrc.set_type(fbt::Uuid{{6}});
43 chrc.set_properties(fbg::CharacteristicPropertyBits::READ);
44 fbg::AttributePermissions permissions;
45 fbg::SecurityRequirements security;
46 security.set_encryption_required(true);
47 permissions.set_read(std::move(security));
48 chrc.set_permissions(std::move(permissions));
49 return chrc;
50 }
51
BuildSimpleService(uint64_t svc_handle=1,bt::UInt128 svc_type={5},uint64_t chrc_handle=2)52 fbg::ServiceInfo BuildSimpleService(uint64_t svc_handle = 1,
53 bt::UInt128 svc_type = {5},
54 uint64_t chrc_handle = 2) {
55 fbg::ServiceInfo svc_info;
56 svc_info.set_handle(fbg::ServiceHandle{svc_handle});
57 svc_info.set_type(fbt::Uuid{svc_type});
58
59 std::vector<fbg::Characteristic> chrcs;
60 chrcs.push_back(BuildSimpleCharacteristic(chrc_handle));
61 svc_info.set_characteristics(std::move(chrcs));
62
63 return svc_info;
64 }
65
66 class MockLocalService final : private ServerBase<fbg::LocalService> {
67 public:
68 using ReadValueFunction =
69 fit::function<void(fbt::PeerId, fbg::Handle, int32_t, ReadValueCallback)>;
70 using WriteValueFunction = fit::function<void(
71 fbg::LocalServiceWriteValueRequest, WriteValueCallback)>;
72 using CccFunction = fit::function<void(fbt::PeerId,
73 fbg::Handle,
74 bool,
75 bool,
76 CharacteristicConfigurationCallback)>;
77
MockLocalService(fidl::InterfaceRequest<fbg::LocalService> request)78 MockLocalService(fidl::InterfaceRequest<fbg::LocalService> request)
79 : ServerBase<fbg::LocalService>(this, std::move(request)) {
80 set_error_handler([this](zx_status_t status) { error_ = status; });
81 }
82
set_read_value_function(ReadValueFunction func)83 void set_read_value_function(ReadValueFunction func) {
84 read_value_func_ = std::move(func);
85 }
set_write_value_function(WriteValueFunction func)86 void set_write_value_function(WriteValueFunction func) {
87 write_value_func_ = std::move(func);
88 }
set_ccc_function(CccFunction func)89 void set_ccc_function(CccFunction func) { ccc_func_ = std::move(func); }
90
credits() const91 int credits() const { return credits_; }
92
credit_log() const93 const std::vector<uint8_t>& credit_log() const { return credits_log_; }
94
NotifyValue(fbg::ValueChangedParameters update)95 void NotifyValue(fbg::ValueChangedParameters update) {
96 credits_--;
97 binding()->events().OnNotifyValue(std::move(update));
98 }
99
IndicateValue(fbg::ValueChangedParameters update,zx::eventpair confirmation)100 void IndicateValue(fbg::ValueChangedParameters update,
101 zx::eventpair confirmation) {
102 credits_--;
103 binding()->events().OnIndicateValue(std::move(update),
104 std::move(confirmation));
105 }
106
error() const107 std::optional<zx_status_t> error() const { return error_; }
108
109 private:
110 // fbg::LocalService overrides:
CharacteristicConfiguration(fbt::PeerId peer_id,fbg::Handle handle,bool notify,bool indicate,CharacteristicConfigurationCallback callback)111 void CharacteristicConfiguration(
112 fbt::PeerId peer_id,
113 fbg::Handle handle,
114 bool notify,
115 bool indicate,
116 CharacteristicConfigurationCallback callback) override {
117 if (ccc_func_) {
118 ccc_func_(peer_id, handle, notify, indicate, std::move((callback)));
119 }
120 }
ReadValue(fbt::PeerId peer_id,fbg::Handle handle,int32_t offset,ReadValueCallback callback)121 void ReadValue(fbt::PeerId peer_id,
122 fbg::Handle handle,
123 int32_t offset,
124 ReadValueCallback callback) override {
125 if (read_value_func_) {
126 read_value_func_(peer_id, handle, offset, std::move(callback));
127 }
128 }
WriteValue(fbg::LocalServiceWriteValueRequest req,WriteValueCallback callback)129 void WriteValue(fbg::LocalServiceWriteValueRequest req,
130 WriteValueCallback callback) override {
131 if (write_value_func_) {
132 write_value_func_(std::move(req), std::move(callback));
133 }
134 }
PeerUpdate(fbg::LocalServicePeerUpdateRequest req,PeerUpdateCallback callback)135 void PeerUpdate(fbg::LocalServicePeerUpdateRequest req,
136 PeerUpdateCallback callback) override {}
ValueChangedCredit(uint8_t additional_credit)137 void ValueChangedCredit(uint8_t additional_credit) override {
138 credits_ += additional_credit;
139 credits_log_.push_back(additional_credit);
140 }
141
142 ReadValueFunction read_value_func_;
143 WriteValueFunction write_value_func_;
144 CccFunction ccc_func_;
145 // Use signed integer because in tests it is possible to have negative
146 // credits.
147 int credits_ = fbg::INITIAL_VALUE_CHANGED_CREDITS;
148 std::vector<uint8_t> credits_log_;
149 std::optional<zx_status_t> error_;
150 };
151
152 class Gatt2ServerServerTest : public bt::fidl::testing::FakeGattFixture {
153 public:
154 ~Gatt2ServerServerTest() override = default;
155
Gatt2ServerServerTest()156 Gatt2ServerServerTest() {}
157
SetUp()158 void SetUp() override {
159 // Create and connect to production GATT2 Server implementation
160 fidl::InterfaceHandle<fbg::Server> server_handle;
161 server_ = std::make_unique<Gatt2ServerServer>(gatt()->GetWeakPtr(),
162 server_handle.NewRequest());
163 server_ptr_ = server_handle.Bind();
164 }
165
TearDown()166 void TearDown() override {}
167
168 protected:
server_ptr()169 fbg::ServerPtr& server_ptr() { return server_ptr_; }
170
DestroyServer()171 void DestroyServer() { server_.reset(); }
172
173 private:
174 // Proxy interface to the GATT2 Server implementation.
175 fbg::ServerPtr server_ptr_;
176 // Raw GATT2 Server implementation
177 std::unique_ptr<Gatt2ServerServer> server_;
178 };
179
TEST_F(Gatt2ServerServerTest,PublishAndRemoveServiceWithTwoCharacteristicsSuccess)180 TEST_F(Gatt2ServerServerTest,
181 PublishAndRemoveServiceWithTwoCharacteristicsSuccess) {
182 fbg::ServiceInfo svc_info;
183 svc_info.set_handle(fbg::ServiceHandle{1});
184 bt::UInt128 svc_type = {5};
185 svc_info.set_type(fbt::Uuid{svc_type});
186
187 std::vector<fbg::Characteristic> characteristics;
188 characteristics.push_back(BuildSimpleCharacteristic(/*handle=*/2));
189 characteristics.push_back(BuildSimpleCharacteristic(/*handle=*/3));
190 svc_info.set_characteristics(std::move(characteristics));
191
192 fidl::InterfaceHandle<fbg::LocalService> local_service_handle_0;
193 fidl::InterfaceRequest<fbg::LocalService> request =
194 local_service_handle_0.NewRequest();
195
196 int cb_count = 0;
197 auto cb = [&](fbg::Server_PublishService_Result res) {
198 EXPECT_TRUE(res.is_response());
199 cb_count++;
200 };
201 server_ptr()->PublishService(
202 std::move(svc_info), std::move(local_service_handle_0), std::move(cb));
203 RunLoopUntilIdle();
204 EXPECT_EQ(cb_count, 1);
205 ASSERT_EQ(fake_gatt()->local_services().size(), 1u);
206 bt::gatt::Service* service =
207 fake_gatt()->local_services().begin()->second.service.get();
208 EXPECT_EQ(service->type(), svc_type);
209 EXPECT_TRUE(service->primary());
210 ASSERT_EQ(service->characteristics().size(), 2u);
211 EXPECT_EQ(service->characteristics()[0]->id(), 2u);
212 EXPECT_EQ(service->characteristics()[1]->id(), 3u);
213
214 request.Close(ZX_ERR_PEER_CLOSED);
215 RunLoopUntilIdle();
216 EXPECT_EQ(fake_gatt()->local_services().size(), 0u);
217 }
218
TEST_F(Gatt2ServerServerTest,DestroyingServerUnregistersService)219 TEST_F(Gatt2ServerServerTest, DestroyingServerUnregistersService) {
220 bt::UInt128 svc_type = {5};
221 fbg::ServiceInfo svc_info = BuildSimpleService(/*svc_handle=*/1, svc_type);
222
223 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
224 fidl::InterfaceRequest<fbg::LocalService> request =
225 local_service_handle.NewRequest();
226
227 int cb_count = 0;
228 auto cb = [&](fbg::Server_PublishService_Result res) {
229 EXPECT_TRUE(res.is_response());
230 cb_count++;
231 };
232 server_ptr()->PublishService(
233 std::move(svc_info), std::move(local_service_handle), std::move(cb));
234 RunLoopUntilIdle();
235 EXPECT_EQ(cb_count, 1);
236 ASSERT_EQ(fake_gatt()->local_services().size(), 1u);
237 EXPECT_EQ(
238 fake_gatt()->local_services().begin()->second.service->type().value(),
239 svc_type);
240 DestroyServer();
241 EXPECT_EQ(fake_gatt()->local_services().size(), 0u);
242 }
243
TEST_F(Gatt2ServerServerTest,PublishServiceWithoutHandleFails)244 TEST_F(Gatt2ServerServerTest, PublishServiceWithoutHandleFails) {
245 fbg::ServiceInfo svc_info = BuildSimpleService();
246 svc_info.clear_handle();
247
248 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
249 auto request = local_service_handle.NewRequest();
250
251 int cb_count = 0;
252 auto cb = [&](fbg::Server_PublishService_Result res) {
253 ASSERT_TRUE(res.is_err());
254 EXPECT_EQ(res.err(), fbg::PublishServiceError::INVALID_SERVICE_HANDLE);
255 cb_count++;
256 };
257 server_ptr()->PublishService(
258 std::move(svc_info), std::move(local_service_handle), std::move(cb));
259 RunLoopUntilIdle();
260 EXPECT_EQ(cb_count, 1);
261 EXPECT_EQ(fake_gatt()->local_services().size(), 0u);
262 }
263
TEST_F(Gatt2ServerServerTest,PublishServiceWithoutTypeFails)264 TEST_F(Gatt2ServerServerTest, PublishServiceWithoutTypeFails) {
265 fbg::ServiceInfo svc_info = BuildSimpleService();
266 svc_info.clear_type();
267
268 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
269 auto request = local_service_handle.NewRequest();
270
271 int cb_count = 0;
272 auto cb = [&](fbg::Server_PublishService_Result res) {
273 ASSERT_TRUE(res.is_err());
274 EXPECT_EQ(res.err(), fbg::PublishServiceError::INVALID_UUID);
275 cb_count++;
276 };
277 server_ptr()->PublishService(
278 std::move(svc_info), std::move(local_service_handle), std::move(cb));
279 RunLoopUntilIdle();
280 EXPECT_EQ(cb_count, 1);
281 EXPECT_EQ(fake_gatt()->local_services().size(), 0u);
282 }
283
TEST_F(Gatt2ServerServerTest,PublishServiceWithoutCharacteristicsFails)284 TEST_F(Gatt2ServerServerTest, PublishServiceWithoutCharacteristicsFails) {
285 fbg::ServiceInfo svc_info = BuildSimpleService();
286 svc_info.clear_characteristics();
287
288 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
289 auto request = local_service_handle.NewRequest();
290
291 int cb_count = 0;
292 auto cb = [&](fbg::Server_PublishService_Result res) {
293 ASSERT_TRUE(res.is_err());
294 EXPECT_EQ(res.err(), fbg::PublishServiceError::INVALID_CHARACTERISTICS);
295 cb_count++;
296 };
297 server_ptr()->PublishService(
298 std::move(svc_info), std::move(local_service_handle), std::move(cb));
299 RunLoopUntilIdle();
300 EXPECT_EQ(cb_count, 1);
301 EXPECT_EQ(fake_gatt()->local_services().size(), 0u);
302 }
303
TEST_F(Gatt2ServerServerTest,PublishServiceWithReusedHandleFails)304 TEST_F(Gatt2ServerServerTest, PublishServiceWithReusedHandleFails) {
305 fbg::ServiceInfo svc_info_0 = BuildSimpleService();
306
307 fidl::InterfaceHandle<fbg::LocalService> local_service_handle_0;
308 auto request_0 = local_service_handle_0.NewRequest();
309
310 int cb_count_0 = 0;
311 auto cb_0 = [&](fbg::Server_PublishService_Result res) {
312 EXPECT_TRUE(res.is_response());
313 cb_count_0++;
314 };
315 server_ptr()->PublishService(std::move(svc_info_0),
316 std::move(local_service_handle_0),
317 std::move(cb_0));
318 RunLoopUntilIdle();
319 EXPECT_EQ(cb_count_0, 1);
320 EXPECT_EQ(fake_gatt()->local_services().size(), 1u);
321
322 fbg::ServiceInfo svc_info_1 = BuildSimpleService();
323
324 fidl::InterfaceHandle<fbg::LocalService> local_service_handle_1;
325 auto request_1 = local_service_handle_1.NewRequest();
326
327 int cb_count_1 = 0;
328 auto cb_1 = [&](fbg::Server_PublishService_Result res) {
329 ASSERT_TRUE(res.is_err());
330 EXPECT_EQ(res.err(), fbg::PublishServiceError::INVALID_SERVICE_HANDLE);
331 cb_count_1++;
332 };
333 server_ptr()->PublishService(std::move(svc_info_1),
334 std::move(local_service_handle_1),
335 std::move(cb_1));
336 RunLoopUntilIdle();
337 EXPECT_EQ(cb_count_1, 1);
338 EXPECT_EQ(fake_gatt()->local_services().size(), 1u);
339 }
340
TEST_F(Gatt2ServerServerTest,PublishServiceWithReusedHandleAcrossTwoGattServersSuccceeds)341 TEST_F(Gatt2ServerServerTest,
342 PublishServiceWithReusedHandleAcrossTwoGattServersSuccceeds) {
343 // Both services are identical.
344 fbg::ServiceInfo svc_info_0 = BuildSimpleService();
345 fbg::ServiceInfo svc_info_1 = BuildSimpleService();
346
347 fidl::InterfaceHandle<fbg::LocalService> local_service_handle_0;
348 auto request_0 = local_service_handle_0.NewRequest();
349
350 int cb_count_0 = 0;
351 auto cb_0 = [&](fbg::Server_PublishService_Result res) {
352 EXPECT_TRUE(res.is_response());
353 cb_count_0++;
354 };
355 server_ptr()->PublishService(std::move(svc_info_0),
356 std::move(local_service_handle_0),
357 std::move(cb_0));
358 RunLoopUntilIdle();
359 EXPECT_EQ(cb_count_0, 1);
360 EXPECT_EQ(fake_gatt()->local_services().size(), 1u);
361
362 fidl::InterfaceHandle<fbg::LocalService> local_service_handle_1;
363 auto request_1 = local_service_handle_1.NewRequest();
364
365 int cb_count_1 = 0;
366 auto cb_1 = [&](fbg::Server_PublishService_Result res) {
367 EXPECT_TRUE(res.is_response());
368 cb_count_1++;
369 };
370
371 // Create and connect to a second GATT Server implementation
372 fidl::InterfaceHandle<fbg::Server> server_handle_1;
373 auto server_1 = std::make_unique<Gatt2ServerServer>(
374 gatt()->GetWeakPtr(), server_handle_1.NewRequest());
375 fidl::InterfacePtr<fuchsia::bluetooth::gatt2::Server> server_ptr_1 =
376 server_handle_1.Bind();
377 // Publish an identical service.
378 server_ptr_1->PublishService(std::move(svc_info_1),
379 std::move(local_service_handle_1),
380 std::move(cb_1));
381 RunLoopUntilIdle();
382 EXPECT_EQ(cb_count_1, 1);
383 ASSERT_EQ(fake_gatt()->local_services().size(), 2u);
384 }
385
TEST_F(Gatt2ServerServerTest,PublishTwoServicesSuccess)386 TEST_F(Gatt2ServerServerTest, PublishTwoServicesSuccess) {
387 bt::UInt128 svc_type_0 = {5};
388 fbg::ServiceInfo svc_info_0 =
389 BuildSimpleService(/*svc_handle=*/1, svc_type_0);
390
391 fidl::InterfaceHandle<fbg::LocalService> local_service_handle_0;
392 fidl::InterfaceRequest<fbg::LocalService> request_0 =
393 local_service_handle_0.NewRequest();
394
395 int cb_count_0 = 0;
396 auto cb_0 = [&](fbg::Server_PublishService_Result res) {
397 EXPECT_TRUE(res.is_response());
398 cb_count_0++;
399 };
400 server_ptr()->PublishService(std::move(svc_info_0),
401 std::move(local_service_handle_0),
402 std::move(cb_0));
403 RunLoopUntilIdle();
404 EXPECT_EQ(cb_count_0, 1);
405 ASSERT_EQ(fake_gatt()->local_services().size(), 1u);
406 bt::gatt::Service* service =
407 fake_gatt()->local_services().begin()->second.service.get();
408 EXPECT_EQ(service->type(), svc_type_0);
409
410 bt::UInt128 svc_type_1 = {6};
411 fbg::ServiceInfo svc_info_1 =
412 BuildSimpleService(/*svc_handle=*/9, svc_type_1);
413
414 fidl::InterfaceHandle<fbg::LocalService> local_service_handle_1;
415 fidl::InterfaceRequest<fbg::LocalService> request_1 =
416 local_service_handle_1.NewRequest();
417
418 int cb_count_1 = 0;
419 auto cb_1 = [&](fbg::Server_PublishService_Result res) {
420 EXPECT_TRUE(res.is_response());
421 cb_count_1++;
422 };
423 server_ptr()->PublishService(std::move(svc_info_1),
424 std::move(local_service_handle_1),
425 std::move(cb_1));
426 RunLoopUntilIdle();
427 EXPECT_EQ(cb_count_1, 1);
428 ASSERT_EQ(fake_gatt()->local_services().size(), 2u);
429 auto svc_iter = fake_gatt()->local_services().begin();
430 EXPECT_EQ(svc_iter->second.service->type(), svc_type_0);
431 svc_iter++;
432 EXPECT_EQ(svc_iter->second.service->type(), svc_type_1);
433
434 request_0.Close(ZX_ERR_PEER_CLOSED);
435 request_1.Close(ZX_ERR_PEER_CLOSED);
436 RunLoopUntilIdle();
437 EXPECT_EQ(fake_gatt()->local_services().size(), 0u);
438 }
439
TEST_F(Gatt2ServerServerTest,PublishSecondaryService)440 TEST_F(Gatt2ServerServerTest, PublishSecondaryService) {
441 bt::UInt128 svc_type = {5};
442 fbg::ServiceInfo svc_info = BuildSimpleService(/*svc_handle=*/1, svc_type);
443 svc_info.set_kind(fbg::ServiceKind::SECONDARY);
444
445 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
446 fidl::InterfaceRequest<fbg::LocalService> request =
447 local_service_handle.NewRequest();
448
449 int cb_count = 0;
450 auto cb = [&](fbg::Server_PublishService_Result res) {
451 EXPECT_TRUE(res.is_response());
452 cb_count++;
453 };
454 server_ptr()->PublishService(
455 std::move(svc_info), std::move(local_service_handle), std::move(cb));
456 RunLoopUntilIdle();
457 EXPECT_EQ(cb_count, 1);
458 ASSERT_EQ(fake_gatt()->local_services().size(), 1u);
459 auto svc_iter = fake_gatt()->local_services().begin();
460 EXPECT_EQ(svc_iter->second.service->type(), svc_type);
461 EXPECT_FALSE(svc_iter->second.service->primary());
462 }
463
TEST_F(Gatt2ServerServerTest,ReadSuccess)464 TEST_F(Gatt2ServerServerTest, ReadSuccess) {
465 uint64_t svc_handle = 1;
466 fbg::ServiceInfo svc_info;
467 svc_info.set_handle(fbg::ServiceHandle{svc_handle});
468 svc_info.set_type(fbt::Uuid{{5}});
469 fbg::Characteristic chrc;
470 fbg::Handle chrc_handle{2};
471 chrc.set_handle(chrc_handle);
472 chrc.set_type(fbt::Uuid{{0}});
473 chrc.set_properties(fbg::CharacteristicPropertyBits::READ);
474 chrc.set_permissions(fbg::AttributePermissions());
475 std::vector<fbg::Characteristic> chrcs;
476 chrcs.push_back(std::move(chrc));
477 svc_info.set_characteristics(std::move(chrcs));
478
479 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
480 MockLocalService local_svc(local_service_handle.NewRequest());
481
482 int cb_count = 0;
483 auto cb = [&](fbg::Server_PublishService_Result res) {
484 EXPECT_TRUE(res.is_response());
485 cb_count++;
486 };
487 server_ptr()->PublishService(
488 std::move(svc_info), std::move(local_service_handle), std::move(cb));
489 RunLoopUntilIdle();
490 EXPECT_EQ(cb_count, 1);
491 ASSERT_EQ(fake_gatt()->local_services().size(), 1u);
492 auto svc_iter = fake_gatt()->local_services().begin();
493 ASSERT_EQ(svc_iter->second.service->characteristics().size(), 1u);
494
495 bt::gatt::IdType svc_id = svc_iter->first;
496 bt::gatt::IdType chrc_id =
497 svc_iter->second.service->characteristics()[0]->id();
498 bt::PeerId peer_id(99);
499
500 int read_value_count = 0;
501 local_svc.set_read_value_function(
502 [&](fbt::PeerId cb_peer_id,
503 fbg::Handle handle,
504 int32_t offset,
505 fbg::LocalService::ReadValueCallback callback) {
506 read_value_count++;
507 EXPECT_EQ(peer_id.value(), cb_peer_id.value);
508 EXPECT_EQ(handle.value, chrc_handle.value);
509 EXPECT_EQ(offset, 3);
510 callback(fpromise::ok(kBuffer));
511 });
512
513 int read_responder_count = 0;
514 auto read_responder = [&](fit::result<bt::att::ErrorCode> status,
515 const bt::ByteBuffer& value) {
516 read_responder_count++;
517 EXPECT_TRUE(status.is_ok());
518 EXPECT_THAT(value, ::testing::ElementsAreArray(kBuffer));
519 };
520
521 svc_iter->second.read_handler(
522 peer_id, svc_id, chrc_id, /*offset=*/3, read_responder);
523 RunLoopUntilIdle();
524 EXPECT_EQ(read_value_count, 1);
525 EXPECT_EQ(read_responder_count, 1);
526 }
527
TEST_F(Gatt2ServerServerTest,ReadErrorResponse)528 TEST_F(Gatt2ServerServerTest, ReadErrorResponse) {
529 uint64_t svc_handle = 1;
530 fbg::ServiceInfo svc_info;
531 svc_info.set_handle(fbg::ServiceHandle{svc_handle});
532 svc_info.set_type(fbt::Uuid{{5}});
533 fbg::Characteristic chrc;
534 fbg::Handle chrc_handle{2};
535 chrc.set_handle(chrc_handle);
536 chrc.set_type(fbt::Uuid{{0}});
537 chrc.set_properties(fbg::CharacteristicPropertyBits::READ);
538 chrc.set_permissions(fbg::AttributePermissions());
539 std::vector<fbg::Characteristic> chrcs;
540 chrcs.push_back(std::move(chrc));
541 svc_info.set_characteristics(std::move(chrcs));
542
543 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
544 MockLocalService local_svc(local_service_handle.NewRequest());
545
546 int cb_count = 0;
547 auto cb = [&](fbg::Server_PublishService_Result res) {
548 EXPECT_TRUE(res.is_response());
549 cb_count++;
550 };
551 server_ptr()->PublishService(
552 std::move(svc_info), std::move(local_service_handle), std::move(cb));
553 RunLoopUntilIdle();
554 EXPECT_EQ(cb_count, 1);
555 ASSERT_EQ(fake_gatt()->local_services().size(), 1u);
556 auto svc_iter = fake_gatt()->local_services().begin();
557 ASSERT_EQ(svc_iter->second.service->characteristics().size(), 1u);
558
559 bt::gatt::IdType svc_id = svc_iter->first;
560 bt::gatt::IdType chrc_id =
561 svc_iter->second.service->characteristics()[0]->id();
562
563 int read_value_count = 0;
564 local_svc.set_read_value_function(
565 [&](fbt::PeerId cb_peer_id,
566 fbg::Handle handle,
567 int32_t offset,
568 fbg::LocalService::ReadValueCallback callback) {
569 read_value_count++;
570 callback(fpromise::error(fbg::Error::READ_NOT_PERMITTED));
571 });
572
573 int read_responder_count = 0;
574 auto read_responder = [&](fit::result<bt::att::ErrorCode> status,
575 const bt::ByteBuffer& value) {
576 read_responder_count++;
577 ASSERT_TRUE(status.is_error());
578 EXPECT_EQ(status.error_value(), bt::att::ErrorCode::kReadNotPermitted);
579 EXPECT_EQ(value.size(), 0u);
580 };
581
582 svc_iter->second.read_handler(
583 bt::PeerId(42), svc_id, chrc_id, /*offset=*/0, read_responder);
584 RunLoopUntilIdle();
585 EXPECT_EQ(read_value_count, 1);
586 EXPECT_EQ(read_responder_count, 1);
587 }
588
TEST_F(Gatt2ServerServerTest,WriteSuccess)589 TEST_F(Gatt2ServerServerTest, WriteSuccess) {
590 uint64_t svc_handle = 1;
591 fbg::ServiceInfo svc_info;
592 svc_info.set_handle(fbg::ServiceHandle{svc_handle});
593 svc_info.set_type(fbt::Uuid{{5}});
594 fbg::Characteristic chrc;
595 fbg::Handle chrc_handle{2};
596 chrc.set_handle(chrc_handle);
597 chrc.set_type(fbt::Uuid{{0}});
598 chrc.set_properties(fbg::CharacteristicPropertyBits::WRITE);
599 chrc.set_permissions(fbg::AttributePermissions());
600 std::vector<fbg::Characteristic> chrcs;
601 chrcs.push_back(std::move(chrc));
602 svc_info.set_characteristics(std::move(chrcs));
603
604 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
605 MockLocalService local_svc(local_service_handle.NewRequest());
606
607 int cb_count = 0;
608 auto cb = [&](fbg::Server_PublishService_Result res) {
609 EXPECT_TRUE(res.is_response());
610 cb_count++;
611 };
612 server_ptr()->PublishService(
613 std::move(svc_info), std::move(local_service_handle), std::move(cb));
614 RunLoopUntilIdle();
615 EXPECT_EQ(cb_count, 1);
616 ASSERT_EQ(fake_gatt()->local_services().size(), 1u);
617 auto svc_iter = fake_gatt()->local_services().begin();
618 ASSERT_EQ(svc_iter->second.service->characteristics().size(), 1u);
619
620 bt::gatt::IdType svc_id = svc_iter->first;
621 bt::gatt::IdType chrc_id =
622 svc_iter->second.service->characteristics()[0]->id();
623 bt::PeerId peer_id(99);
624 bt::StaticByteBuffer value_buffer(0x00, 0x01, 0x02);
625
626 int write_value_count = 0;
627 local_svc.set_write_value_function(
628 [&](fbg::LocalServiceWriteValueRequest req,
629 fbg::LocalService::WriteValueCallback cb) {
630 write_value_count++;
631 ASSERT_TRUE(req.has_peer_id());
632 EXPECT_EQ(req.peer_id().value, peer_id.value());
633 ASSERT_TRUE(req.has_handle());
634 EXPECT_EQ(req.handle().value, chrc_handle.value);
635 ASSERT_TRUE(req.has_offset());
636 EXPECT_EQ(req.offset(), 3u);
637 ASSERT_TRUE(req.has_value());
638 EXPECT_THAT(req.value(), ::testing::ElementsAreArray(value_buffer));
639 cb(fpromise::ok());
640 });
641 int write_responder_count = 0;
642 auto write_responder = [&](fit::result<bt::att::ErrorCode> status) {
643 write_responder_count++;
644 EXPECT_TRUE(status.is_ok());
645 };
646 svc_iter->second.write_handler(peer_id,
647 svc_id,
648 chrc_id,
649 /*offset=*/3,
650 value_buffer,
651 std::move(write_responder));
652 RunLoopUntilIdle();
653 EXPECT_EQ(write_value_count, 1);
654 EXPECT_EQ(write_responder_count, 1);
655 }
656
TEST_F(Gatt2ServerServerTest,WriteError)657 TEST_F(Gatt2ServerServerTest, WriteError) {
658 uint64_t svc_handle = 1;
659 fbg::ServiceInfo svc_info;
660 svc_info.set_handle(fbg::ServiceHandle{svc_handle});
661 svc_info.set_type(fbt::Uuid{{5}});
662 fbg::Characteristic chrc;
663 fbg::Handle chrc_handle{2};
664 chrc.set_handle(chrc_handle);
665 chrc.set_type(fbt::Uuid{{0}});
666 chrc.set_properties(fbg::CharacteristicPropertyBits::WRITE);
667 chrc.set_permissions(fbg::AttributePermissions());
668 std::vector<fbg::Characteristic> chrcs;
669 chrcs.push_back(std::move(chrc));
670 svc_info.set_characteristics(std::move(chrcs));
671
672 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
673 MockLocalService local_svc(local_service_handle.NewRequest());
674
675 int cb_count = 0;
676 auto cb = [&](fbg::Server_PublishService_Result res) {
677 EXPECT_TRUE(res.is_response());
678 cb_count++;
679 };
680 server_ptr()->PublishService(
681 std::move(svc_info), std::move(local_service_handle), std::move(cb));
682 RunLoopUntilIdle();
683 EXPECT_EQ(cb_count, 1);
684 ASSERT_EQ(fake_gatt()->local_services().size(), 1u);
685 auto svc_iter = fake_gatt()->local_services().begin();
686 ASSERT_EQ(svc_iter->second.service->characteristics().size(), 1u);
687
688 bt::gatt::IdType svc_id = svc_iter->first;
689 bt::gatt::IdType chrc_id =
690 svc_iter->second.service->characteristics()[0]->id();
691
692 int write_value_count = 0;
693 local_svc.set_write_value_function(
694 [&](fbg::LocalServiceWriteValueRequest req,
695 fbg::LocalService::WriteValueCallback cb) {
696 write_value_count++;
697 cb(fpromise::error(fbg::Error::WRITE_NOT_PERMITTED));
698 });
699 int write_responder_count = 0;
700 auto write_responder = [&](fit::result<bt::att::ErrorCode> status) {
701 write_responder_count++;
702 ASSERT_TRUE(status.is_error());
703 EXPECT_EQ(status.error_value(), bt::att::ErrorCode::kWriteNotPermitted);
704 };
705 svc_iter->second.write_handler(bt::PeerId(4),
706 svc_id,
707 chrc_id,
708 /*offset=*/0,
709 bt::BufferView(),
710 std::move(write_responder));
711 RunLoopUntilIdle();
712 EXPECT_EQ(write_value_count, 1);
713 EXPECT_EQ(write_responder_count, 1);
714 }
715
TEST_F(Gatt2ServerServerTest,ClientCharacteristicConfiguration)716 TEST_F(Gatt2ServerServerTest, ClientCharacteristicConfiguration) {
717 const uint64_t chrc_handle = 2;
718 fbg::ServiceInfo svc_info =
719 BuildSimpleService(/*svc_handle=*/1, /*svc_type=*/{5}, chrc_handle);
720
721 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
722 MockLocalService local_svc = local_service_handle.NewRequest();
723
724 int cb_count = 0;
725 auto cb = [&](fbg::Server_PublishService_Result res) {
726 EXPECT_TRUE(res.is_response());
727 cb_count++;
728 };
729 server_ptr()->PublishService(
730 std::move(svc_info), std::move(local_service_handle), std::move(cb));
731 RunLoopUntilIdle();
732 EXPECT_EQ(cb_count, 1);
733 ASSERT_EQ(fake_gatt()->local_services().size(), 1u);
734 auto svc_iter = fake_gatt()->local_services().begin();
735 bt::gatt::IdType svc_id = svc_iter->first;
736
737 bt::PeerId peer_id(4);
738 int ccc_count = 0;
739 local_svc.set_ccc_function(
740 [&](fbt::PeerId cb_peer_id,
741 fbg::Handle handle,
742 bool notify,
743 bool indicate,
744 fbg::LocalService::CharacteristicConfigurationCallback cb) {
745 ccc_count++;
746 EXPECT_EQ(peer_id.value(), cb_peer_id.value);
747 EXPECT_EQ(handle.value, chrc_handle);
748 EXPECT_TRUE(notify);
749 EXPECT_FALSE(indicate);
750 cb();
751 });
752 svc_iter->second.ccc_callback(
753 svc_id, chrc_handle, peer_id, /*notify=*/true, /*indicate=*/false);
754 RunLoopUntilIdle();
755 EXPECT_EQ(ccc_count, 1);
756 }
757
TEST_F(Gatt2ServerServerTest,IndicateAllPeers)758 TEST_F(Gatt2ServerServerTest, IndicateAllPeers) {
759 const uint64_t chrc_handle = 2;
760 fbg::ServiceInfo svc_info =
761 BuildSimpleService(/*svc_handle=*/1, /*svc_type=*/{5}, chrc_handle);
762
763 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
764 MockLocalService local_svc = local_service_handle.NewRequest();
765
766 int cb_count = 0;
767 auto cb = [&](fbg::Server_PublishService_Result res) {
768 EXPECT_TRUE(res.is_response());
769 cb_count++;
770 };
771 server_ptr()->PublishService(
772 std::move(svc_info), std::move(local_service_handle), std::move(cb));
773 RunLoopUntilIdle();
774 EXPECT_EQ(cb_count, 1);
775 ASSERT_EQ(fake_gatt()->local_services().size(), 1u);
776 auto svc_iter = fake_gatt()->local_services().begin();
777
778 fbg::ValueChangedParameters params_0;
779 params_0.set_handle(fbg::Handle{chrc_handle});
780 std::vector<uint8_t> buffer = {0x00, 0x01, 0x02};
781 params_0.set_value(buffer);
782 zx::eventpair confirm_ours_0;
783 zx::eventpair confirm_theirs_0;
784 zx::eventpair::create(/*options=*/0, &confirm_ours_0, &confirm_theirs_0);
785 local_svc.IndicateValue(std::move(params_0), std::move(confirm_theirs_0));
786 RunLoopUntilIdle();
787 ASSERT_EQ(svc_iter->second.updates.size(), 1u);
788 EXPECT_EQ(svc_iter->second.updates[0].chrc_id, chrc_handle);
789 EXPECT_EQ(svc_iter->second.updates[0].value, buffer);
790
791 // Eventpair should not be signalled until indicate_cb called.
792 zx_signals_t observed;
793 zx_status_t status =
794 confirm_ours_0.wait_one(ZX_EVENTPAIR_PEER_CLOSED | ZX_EVENTPAIR_SIGNALED,
795 /*deadline=*/zx::time(0),
796 &observed);
797 ASSERT_EQ(status, ZX_ERR_TIMED_OUT);
798 EXPECT_EQ(observed, 0u);
799
800 svc_iter->second.updates[0].indicate_cb(fit::ok());
801
802 status =
803 confirm_ours_0.wait_one(ZX_EVENTPAIR_PEER_CLOSED | ZX_EVENTPAIR_SIGNALED,
804 /*deadline=*/zx::time(0),
805 &observed);
806 ASSERT_EQ(status, ZX_OK);
807 // The eventpair should have been signaled before it was closed.
808 EXPECT_EQ(observed, ZX_EVENTPAIR_SIGNALED | ZX_EVENTPAIR_PEER_CLOSED);
809 observed = 0;
810
811 // Also test with an empty peer_ids vector
812 fbg::ValueChangedParameters params_1;
813 params_1.set_peer_ids({});
814 params_1.set_handle(fbg::Handle{chrc_handle});
815 params_1.set_value(buffer);
816 zx::eventpair confirm_ours_1;
817 zx::eventpair confirm_theirs_1;
818 zx::eventpair::create(/*options=*/0, &confirm_ours_1, &confirm_theirs_1);
819 local_svc.IndicateValue(std::move(params_1), std::move(confirm_theirs_1));
820 RunLoopUntilIdle();
821 ASSERT_EQ(svc_iter->second.updates.size(), 2u);
822 status =
823 confirm_ours_1.wait_one(ZX_EVENTPAIR_PEER_CLOSED | ZX_EVENTPAIR_SIGNALED,
824 /*deadline=*/zx::time(0),
825 &observed);
826 ASSERT_EQ(status, ZX_ERR_TIMED_OUT);
827 EXPECT_EQ(observed, 0u);
828
829 svc_iter->second.updates[1].indicate_cb(fit::ok());
830
831 status =
832 confirm_ours_1.wait_one(ZX_EVENTPAIR_PEER_CLOSED | ZX_EVENTPAIR_SIGNALED,
833 /*deadline=*/zx::time(0),
834 &observed);
835 ASSERT_EQ(status, ZX_OK);
836 EXPECT_EQ(observed, ZX_EVENTPAIR_SIGNALED | ZX_EVENTPAIR_PEER_CLOSED);
837 }
838
TEST_F(Gatt2ServerServerTest,IndicateAllPeersError)839 TEST_F(Gatt2ServerServerTest, IndicateAllPeersError) {
840 const uint64_t chrc_handle = 2;
841 fbg::ServiceInfo svc_info =
842 BuildSimpleService(/*svc_handle=*/1, /*svc_type=*/{5}, chrc_handle);
843
844 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
845 MockLocalService local_svc = local_service_handle.NewRequest();
846
847 int cb_count = 0;
848 auto cb = [&](fbg::Server_PublishService_Result res) {
849 EXPECT_TRUE(res.is_response());
850 cb_count++;
851 };
852 server_ptr()->PublishService(
853 std::move(svc_info), std::move(local_service_handle), std::move(cb));
854 RunLoopUntilIdle();
855 EXPECT_EQ(cb_count, 1);
856 ASSERT_EQ(fake_gatt()->local_services().size(), 1u);
857 auto svc_iter = fake_gatt()->local_services().begin();
858
859 fbg::ValueChangedParameters params;
860 params.set_handle(fbg::Handle{chrc_handle});
861 std::vector<uint8_t> buffer = {0x00, 0x01, 0x02};
862 params.set_value(buffer);
863 zx::eventpair confirm_ours;
864 zx::eventpair confirm_theirs;
865 zx::eventpair::create(/*options=*/0, &confirm_ours, &confirm_theirs);
866 local_svc.IndicateValue(std::move(params), std::move(confirm_theirs));
867 RunLoopUntilIdle();
868 ASSERT_EQ(svc_iter->second.updates.size(), 1u);
869 EXPECT_EQ(svc_iter->second.updates[0].chrc_id, chrc_handle);
870 EXPECT_EQ(svc_iter->second.updates[0].value, buffer);
871
872 // Eventpair should not be signalled until indicate_cb called.
873 zx_signals_t observed;
874 zx_status_t status =
875 confirm_ours.wait_one(ZX_EVENTPAIR_PEER_CLOSED | ZX_EVENTPAIR_SIGNALED,
876 /*deadline=*/zx::time(0),
877 &observed);
878 ASSERT_EQ(status, ZX_ERR_TIMED_OUT);
879 EXPECT_EQ(observed, 0u);
880
881 svc_iter->second.updates[0].indicate_cb(
882 fit::error(bt::att::ErrorCode::kUnlikelyError));
883
884 status =
885 confirm_ours.wait_one(ZX_EVENTPAIR_PEER_CLOSED | ZX_EVENTPAIR_SIGNALED,
886 /*deadline=*/zx::time(0),
887 &observed);
888 ASSERT_EQ(status, ZX_OK);
889 EXPECT_EQ(observed, ZX_EVENTPAIR_PEER_CLOSED);
890 }
891
TEST_F(Gatt2ServerServerTest,IndicateValueChangedParametersMissingHandleClosesService)892 TEST_F(Gatt2ServerServerTest,
893 IndicateValueChangedParametersMissingHandleClosesService) {
894 const uint64_t chrc_handle = 2;
895 fbg::ServiceInfo svc_info =
896 BuildSimpleService(/*svc_handle=*/1, /*svc_type=*/{5}, chrc_handle);
897
898 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
899 MockLocalService local_svc = local_service_handle.NewRequest();
900
901 int cb_count = 0;
902 auto cb = [&](fbg::Server_PublishService_Result res) {
903 EXPECT_TRUE(res.is_response());
904 cb_count++;
905 };
906 server_ptr()->PublishService(
907 std::move(svc_info), std::move(local_service_handle), std::move(cb));
908 RunLoopUntilIdle();
909 EXPECT_EQ(cb_count, 1);
910 ASSERT_EQ(fake_gatt()->local_services().size(), 1u);
911 ASSERT_FALSE(local_svc.error());
912
913 // No handle is set.
914 fbg::ValueChangedParameters params_0;
915 std::vector<uint8_t> buffer = {0x00, 0x01, 0x02};
916 params_0.set_value(buffer);
917 zx::eventpair confirm_ours_0;
918 zx::eventpair confirm_theirs_0;
919 zx::eventpair::create(/*options=*/0, &confirm_ours_0, &confirm_theirs_0);
920 local_svc.IndicateValue(std::move(params_0), std::move(confirm_theirs_0));
921 RunLoopUntilIdle();
922 ASSERT_TRUE(local_svc.error());
923 EXPECT_EQ(local_svc.error().value(), ZX_ERR_PEER_CLOSED);
924 EXPECT_TRUE(fake_gatt()->local_services().empty());
925 zx_signals_t observed;
926 zx_status_t status =
927 confirm_ours_0.wait_one(ZX_EVENTPAIR_PEER_CLOSED | ZX_EVENTPAIR_SIGNALED,
928 /*deadline=*/zx::time(0),
929 &observed);
930 ASSERT_EQ(status, ZX_OK);
931 EXPECT_EQ(observed, ZX_EVENTPAIR_PEER_CLOSED);
932 }
933
TEST_F(Gatt2ServerServerTest,IndicateValueChangedParametersMissingValueClosesService)934 TEST_F(Gatt2ServerServerTest,
935 IndicateValueChangedParametersMissingValueClosesService) {
936 const uint64_t chrc_handle = 2;
937 fbg::ServiceInfo svc_info =
938 BuildSimpleService(/*svc_handle=*/1, /*svc_type=*/{5}, chrc_handle);
939
940 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
941 MockLocalService local_svc = local_service_handle.NewRequest();
942
943 int cb_count = 0;
944 auto cb = [&](fbg::Server_PublishService_Result res) {
945 EXPECT_TRUE(res.is_response());
946 cb_count++;
947 };
948 server_ptr()->PublishService(
949 std::move(svc_info), std::move(local_service_handle), std::move(cb));
950 RunLoopUntilIdle();
951 EXPECT_EQ(cb_count, 1);
952 ASSERT_FALSE(local_svc.error());
953 ASSERT_EQ(fake_gatt()->local_services().size(), 1u);
954
955 // No value is set.
956 fbg::ValueChangedParameters params_1;
957 params_1.set_handle(fbg::Handle{chrc_handle});
958 zx::eventpair confirm_ours_1;
959 zx::eventpair confirm_theirs_1;
960 zx::eventpair::create(/*options=*/0, &confirm_ours_1, &confirm_theirs_1);
961 local_svc.IndicateValue(std::move(params_1), std::move(confirm_theirs_1));
962 RunLoopUntilIdle();
963 ASSERT_TRUE(local_svc.error());
964 EXPECT_EQ(local_svc.error().value(), ZX_ERR_PEER_CLOSED);
965 EXPECT_TRUE(fake_gatt()->local_services().empty());
966 zx_signals_t observed;
967 zx_status_t status =
968 confirm_ours_1.wait_one(ZX_EVENTPAIR_PEER_CLOSED | ZX_EVENTPAIR_SIGNALED,
969 /*deadline=*/zx::time(0),
970 &observed);
971 ASSERT_EQ(status, ZX_OK);
972 EXPECT_EQ(observed, ZX_EVENTPAIR_PEER_CLOSED);
973 }
974
TEST_F(Gatt2ServerServerTest,Indicate2PeersSuccess)975 TEST_F(Gatt2ServerServerTest, Indicate2PeersSuccess) {
976 const uint64_t chrc_handle = 2;
977 fbg::ServiceInfo svc_info =
978 BuildSimpleService(/*svc_handle=*/1, /*svc_type=*/{5}, chrc_handle);
979
980 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
981 MockLocalService local_svc = local_service_handle.NewRequest();
982
983 int cb_count = 0;
984 auto cb = [&](fbg::Server_PublishService_Result res) {
985 EXPECT_TRUE(res.is_response());
986 cb_count++;
987 };
988 server_ptr()->PublishService(
989 std::move(svc_info), std::move(local_service_handle), std::move(cb));
990 RunLoopUntilIdle();
991 EXPECT_EQ(cb_count, 1);
992 ASSERT_EQ(fake_gatt()->local_services().size(), 1u);
993 auto svc_iter = fake_gatt()->local_services().begin();
994
995 bt::PeerId peer_0(0);
996 bt::PeerId peer_1(1);
997 fbg::ValueChangedParameters params;
998 params.set_handle(fbg::Handle{chrc_handle});
999 std::vector<uint8_t> buffer = {0x00, 0x01, 0x02};
1000 params.set_value(buffer);
1001 params.set_peer_ids(
1002 {fbt::PeerId{peer_0.value()}, fbt::PeerId{peer_1.value()}});
1003 zx::eventpair confirm_ours;
1004 zx::eventpair confirm_theirs;
1005 zx::eventpair::create(/*options=*/0, &confirm_ours, &confirm_theirs);
1006 local_svc.IndicateValue(std::move(params), std::move(confirm_theirs));
1007 RunLoopUntilIdle();
1008 ASSERT_EQ(svc_iter->second.updates.size(), 2u);
1009 EXPECT_EQ(svc_iter->second.updates[0].chrc_id, chrc_handle);
1010 EXPECT_EQ(svc_iter->second.updates[0].value, buffer);
1011 EXPECT_THAT(svc_iter->second.updates[0].peer, ::testing::Optional(peer_0));
1012 EXPECT_EQ(svc_iter->second.updates[1].chrc_id, chrc_handle);
1013 EXPECT_EQ(svc_iter->second.updates[1].value, buffer);
1014 EXPECT_THAT(svc_iter->second.updates[1].peer, ::testing::Optional(peer_1));
1015
1016 // Eventpair should not be signaled until indicate_cb called for both peers.
1017 zx_signals_t observed;
1018 zx_status_t status =
1019 confirm_ours.wait_one(ZX_EVENTPAIR_PEER_CLOSED | ZX_EVENTPAIR_SIGNALED,
1020 /*deadline=*/zx::time(0),
1021 &observed);
1022 ASSERT_EQ(status, ZX_ERR_TIMED_OUT);
1023
1024 svc_iter->second.updates[1].indicate_cb(fit::ok());
1025
1026 status =
1027 confirm_ours.wait_one(ZX_EVENTPAIR_PEER_CLOSED | ZX_EVENTPAIR_SIGNALED,
1028 /*deadline=*/zx::time(0),
1029 &observed);
1030 ASSERT_EQ(status, ZX_ERR_TIMED_OUT);
1031
1032 svc_iter->second.updates[0].indicate_cb(fit::ok());
1033
1034 status =
1035 confirm_ours.wait_one(ZX_EVENTPAIR_PEER_CLOSED | ZX_EVENTPAIR_SIGNALED,
1036 /*deadline=*/zx::time(0),
1037 &observed);
1038 ASSERT_EQ(status, ZX_OK);
1039 EXPECT_EQ(observed, ZX_EVENTPAIR_PEER_CLOSED | ZX_EVENTPAIR_SIGNALED);
1040 }
1041
TEST_F(Gatt2ServerServerTest,Indicate2PeersFirstOneFails)1042 TEST_F(Gatt2ServerServerTest, Indicate2PeersFirstOneFails) {
1043 const uint64_t chrc_handle = 2;
1044 fbg::ServiceInfo svc_info =
1045 BuildSimpleService(/*svc_handle=*/1, /*svc_type=*/{5}, chrc_handle);
1046
1047 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
1048 MockLocalService local_svc = local_service_handle.NewRequest();
1049
1050 int cb_count = 0;
1051 auto cb = [&](fbg::Server_PublishService_Result res) {
1052 EXPECT_TRUE(res.is_response());
1053 cb_count++;
1054 };
1055 server_ptr()->PublishService(
1056 std::move(svc_info), std::move(local_service_handle), std::move(cb));
1057 RunLoopUntilIdle();
1058 EXPECT_EQ(cb_count, 1);
1059 ASSERT_EQ(fake_gatt()->local_services().size(), 1u);
1060 auto svc_iter = fake_gatt()->local_services().begin();
1061
1062 fbg::ValueChangedParameters params;
1063 params.set_handle(fbg::Handle{chrc_handle});
1064 params.set_value(kBuffer);
1065 params.set_peer_ids({fbt::PeerId{0}, fbt::PeerId{1}});
1066 zx::eventpair confirm_ours;
1067 zx::eventpair confirm_theirs;
1068 zx::eventpair::create(/*options=*/0, &confirm_ours, &confirm_theirs);
1069 local_svc.IndicateValue(std::move(params), std::move(confirm_theirs));
1070 RunLoopUntilIdle();
1071 ASSERT_EQ(svc_iter->second.updates.size(), 2u);
1072
1073 zx_signals_t observed;
1074 zx_status_t status =
1075 confirm_ours.wait_one(ZX_EVENTPAIR_PEER_CLOSED | ZX_EVENTPAIR_SIGNALED,
1076 /*deadline=*/zx::time(0),
1077 &observed);
1078 ASSERT_EQ(status, ZX_ERR_TIMED_OUT);
1079
1080 svc_iter->second.updates[0].indicate_cb(
1081 fit::error(bt::att::ErrorCode::kUnlikelyError));
1082
1083 status =
1084 confirm_ours.wait_one(ZX_EVENTPAIR_PEER_CLOSED | ZX_EVENTPAIR_SIGNALED,
1085 /*deadline=*/zx::time(0),
1086 &observed);
1087 ASSERT_EQ(status, ZX_OK);
1088 EXPECT_EQ(observed, ZX_EVENTPAIR_PEER_CLOSED);
1089
1090 svc_iter->second.updates[1].indicate_cb(fit::ok());
1091 }
1092
TEST_F(Gatt2ServerServerTest,Indicate2PeersBothFail)1093 TEST_F(Gatt2ServerServerTest, Indicate2PeersBothFail) {
1094 const uint64_t chrc_handle = 2;
1095 fbg::ServiceInfo svc_info =
1096 BuildSimpleService(/*svc_handle=*/1, /*svc_type=*/{5}, chrc_handle);
1097
1098 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
1099 MockLocalService local_svc = local_service_handle.NewRequest();
1100
1101 int cb_count = 0;
1102 auto cb = [&](fbg::Server_PublishService_Result res) {
1103 EXPECT_TRUE(res.is_response());
1104 cb_count++;
1105 };
1106 server_ptr()->PublishService(
1107 std::move(svc_info), std::move(local_service_handle), std::move(cb));
1108 RunLoopUntilIdle();
1109 EXPECT_EQ(cb_count, 1);
1110 ASSERT_EQ(fake_gatt()->local_services().size(), 1u);
1111 auto svc_iter = fake_gatt()->local_services().begin();
1112
1113 fbg::ValueChangedParameters params;
1114 params.set_handle(fbg::Handle{chrc_handle});
1115 params.set_value(kBuffer);
1116 params.set_peer_ids({fbt::PeerId{0}, fbt::PeerId{1}});
1117 zx::eventpair confirm_ours;
1118 zx::eventpair confirm_theirs;
1119 zx::eventpair::create(/*options=*/0, &confirm_ours, &confirm_theirs);
1120 local_svc.IndicateValue(std::move(params), std::move(confirm_theirs));
1121 RunLoopUntilIdle();
1122 ASSERT_EQ(svc_iter->second.updates.size(), 2u);
1123
1124 zx_signals_t observed;
1125 zx_status_t status =
1126 confirm_ours.wait_one(ZX_EVENTPAIR_PEER_CLOSED | ZX_EVENTPAIR_SIGNALED,
1127 /*deadline=*/zx::time(0),
1128 &observed);
1129 ASSERT_EQ(status, ZX_ERR_TIMED_OUT);
1130
1131 svc_iter->second.updates[1].indicate_cb(
1132 fit::error(bt::att::ErrorCode::kUnlikelyError));
1133
1134 status =
1135 confirm_ours.wait_one(ZX_EVENTPAIR_PEER_CLOSED | ZX_EVENTPAIR_SIGNALED,
1136 /*deadline=*/zx::time(0),
1137 &observed);
1138 ASSERT_EQ(status, ZX_OK);
1139 EXPECT_EQ(observed, ZX_EVENTPAIR_PEER_CLOSED);
1140
1141 svc_iter->second.updates[0].indicate_cb(
1142 fit::error(bt::att::ErrorCode::kUnlikelyError));
1143 }
1144
TEST_F(Gatt2ServerServerTest,NotifyAllPeers)1145 TEST_F(Gatt2ServerServerTest, NotifyAllPeers) {
1146 const uint64_t chrc_handle = 2;
1147 fbg::ServiceInfo svc_info =
1148 BuildSimpleService(/*svc_handle=*/1, /*svc_type=*/{5}, chrc_handle);
1149
1150 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
1151 MockLocalService local_svc = local_service_handle.NewRequest();
1152
1153 int cb_count = 0;
1154 auto cb = [&](fbg::Server_PublishService_Result res) {
1155 EXPECT_TRUE(res.is_response());
1156 cb_count++;
1157 };
1158 server_ptr()->PublishService(
1159 std::move(svc_info), std::move(local_service_handle), std::move(cb));
1160 RunLoopUntilIdle();
1161 EXPECT_EQ(cb_count, 1);
1162 ASSERT_EQ(fake_gatt()->local_services().size(), 1u);
1163 auto svc_iter = fake_gatt()->local_services().begin();
1164
1165 fbg::ValueChangedParameters params_0;
1166 params_0.set_handle(fbg::Handle{chrc_handle});
1167 params_0.set_value(kBuffer);
1168 local_svc.NotifyValue(std::move(params_0));
1169 RunLoopUntilIdle();
1170 ASSERT_EQ(svc_iter->second.updates.size(), 1u);
1171 EXPECT_EQ(svc_iter->second.updates[0].chrc_id, chrc_handle);
1172 EXPECT_EQ(svc_iter->second.updates[0].value, kBuffer);
1173 EXPECT_FALSE(svc_iter->second.updates[0].peer);
1174 EXPECT_FALSE(svc_iter->second.updates[0].indicate_cb);
1175
1176 // Also test with an empty peer_ids vector
1177 fbg::ValueChangedParameters params_1;
1178 params_1.set_peer_ids({});
1179 params_1.set_handle(fbg::Handle{chrc_handle});
1180 params_1.set_value(kBuffer);
1181 local_svc.NotifyValue(std::move(params_1));
1182 RunLoopUntilIdle();
1183 ASSERT_EQ(svc_iter->second.updates.size(), 2u);
1184 EXPECT_EQ(svc_iter->second.updates[1].chrc_id, chrc_handle);
1185 EXPECT_EQ(svc_iter->second.updates[1].value, kBuffer);
1186 EXPECT_FALSE(svc_iter->second.updates[1].peer);
1187 EXPECT_FALSE(svc_iter->second.updates[1].indicate_cb);
1188 }
1189
TEST_F(Gatt2ServerServerTest,NotifyTwoPeers)1190 TEST_F(Gatt2ServerServerTest, NotifyTwoPeers) {
1191 const uint64_t chrc_handle = 2;
1192 fbg::ServiceInfo svc_info =
1193 BuildSimpleService(/*svc_handle=*/1, /*svc_type=*/{5}, chrc_handle);
1194
1195 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
1196 MockLocalService local_svc = local_service_handle.NewRequest();
1197
1198 int cb_count = 0;
1199 auto cb = [&](fbg::Server_PublishService_Result res) {
1200 EXPECT_TRUE(res.is_response());
1201 cb_count++;
1202 };
1203 server_ptr()->PublishService(
1204 std::move(svc_info), std::move(local_service_handle), std::move(cb));
1205 RunLoopUntilIdle();
1206 EXPECT_EQ(cb_count, 1);
1207 ASSERT_EQ(fake_gatt()->local_services().size(), 1u);
1208 auto svc_iter = fake_gatt()->local_services().begin();
1209
1210 fbg::ValueChangedParameters params_0;
1211 params_0.set_handle(fbg::Handle{chrc_handle});
1212 params_0.set_value(kBuffer);
1213 params_0.set_peer_ids({fbt::PeerId{0}, fbt::PeerId{1}});
1214 local_svc.NotifyValue(std::move(params_0));
1215 RunLoopUntilIdle();
1216 ASSERT_EQ(svc_iter->second.updates.size(), 2u);
1217 EXPECT_EQ(svc_iter->second.updates[0].chrc_id, chrc_handle);
1218 EXPECT_EQ(svc_iter->second.updates[0].value, kBuffer);
1219 EXPECT_THAT(svc_iter->second.updates[0].peer,
1220 ::testing::Optional(bt::PeerId(0)));
1221 EXPECT_FALSE(svc_iter->second.updates[0].indicate_cb);
1222 EXPECT_EQ(svc_iter->second.updates[1].chrc_id, chrc_handle);
1223 EXPECT_EQ(svc_iter->second.updates[1].value, kBuffer);
1224 EXPECT_THAT(svc_iter->second.updates[1].peer,
1225 ::testing::Optional(bt::PeerId(1)));
1226 EXPECT_FALSE(svc_iter->second.updates[1].indicate_cb);
1227 }
1228
TEST_F(Gatt2ServerServerTest,NotifyInvalidParametersMissingHandleClosesService)1229 TEST_F(Gatt2ServerServerTest,
1230 NotifyInvalidParametersMissingHandleClosesService) {
1231 const uint64_t chrc_handle = 2;
1232 fbg::ServiceInfo svc_info =
1233 BuildSimpleService(/*svc_handle=*/1, /*svc_type=*/{5}, chrc_handle);
1234
1235 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
1236 MockLocalService local_svc = local_service_handle.NewRequest();
1237
1238 int cb_count = 0;
1239 auto cb = [&](fbg::Server_PublishService_Result res) {
1240 EXPECT_TRUE(res.is_response());
1241 cb_count++;
1242 };
1243 server_ptr()->PublishService(
1244 std::move(svc_info), std::move(local_service_handle), std::move(cb));
1245 RunLoopUntilIdle();
1246 EXPECT_EQ(cb_count, 1);
1247 ASSERT_EQ(fake_gatt()->local_services().size(), 1u);
1248 ASSERT_FALSE(local_svc.error());
1249
1250 // Missing handle.
1251 fbg::ValueChangedParameters params_0;
1252 params_0.set_value(kBuffer);
1253 local_svc.NotifyValue(std::move(params_0));
1254 RunLoopUntilIdle();
1255 ASSERT_TRUE(local_svc.error());
1256 EXPECT_EQ(local_svc.error().value(), ZX_ERR_PEER_CLOSED);
1257 EXPECT_TRUE(fake_gatt()->local_services().empty());
1258 }
1259
TEST_F(Gatt2ServerServerTest,NotifyInvalidParametersMissingValueClosesService)1260 TEST_F(Gatt2ServerServerTest,
1261 NotifyInvalidParametersMissingValueClosesService) {
1262 const uint64_t chrc_handle = 2;
1263 fbg::ServiceInfo svc_info =
1264 BuildSimpleService(/*svc_handle=*/1, /*svc_type=*/{5}, chrc_handle);
1265
1266 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
1267 MockLocalService local_svc = local_service_handle.NewRequest();
1268
1269 int cb_count = 0;
1270 auto cb = [&](fbg::Server_PublishService_Result res) {
1271 EXPECT_TRUE(res.is_response());
1272 cb_count++;
1273 };
1274 server_ptr()->PublishService(
1275 std::move(svc_info), std::move(local_service_handle), std::move(cb));
1276 RunLoopUntilIdle();
1277 EXPECT_EQ(cb_count, 1);
1278 ASSERT_EQ(fake_gatt()->local_services().size(), 1u);
1279 ASSERT_FALSE(local_svc.error());
1280
1281 // Missing value.
1282 fbg::ValueChangedParameters params_1;
1283 params_1.set_handle(fbg::Handle{chrc_handle});
1284 local_svc.NotifyValue(std::move(params_1));
1285 RunLoopUntilIdle();
1286 ASSERT_TRUE(local_svc.error());
1287 EXPECT_EQ(local_svc.error().value(), ZX_ERR_PEER_CLOSED);
1288 EXPECT_TRUE(fake_gatt()->local_services().empty());
1289 }
1290
TEST_F(Gatt2ServerServerTest,ValueChangedFlowControl)1291 TEST_F(Gatt2ServerServerTest, ValueChangedFlowControl) {
1292 const uint64_t chrc_handle = 2;
1293 fbg::ServiceInfo svc_info =
1294 BuildSimpleService(/*svc_handle=*/1, /*svc_type=*/{5}, chrc_handle);
1295
1296 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
1297 MockLocalService local_svc = local_service_handle.NewRequest();
1298
1299 int cb_count = 0;
1300 auto cb = [&](fbg::Server_PublishService_Result res) {
1301 EXPECT_TRUE(res.is_response());
1302 cb_count++;
1303 };
1304 server_ptr()->PublishService(
1305 std::move(svc_info), std::move(local_service_handle), std::move(cb));
1306 RunLoopUntilIdle();
1307 EXPECT_EQ(cb_count, 1);
1308 ASSERT_EQ(fake_gatt()->local_services().size(), 1u);
1309 auto svc_iter = fake_gatt()->local_services().begin();
1310
1311 for (size_t i = 0; i < 3 * fbg::INITIAL_VALUE_CHANGED_CREDITS; i++) {
1312 fbg::ValueChangedParameters params;
1313 params.set_handle(fbg::Handle{chrc_handle});
1314 params.set_value(kBuffer);
1315 local_svc.NotifyValue(std::move(params));
1316 }
1317 RunLoopUntilIdle();
1318 ASSERT_EQ(svc_iter->second.updates.size(),
1319 3 * fbg::INITIAL_VALUE_CHANGED_CREDITS);
1320 EXPECT_GT(local_svc.credits(), 0);
1321 EXPECT_LE(local_svc.credits(),
1322 static_cast<int>(fbg::INITIAL_VALUE_CHANGED_CREDITS));
1323 EXPECT_GE(local_svc.credit_log().size(), 2u);
1324
1325 for (size_t i = 0; i < 3 * fbg::INITIAL_VALUE_CHANGED_CREDITS; i++) {
1326 fbg::ValueChangedParameters params;
1327 params.set_handle(fbg::Handle{chrc_handle});
1328 params.set_value(kBuffer);
1329 zx::eventpair confirm_ours;
1330 zx::eventpair confirm_theirs;
1331 zx::eventpair::create(/*options=*/0, &confirm_ours, &confirm_theirs);
1332 local_svc.IndicateValue(std::move(params), std::move(confirm_theirs));
1333 }
1334 RunLoopUntilIdle();
1335 ASSERT_EQ(svc_iter->second.updates.size(),
1336 6 * fbg::INITIAL_VALUE_CHANGED_CREDITS);
1337 EXPECT_GT(local_svc.credits(), 0);
1338 EXPECT_LE(local_svc.credits(),
1339 static_cast<int>(fbg::INITIAL_VALUE_CHANGED_CREDITS));
1340 EXPECT_GE(local_svc.credit_log().size(), 5u);
1341 }
1342
TEST_F(Gatt2ServerServerTest,PublishServiceWithInvalidCharacteristic)1343 TEST_F(Gatt2ServerServerTest, PublishServiceWithInvalidCharacteristic) {
1344 fbg::ServiceInfo svc_info;
1345 svc_info.set_handle(fbg::ServiceHandle{1});
1346 bt::UInt128 svc_type = {5};
1347 svc_info.set_type(fbt::Uuid{svc_type});
1348
1349 fbg::Characteristic chrc_0;
1350 fbg::Handle chrc_handle_0{2};
1351 chrc_0.set_handle(chrc_handle_0);
1352
1353 std::vector<fbg::Characteristic> characteristics;
1354 characteristics.push_back(std::move(chrc_0));
1355 svc_info.set_characteristics(std::move(characteristics));
1356
1357 fidl::InterfaceHandle<fbg::LocalService> local_service_handle_0;
1358 fidl::InterfaceRequest<fbg::LocalService> request =
1359 local_service_handle_0.NewRequest();
1360
1361 int cb_count = 0;
1362 auto cb = [&](fbg::Server_PublishService_Result res) {
1363 cb_count++;
1364 ASSERT_TRUE(res.is_err());
1365 EXPECT_EQ(res.err(), fbg::PublishServiceError::INVALID_CHARACTERISTICS);
1366 };
1367 server_ptr()->PublishService(
1368 std::move(svc_info), std::move(local_service_handle_0), std::move(cb));
1369 RunLoopUntilIdle();
1370 EXPECT_EQ(cb_count, 1);
1371 ASSERT_EQ(fake_gatt()->local_services().size(), 0u);
1372 }
1373
TEST_F(Gatt2ServerServerTest,PublishServiceReturnsInvalidId)1374 TEST_F(Gatt2ServerServerTest, PublishServiceReturnsInvalidId) {
1375 bt::UInt128 svc_type = {5};
1376 fbg::ServiceInfo svc_info = BuildSimpleService(/*svc_handle=*/1, svc_type);
1377
1378 fidl::InterfaceHandle<fbg::LocalService> local_service_handle;
1379 fidl::InterfaceRequest<fbg::LocalService> request =
1380 local_service_handle.NewRequest();
1381
1382 int cb_count = 0;
1383 auto cb = [&](fbg::Server_PublishService_Result res) {
1384 cb_count++;
1385 ASSERT_TRUE(res.is_err());
1386 EXPECT_EQ(res.err(), fbg::PublishServiceError::UNLIKELY_ERROR);
1387 };
1388
1389 fake_gatt()->set_register_service_fails(true);
1390 server_ptr()->PublishService(
1391 std::move(svc_info), std::move(local_service_handle), std::move(cb));
1392 RunLoopUntilIdle();
1393 EXPECT_EQ(cb_count, 1);
1394 ASSERT_EQ(fake_gatt()->local_services().size(), 0u);
1395 }
1396
1397 } // namespace
1398 } // namespace bthost
1399