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_remote_service_server.h"
16
17 #include <fuchsia/bluetooth/gatt2/cpp/fidl_test_base.h>
18 #include <pw_assert/check.h>
19
20 #include <algorithm>
21 #include <optional>
22
23 #include "fuchsia/bluetooth/gatt2/cpp/fidl.h"
24 #include "gtest/gtest.h"
25 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/fake_gatt_fixture.h"
26 #include "pw_bluetooth_sapphire/internal/host/gatt/remote_service.h"
27 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
28
29 namespace bthost {
30 namespace {
31
32 namespace fbg = fuchsia::bluetooth::gatt2;
33
34 constexpr bt::PeerId kPeerId(1);
35
36 constexpr bt::att::Handle kServiceStartHandle = 0x0001;
37 constexpr bt::att::Handle kServiceEndHandle = 0xFFFE;
38 const bt::UUID kServiceUuid(uint16_t{0x180D});
39 const bt::UUID kCharacteristicUuid(uint16_t{0x180E});
40 const bt::UUID kDescriptorUuid(uint16_t{0x180F});
41
42 class Gatt2RemoteServiceServerTest : public bt::fidl::testing::FakeGattFixture {
43 public:
44 Gatt2RemoteServiceServerTest() = default;
45 ~Gatt2RemoteServiceServerTest() override = default;
46
SetUp()47 void SetUp() override {
48 {
49 auto [svc, client] = fake_gatt()->AddPeerService(
50 kPeerId,
51 bt::gatt::ServiceData(bt::gatt::ServiceKind::PRIMARY,
52 kServiceStartHandle,
53 kServiceEndHandle,
54 kServiceUuid));
55 service_ = std::move(svc);
56 fake_client_ = std::move(client);
57 }
58
59 fidl::InterfaceHandle<fbg::RemoteService> handle;
60 server_ = std::make_unique<Gatt2RemoteServiceServer>(
61 service_, gatt()->GetWeakPtr(), kPeerId, handle.NewRequest());
62 proxy_.Bind(std::move(handle));
63 }
64
TearDown()65 void TearDown() override {
66 // Clear any previous expectations that are based on the ATT Write Request,
67 // so that write requests sent during RemoteService::ShutDown() are ignored.
68 fake_client()->set_write_request_callback({});
69
70 bt::fidl::testing::FakeGattFixture::TearDown();
71 }
72
heap_dispatcher()73 pw::async::HeapDispatcher& heap_dispatcher() { return heap_dispatcher_; }
74
75 protected:
fake_client() const76 const bt::gatt::testing::FakeClient::WeakPtr& fake_client() const {
77 PW_CHECK(fake_client_.is_alive());
78 return fake_client_;
79 }
80
service_proxy()81 fbg::RemoteServicePtr& service_proxy() { return proxy_; }
service()82 bt::gatt::RemoteService::WeakPtr service() { return service_; }
83
DestroyServer()84 void DestroyServer() { server_.reset(); }
85
86 private:
87 std::unique_ptr<Gatt2RemoteServiceServer> server_;
88
89 fbg::RemoteServicePtr proxy_;
90 bt::gatt::RemoteService::WeakPtr service_;
91 bt::gatt::testing::FakeClient::WeakPtr fake_client_;
92 pw::async_fuchsia::FuchsiaDispatcher pw_dispatcher_{dispatcher()};
93 pw::async::HeapDispatcher heap_dispatcher_{pw_dispatcher_};
94
95 BT_DISALLOW_COPY_ASSIGN_AND_MOVE(Gatt2RemoteServiceServerTest);
96 };
97
TEST_F(Gatt2RemoteServiceServerTest,DiscoverCharacteristics)98 TEST_F(Gatt2RemoteServiceServerTest, DiscoverCharacteristics) {
99 bt::gatt::Properties properties =
100 static_cast<bt::gatt::Properties>(
101 bt::gatt::Property::kAuthenticatedSignedWrites) |
102 static_cast<bt::gatt::Properties>(
103 bt::gatt::Property::kExtendedProperties);
104 bt::gatt::ExtendedProperties ext_properties =
105 static_cast<bt::gatt::ExtendedProperties>(
106 bt::gatt::ExtendedProperty::kReliableWrite) |
107 static_cast<bt::gatt::ExtendedProperties>(
108 bt::gatt::ExtendedProperty::kWritableAuxiliaries);
109 constexpr bt::att::Handle kCharacteristicHandle(kServiceStartHandle + 1);
110 constexpr bt::att::Handle kCharacteristicValueHandle(kCharacteristicHandle +
111 1);
112 const bt::UUID kCharacteristicUuid(uint16_t{0x0000});
113 bt::gatt::CharacteristicData characteristic(properties,
114 ext_properties,
115 kCharacteristicHandle,
116 kCharacteristicValueHandle,
117 kCharacteristicUuid);
118 fake_client()->set_characteristics({characteristic});
119
120 constexpr bt::att::Handle kDescriptorHandle(kCharacteristicValueHandle + 1);
121 const bt::UUID kDescriptorUuid(uint16_t{0x0001});
122 bt::gatt::DescriptorData descriptor(kDescriptorHandle, kDescriptorUuid);
123 fake_client()->set_descriptors({descriptor});
124
125 std::optional<std::vector<fbg::Characteristic>> fidl_characteristics;
126 service_proxy()->DiscoverCharacteristics(
127 [&](std::vector<fbg::Characteristic> chars) {
128 fidl_characteristics = std::move(chars);
129 });
130 RunLoopUntilIdle();
131 ASSERT_TRUE(fidl_characteristics.has_value());
132 ASSERT_EQ(fidl_characteristics->size(), 1u);
133 const fbg::Characteristic& fidl_characteristic =
134 fidl_characteristics->front();
135
136 ASSERT_TRUE(fidl_characteristic.has_handle());
137 EXPECT_EQ(fidl_characteristic.handle().value,
138 static_cast<uint64_t>(kCharacteristicValueHandle));
139
140 ASSERT_TRUE(fidl_characteristic.has_type());
141 EXPECT_EQ(fidl_characteristic.type().value, kCharacteristicUuid.value());
142
143 ASSERT_TRUE(fidl_characteristic.has_properties());
144 EXPECT_EQ(fidl_characteristic.properties(),
145 fbg::CharacteristicPropertyBits::AUTHENTICATED_SIGNED_WRITES |
146 fbg::CharacteristicPropertyBits::RELIABLE_WRITE |
147 fbg::CharacteristicPropertyBits::WRITABLE_AUXILIARIES);
148
149 EXPECT_FALSE(fidl_characteristic.has_permissions());
150
151 ASSERT_TRUE(fidl_characteristic.has_descriptors());
152 ASSERT_EQ(fidl_characteristic.descriptors().size(), 1u);
153 const fbg::Descriptor& fidl_descriptor =
154 fidl_characteristic.descriptors().front();
155
156 ASSERT_TRUE(fidl_descriptor.has_handle());
157 EXPECT_EQ(fidl_descriptor.handle().value,
158 static_cast<uint64_t>(kDescriptorHandle));
159
160 ASSERT_TRUE(fidl_descriptor.has_type());
161 EXPECT_EQ(fidl_descriptor.type().value, kDescriptorUuid.value());
162
163 EXPECT_FALSE(fidl_descriptor.has_permissions());
164 }
165
TEST_F(Gatt2RemoteServiceServerTest,DiscoverCharacteristicsWithNoDescriptors)166 TEST_F(Gatt2RemoteServiceServerTest, DiscoverCharacteristicsWithNoDescriptors) {
167 bt::gatt::Properties properties = 0;
168 bt::gatt::ExtendedProperties ext_properties = 0;
169 constexpr bt::att::Handle kCharacteristicHandle(kServiceStartHandle + 1);
170 constexpr bt::att::Handle kCharacteristicValueHandle(kCharacteristicHandle +
171 1);
172 const bt::UUID kCharacteristicUuid(uint16_t{0x0000});
173 bt::gatt::CharacteristicData characteristic(properties,
174 ext_properties,
175 kCharacteristicHandle,
176 kCharacteristicValueHandle,
177 kCharacteristicUuid);
178 fake_client()->set_characteristics({characteristic});
179
180 std::optional<std::vector<fbg::Characteristic>> fidl_characteristics;
181 service_proxy()->DiscoverCharacteristics(
182 [&](std::vector<fbg::Characteristic> chars) {
183 fidl_characteristics = std::move(chars);
184 });
185 RunLoopUntilIdle();
186 ASSERT_TRUE(fidl_characteristics.has_value());
187 ASSERT_EQ(fidl_characteristics->size(), 1u);
188 const fbg::Characteristic& fidl_characteristic =
189 fidl_characteristics->front();
190 EXPECT_FALSE(fidl_characteristic.has_descriptors());
191 }
192
TEST_F(Gatt2RemoteServiceServerTest,ReadByTypeSuccess)193 TEST_F(Gatt2RemoteServiceServerTest, ReadByTypeSuccess) {
194 constexpr bt::UUID kCharUuid(uint16_t{0xfefe});
195
196 constexpr bt::att::Handle kHandle = kServiceStartHandle;
197 const auto kValue = bt::StaticByteBuffer(0x00, 0x01, 0x02);
198 const std::vector<bt::gatt::Client::ReadByTypeValue> kValues = {
199 {kHandle, kValue.view(), /*maybe_truncated=*/false}};
200
201 size_t read_count = 0;
202 fake_client()->set_read_by_type_request_callback([&](const bt::UUID& type,
203 bt::att::Handle start,
204 bt::att::Handle end,
205 auto callback) {
206 switch (read_count++) {
207 case 0:
208 callback(fit::ok(kValues));
209 break;
210 case 1:
211 callback(fit::error(bt::gatt::Client::ReadByTypeError{
212 bt::att::Error(bt::att::ErrorCode::kAttributeNotFound), start}));
213 break;
214 default:
215 FAIL();
216 }
217 });
218
219 std::optional<fbg::RemoteService_ReadByType_Result> fidl_result;
220 service_proxy()->ReadByType(
221 fuchsia::bluetooth::Uuid{kCharUuid.value()},
222 [&](auto cb_result) { fidl_result = std::move(cb_result); });
223
224 RunLoopUntilIdle();
225 ASSERT_TRUE(fidl_result.has_value());
226 ASSERT_TRUE(fidl_result->is_response());
227 const auto& response = fidl_result->response();
228 ASSERT_EQ(1u, response.results.size());
229 const fbg::ReadByTypeResult& result0 = response.results[0];
230 ASSERT_TRUE(result0.has_handle());
231 EXPECT_EQ(result0.handle().value, static_cast<uint64_t>(kHandle));
232
233 EXPECT_FALSE(result0.has_error());
234
235 ASSERT_TRUE(result0.has_value());
236 const fbg::ReadValue& read_value = result0.value();
237 ASSERT_TRUE(read_value.has_handle());
238 EXPECT_EQ(read_value.handle().value, static_cast<uint64_t>(kHandle));
239 ASSERT_TRUE(read_value.has_maybe_truncated());
240 EXPECT_FALSE(read_value.maybe_truncated());
241
242 ASSERT_TRUE(read_value.has_value());
243 const std::vector<uint8_t>& value = read_value.value();
244 EXPECT_TRUE(
245 ContainersEqual(bt::BufferView(value.data(), value.size()), kValue));
246 }
247
TEST_F(Gatt2RemoteServiceServerTest,ReadByTypeResultPermissionError)248 TEST_F(Gatt2RemoteServiceServerTest, ReadByTypeResultPermissionError) {
249 constexpr bt::UUID kCharUuid(uint16_t{0xfefe});
250
251 size_t read_count = 0;
252 fake_client()->set_read_by_type_request_callback([&](const bt::UUID& type,
253 bt::att::Handle start,
254 bt::att::Handle end,
255 auto callback) {
256 ASSERT_EQ(0u, read_count++);
257 callback(fit::error(bt::gatt::Client::ReadByTypeError{
258 bt::att::Error(bt::att::ErrorCode::kInsufficientAuthorization),
259 kServiceEndHandle}));
260 });
261
262 std::optional<fbg::RemoteService_ReadByType_Result> fidl_result;
263 service_proxy()->ReadByType(
264 fuchsia::bluetooth::Uuid{kCharUuid.value()},
265 [&](auto cb_result) { fidl_result = std::move(cb_result); });
266
267 RunLoopUntilIdle();
268 ASSERT_TRUE(fidl_result.has_value());
269 ASSERT_TRUE(fidl_result->is_response());
270 const auto& response = fidl_result->response();
271 ASSERT_EQ(1u, response.results.size());
272 const fbg::ReadByTypeResult& result0 = response.results[0];
273 ASSERT_TRUE(result0.has_handle());
274 EXPECT_EQ(result0.handle().value, static_cast<uint64_t>(kServiceEndHandle));
275 EXPECT_FALSE(result0.has_value());
276 ASSERT_TRUE(result0.has_error());
277 EXPECT_EQ(fbg::Error::INSUFFICIENT_AUTHORIZATION, result0.error());
278 }
279
TEST_F(Gatt2RemoteServiceServerTest,ReadByTypeReturnsError)280 TEST_F(Gatt2RemoteServiceServerTest, ReadByTypeReturnsError) {
281 constexpr bt::UUID kCharUuid(uint16_t{0xfefe});
282
283 size_t read_count = 0;
284 fake_client()->set_read_by_type_request_callback([&](const bt::UUID& type,
285 bt::att::Handle start,
286 bt::att::Handle end,
287 auto callback) {
288 switch (read_count++) {
289 case 0:
290 callback(fit::error(bt::gatt::Client::ReadByTypeError{
291 bt::Error(bt::HostError::kPacketMalformed), std::nullopt}));
292 break;
293 default:
294 FAIL();
295 }
296 });
297
298 std::optional<fbg::RemoteService_ReadByType_Result> fidl_result;
299 service_proxy()->ReadByType(
300 fuchsia::bluetooth::Uuid{kCharUuid.value()},
301 [&](auto cb_result) { fidl_result = std::move(cb_result); });
302
303 RunLoopUntilIdle();
304 ASSERT_TRUE(fidl_result.has_value());
305 ASSERT_TRUE(fidl_result->is_err());
306 const auto& err = fidl_result->err();
307 EXPECT_EQ(fbg::Error::UNLIKELY_ERROR, err);
308 }
309
TEST_F(Gatt2RemoteServiceServerTest,ReadByTypeInvalidUuid)310 TEST_F(Gatt2RemoteServiceServerTest, ReadByTypeInvalidUuid) {
311 constexpr bt::UUID kCharUuid = bt::gatt::types::kCharacteristicDeclaration;
312
313 fake_client()->set_read_by_type_request_callback(
314 [&](const bt::UUID& type,
315 bt::att::Handle start,
316 bt::att::Handle end,
317 auto callback) { FAIL(); });
318
319 std::optional<fbg::RemoteService_ReadByType_Result> fidl_result;
320 service_proxy()->ReadByType(
321 fuchsia::bluetooth::Uuid{kCharUuid.value()},
322 [&](auto cb_result) { fidl_result = std::move(cb_result); });
323
324 RunLoopUntilIdle();
325 ASSERT_TRUE(fidl_result.has_value());
326 ASSERT_TRUE(fidl_result->is_err());
327 const auto& err = fidl_result->err();
328 EXPECT_EQ(fbg::Error::INVALID_PARAMETERS, err);
329 }
330
TEST_F(Gatt2RemoteServiceServerTest,ReadByTypeTooManyResults)331 TEST_F(Gatt2RemoteServiceServerTest, ReadByTypeTooManyResults) {
332 constexpr bt::UUID kCharUuid(uint16_t{0xfefe});
333 const auto value =
334 bt::StaticByteBuffer(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06);
335
336 size_t read_count = 0;
337 fake_client()->set_read_by_type_request_callback([&](const bt::UUID& type,
338 bt::att::Handle start,
339 bt::att::Handle end,
340 auto callback) {
341 read_count++;
342
343 // Ensure that more results are received than can fit in a channel. Each
344 // result is larger than the value payload, so receiving as many values as
345 // will fit in a channel is guaranteed to fill the channel and then some.
346 const size_t max_value_count =
347 static_cast<size_t>(ZX_CHANNEL_MAX_MSG_BYTES) / value.size();
348 if (read_count == max_value_count) {
349 callback(fit::error(bt::gatt::Client::ReadByTypeError{
350 bt::att::Error(bt::att::ErrorCode::kAttributeNotFound), start}));
351 return;
352 }
353
354 // Dispatch callback to prevent recursing too deep and breaking the stack.
355 (void)heap_dispatcher().Post(
356 [start, cb = std::move(callback), &value = value](
357 pw::async::Context /*ctx*/, pw::Status status) {
358 if (status.ok()) {
359 std::vector<bt::gatt::Client::ReadByTypeValue> values = {
360 {start, value.view(), /*maybe_truncated=*/false}};
361 cb(fit::ok(values));
362 }
363 });
364 });
365
366 std::optional<fbg::RemoteService_ReadByType_Result> fidl_result;
367 service_proxy()->ReadByType(
368 fuchsia::bluetooth::Uuid{kCharUuid.value()},
369 [&](auto cb_result) { fidl_result = std::move(cb_result); });
370 RunLoopUntilIdle();
371 ASSERT_TRUE(fidl_result.has_value());
372 ASSERT_TRUE(fidl_result->is_err());
373 const auto& err = fidl_result->err();
374 EXPECT_EQ(fbg::Error::TOO_MANY_RESULTS, err);
375 }
376
TEST_F(Gatt2RemoteServiceServerTest,DiscoverAndReadShortCharacteristic)377 TEST_F(Gatt2RemoteServiceServerTest, DiscoverAndReadShortCharacteristic) {
378 constexpr bt::att::Handle kHandle = 3;
379 constexpr bt::att::Handle kValueHandle = kHandle + 1;
380 const auto kValue = bt::StaticByteBuffer(0x00, 0x01, 0x02, 0x03, 0x04);
381
382 bt::gatt::CharacteristicData char_data(bt::gatt::Property::kRead,
383 std::nullopt,
384 kHandle,
385 kValueHandle,
386 kServiceUuid);
387 fake_client()->set_characteristics({char_data});
388
389 std::optional<std::vector<fbg::Characteristic>> fidl_characteristics;
390 service_proxy()->DiscoverCharacteristics(
391 [&](std::vector<fbg::Characteristic> chars) {
392 fidl_characteristics = std::move(chars);
393 });
394 RunLoopUntilIdle();
395 ASSERT_TRUE(fidl_characteristics.has_value());
396 ASSERT_EQ(fidl_characteristics->size(), 1u);
397 const fbg::Characteristic& fidl_char = fidl_characteristics->front();
398 ASSERT_TRUE(fidl_char.has_handle());
399
400 size_t read_count = 0;
401 fake_client()->set_read_request_callback(
402 [&](bt::att::Handle handle, bt::gatt::Client::ReadCallback callback) {
403 read_count++;
404 EXPECT_EQ(handle, kValueHandle);
405 callback(fit::ok(), kValue, /*maybe_truncated=*/false);
406 });
407 fake_client()->set_read_blob_request_callback(
408 [](auto, auto, auto) { FAIL(); });
409
410 fbg::ReadOptions options =
411 fbg::ReadOptions::WithShortRead(fbg::ShortReadOptions());
412 std::optional<fpromise::result<fbg::ReadValue, fbg::Error>> fidl_result;
413 service_proxy()->ReadCharacteristic(
414 fidl_char.handle(), std::move(options), [&](auto result) {
415 fidl_result = std::move(result);
416 });
417 RunLoopUntilIdle();
418 EXPECT_EQ(read_count, 1u);
419 ASSERT_TRUE(fidl_result.has_value());
420 ASSERT_TRUE(fidl_result->is_ok())
421 << static_cast<uint32_t>(fidl_result->error());
422 const fbg::ReadValue& read_value = fidl_result->value();
423 EXPECT_TRUE(ContainersEqual(kValue, read_value.value()));
424 EXPECT_FALSE(read_value.maybe_truncated());
425 }
426
TEST_F(Gatt2RemoteServiceServerTest,DiscoverAndReadLongCharacteristicWithOffsetAndMaxBytes)427 TEST_F(Gatt2RemoteServiceServerTest,
428 DiscoverAndReadLongCharacteristicWithOffsetAndMaxBytes) {
429 constexpr bt::att::Handle kHandle = 3;
430 constexpr bt::att::Handle kValueHandle = kHandle + 1;
431 const auto kValue = bt::StaticByteBuffer(0x00, 0x01, 0x02, 0x03, 0x04, 0x05);
432 constexpr uint16_t kOffset = 1;
433 constexpr uint16_t kMaxBytes = 3;
434
435 bt::gatt::CharacteristicData char_data(bt::gatt::Property::kRead,
436 std::nullopt,
437 kHandle,
438 kValueHandle,
439 kServiceUuid);
440 fake_client()->set_characteristics({char_data});
441
442 std::optional<std::vector<fbg::Characteristic>> fidl_characteristics;
443 service_proxy()->DiscoverCharacteristics(
444 [&](std::vector<fbg::Characteristic> chars) {
445 fidl_characteristics = std::move(chars);
446 });
447 RunLoopUntilIdle();
448 ASSERT_TRUE(fidl_characteristics.has_value());
449 ASSERT_EQ(fidl_characteristics->size(), 1u);
450 const fbg::Characteristic& fidl_char = fidl_characteristics->front();
451 ASSERT_TRUE(fidl_char.has_handle());
452
453 fbg::LongReadOptions long_options;
454 long_options.set_offset(kOffset);
455 long_options.set_max_bytes(kMaxBytes);
456 fbg::ReadOptions read_options;
457 read_options.set_long_read(std::move(long_options));
458
459 size_t read_count = 0;
460 fake_client()->set_read_request_callback([](auto, auto) { FAIL(); });
461 fake_client()->set_read_blob_request_callback(
462 [&](bt::att::Handle handle,
463 uint16_t offset,
464 bt::gatt::Client::ReadCallback cb) {
465 read_count++;
466 EXPECT_EQ(handle, kValueHandle);
467 EXPECT_EQ(offset, kOffset);
468 cb(fit::ok(), kValue.view(offset), /*maybe_truncated=*/false);
469 });
470
471 std::optional<fpromise::result<fbg::ReadValue, fbg::Error>> fidl_result;
472 service_proxy()->ReadCharacteristic(
473 fidl_char.handle(), std::move(read_options), [&](auto result) {
474 fidl_result = std::move(result);
475 });
476 RunLoopUntilIdle();
477 EXPECT_EQ(read_count, 1u);
478 ASSERT_TRUE(fidl_result.has_value());
479 ASSERT_TRUE(fidl_result->is_ok())
480 << static_cast<uint32_t>(fidl_result->error());
481 const fbg::ReadValue& read_value = fidl_result->value();
482 EXPECT_TRUE(
483 ContainersEqual(kValue.view(kOffset, kMaxBytes), read_value.value()));
484 EXPECT_TRUE(read_value.maybe_truncated());
485 }
486
TEST_F(Gatt2RemoteServiceServerTest,ReadCharacteristicHandleTooLarge)487 TEST_F(Gatt2RemoteServiceServerTest, ReadCharacteristicHandleTooLarge) {
488 fbg::Handle handle;
489 handle.value = std::numeric_limits<bt::att::Handle>::max() + 1ULL;
490
491 fbg::ReadOptions options =
492 fbg::ReadOptions::WithShortRead(fbg::ShortReadOptions());
493 std::optional<fpromise::result<fbg::ReadValue, fbg::Error>> fidl_result;
494 service_proxy()->ReadCharacteristic(
495 handle, std::move(options), [&](auto result) {
496 fidl_result = std::move(result);
497 });
498 RunLoopUntilIdle();
499 ASSERT_TRUE(fidl_result.has_value());
500 ASSERT_TRUE(fidl_result->is_error());
501 EXPECT_EQ(fidl_result->error(), fbg::Error::INVALID_HANDLE);
502 }
503
504 // Trying to read a characteristic that doesn't exist should return a FAILURE
505 // error.
TEST_F(Gatt2RemoteServiceServerTest,ReadCharacteristicFailure)506 TEST_F(Gatt2RemoteServiceServerTest, ReadCharacteristicFailure) {
507 constexpr bt::att::Handle kHandle = 3;
508 fbg::ReadOptions options =
509 fbg::ReadOptions::WithShortRead(fbg::ShortReadOptions());
510 std::optional<fpromise::result<fbg::ReadValue, fbg::Error>> fidl_result;
511 service_proxy()->ReadCharacteristic(
512 fbg::Handle{kHandle}, std::move(options), [&](auto result) {
513 fidl_result = std::move(result);
514 });
515 RunLoopUntilIdle();
516 ASSERT_TRUE(fidl_result.has_value());
517 ASSERT_TRUE(fidl_result->is_error());
518 EXPECT_EQ(fidl_result->error(), fbg::Error::UNLIKELY_ERROR);
519 }
520
TEST_F(Gatt2RemoteServiceServerTest,DiscoverAndReadShortDescriptor)521 TEST_F(Gatt2RemoteServiceServerTest, DiscoverAndReadShortDescriptor) {
522 constexpr bt::att::Handle kCharacteristicHandle = 2;
523 constexpr bt::att::Handle kCharacteristicValueHandle = 3;
524 constexpr bt::att::Handle kDescriptorHandle = 4;
525 const auto kDescriptorValue =
526 bt::StaticByteBuffer(0x00, 0x01, 0x02, 0x03, 0x04);
527
528 bt::gatt::CharacteristicData char_data(bt::gatt::Property::kRead,
529 std::nullopt,
530 kCharacteristicHandle,
531 kCharacteristicValueHandle,
532 kServiceUuid);
533 fake_client()->set_characteristics({char_data});
534 bt::gatt::DescriptorData desc_data(kDescriptorHandle, kDescriptorUuid);
535 fake_client()->set_descriptors({desc_data});
536
537 std::optional<std::vector<fbg::Characteristic>> fidl_characteristics;
538 service_proxy()->DiscoverCharacteristics(
539 [&](std::vector<fbg::Characteristic> chars) {
540 fidl_characteristics = std::move(chars);
541 });
542 RunLoopUntilIdle();
543 ASSERT_TRUE(fidl_characteristics.has_value());
544 ASSERT_EQ(fidl_characteristics->size(), 1u);
545 const fbg::Characteristic& fidl_char = fidl_characteristics->front();
546 ASSERT_TRUE(fidl_char.has_descriptors());
547 ASSERT_EQ(fidl_char.descriptors().size(), 1u);
548 const fbg::Descriptor& fidl_desc = fidl_char.descriptors().front();
549 ASSERT_TRUE(fidl_desc.has_handle());
550
551 size_t read_count = 0;
552 fake_client()->set_read_request_callback(
553 [&](bt::att::Handle handle, bt::gatt::Client::ReadCallback callback) {
554 read_count++;
555 EXPECT_EQ(handle, kDescriptorHandle);
556 callback(fit::ok(), kDescriptorValue, /*maybe_truncated=*/false);
557 });
558 fake_client()->set_read_blob_request_callback(
559 [](auto, auto, auto) { FAIL(); });
560
561 fbg::ReadOptions options =
562 fbg::ReadOptions::WithShortRead(fbg::ShortReadOptions());
563 std::optional<fpromise::result<fbg::ReadValue, fbg::Error>> fidl_result;
564 service_proxy()->ReadDescriptor(
565 fidl_desc.handle(), std::move(options), [&](auto result) {
566 fidl_result = std::move(result);
567 });
568 RunLoopUntilIdle();
569 EXPECT_EQ(read_count, 1u);
570 ASSERT_TRUE(fidl_result.has_value());
571 ASSERT_TRUE(fidl_result->is_ok())
572 << static_cast<uint32_t>(fidl_result->error());
573 const fbg::ReadValue& read_value = fidl_result->value();
574 EXPECT_TRUE(ContainersEqual(kDescriptorValue, read_value.value()));
575 EXPECT_FALSE(read_value.maybe_truncated());
576 }
577
TEST_F(Gatt2RemoteServiceServerTest,DiscoverAndReadLongDescriptorWithOffsetAndMaxBytes)578 TEST_F(Gatt2RemoteServiceServerTest,
579 DiscoverAndReadLongDescriptorWithOffsetAndMaxBytes) {
580 constexpr bt::att::Handle kCharacteristicHandle = 2;
581 constexpr bt::att::Handle kCharacteristicValueHandle = 3;
582 constexpr bt::att::Handle kDescriptorHandle = 4;
583 constexpr uint16_t kOffset = 1;
584 constexpr uint16_t kMaxBytes = 3;
585 const auto kDescriptorValue =
586 bt::StaticByteBuffer(0x00, 0x01, 0x02, 0x03, 0x04);
587
588 bt::gatt::CharacteristicData char_data(bt::gatt::Property::kRead,
589 std::nullopt,
590 kCharacteristicHandle,
591 kCharacteristicValueHandle,
592 kServiceUuid);
593 fake_client()->set_characteristics({char_data});
594 bt::gatt::DescriptorData desc_data(kDescriptorHandle, kDescriptorUuid);
595 fake_client()->set_descriptors({desc_data});
596
597 std::optional<std::vector<fbg::Characteristic>> fidl_characteristics;
598 service_proxy()->DiscoverCharacteristics(
599 [&](std::vector<fbg::Characteristic> chars) {
600 fidl_characteristics = std::move(chars);
601 });
602 RunLoopUntilIdle();
603 ASSERT_TRUE(fidl_characteristics.has_value());
604 ASSERT_EQ(fidl_characteristics->size(), 1u);
605 const fbg::Characteristic& fidl_char = fidl_characteristics->front();
606 ASSERT_TRUE(fidl_char.has_descriptors());
607 ASSERT_EQ(fidl_char.descriptors().size(), 1u);
608 const fbg::Descriptor& fidl_desc = fidl_char.descriptors().front();
609 ASSERT_TRUE(fidl_desc.has_handle());
610
611 fbg::LongReadOptions long_options;
612 long_options.set_offset(kOffset);
613 long_options.set_max_bytes(kMaxBytes);
614 fbg::ReadOptions read_options;
615 read_options.set_long_read(std::move(long_options));
616
617 size_t read_count = 0;
618 fake_client()->set_read_request_callback([](auto, auto) { FAIL(); });
619 fake_client()->set_read_blob_request_callback(
620 [&](bt::att::Handle handle,
621 uint16_t offset,
622 bt::gatt::Client::ReadCallback cb) {
623 read_count++;
624 EXPECT_EQ(handle, kDescriptorHandle);
625 EXPECT_EQ(offset, kOffset);
626 cb(fit::ok(), kDescriptorValue.view(offset), /*maybe_truncated=*/false);
627 });
628
629 std::optional<fpromise::result<fbg::ReadValue, fbg::Error>> fidl_result;
630 service_proxy()->ReadDescriptor(
631 fidl_desc.handle(), std::move(read_options), [&](auto result) {
632 fidl_result = std::move(result);
633 });
634 RunLoopUntilIdle();
635 RunLoopUntilIdle();
636 EXPECT_EQ(read_count, 1u);
637 ASSERT_TRUE(fidl_result.has_value());
638 ASSERT_TRUE(fidl_result->is_ok())
639 << static_cast<uint32_t>(fidl_result->error());
640 const fbg::ReadValue& read_value = fidl_result->value();
641 EXPECT_TRUE(ContainersEqual(kDescriptorValue.view(kOffset, kMaxBytes),
642 read_value.value()));
643 EXPECT_TRUE(read_value.maybe_truncated());
644 }
645
TEST_F(Gatt2RemoteServiceServerTest,ReadDescriptorHandleTooLarge)646 TEST_F(Gatt2RemoteServiceServerTest, ReadDescriptorHandleTooLarge) {
647 fbg::Handle handle;
648 handle.value =
649 static_cast<uint64_t>(std::numeric_limits<bt::att::Handle>::max()) + 1;
650
651 fbg::ReadOptions options =
652 fbg::ReadOptions::WithShortRead(fbg::ShortReadOptions());
653 std::optional<fpromise::result<fbg::ReadValue, fbg::Error>> fidl_result;
654 service_proxy()->ReadDescriptor(handle, std::move(options), [&](auto result) {
655 fidl_result = std::move(result);
656 });
657 RunLoopUntilIdle();
658 ASSERT_TRUE(fidl_result.has_value());
659 ASSERT_TRUE(fidl_result->is_error());
660 EXPECT_EQ(fidl_result->error(), fbg::Error::INVALID_HANDLE);
661 }
662
663 // Trying to read a descriptor that doesn't exist should return a FAILURE error.
TEST_F(Gatt2RemoteServiceServerTest,ReadDescriptorFailure)664 TEST_F(Gatt2RemoteServiceServerTest, ReadDescriptorFailure) {
665 constexpr bt::att::Handle kHandle = 3;
666 fbg::ReadOptions options =
667 fbg::ReadOptions::WithShortRead(fbg::ShortReadOptions());
668 std::optional<fpromise::result<fbg::ReadValue, fbg::Error>> fidl_result;
669 service_proxy()->ReadDescriptor(
670 fbg::Handle{kHandle}, std::move(options), [&](auto result) {
671 fidl_result = std::move(result);
672 });
673 RunLoopUntilIdle();
674 ASSERT_TRUE(fidl_result.has_value());
675 ASSERT_TRUE(fidl_result->is_error());
676 EXPECT_EQ(fidl_result->error(), fbg::Error::UNLIKELY_ERROR);
677 }
678
TEST_F(Gatt2RemoteServiceServerTest,WriteCharacteristicHandleTooLarge)679 TEST_F(Gatt2RemoteServiceServerTest, WriteCharacteristicHandleTooLarge) {
680 fbg::Handle handle;
681 handle.value = std::numeric_limits<bt::att::Handle>::max() + 1ULL;
682
683 std::optional<fpromise::result<void, fbg::Error>> fidl_result;
684 service_proxy()->WriteCharacteristic(
685 handle, /*value=*/{}, fbg::WriteOptions(), [&](auto result) {
686 fidl_result = std::move(result);
687 });
688 RunLoopUntilIdle();
689 ASSERT_TRUE(fidl_result.has_value());
690 ASSERT_TRUE(fidl_result->is_error());
691 EXPECT_EQ(fidl_result->error(), fbg::Error::INVALID_HANDLE);
692 }
693
TEST_F(Gatt2RemoteServiceServerTest,WriteCharacteristicWithoutResponseAndNonZeroOffsetReturnsError)694 TEST_F(Gatt2RemoteServiceServerTest,
695 WriteCharacteristicWithoutResponseAndNonZeroOffsetReturnsError) {
696 fbg::Handle handle;
697 handle.value = 3;
698 fbg::WriteOptions options;
699 options.set_write_mode(fbg::WriteMode::WITHOUT_RESPONSE);
700 options.set_offset(1);
701 std::optional<fpromise::result<void, fbg::Error>> fidl_result;
702 service_proxy()->WriteCharacteristic(
703 handle, /*value=*/{}, std::move(options), [&](auto result) {
704 fidl_result = std::move(result);
705 });
706 RunLoopUntilIdle();
707 ASSERT_TRUE(fidl_result.has_value());
708 ASSERT_TRUE(fidl_result->is_error());
709 EXPECT_EQ(fidl_result->error(), fbg::Error::INVALID_PARAMETERS);
710 }
711
TEST_F(Gatt2RemoteServiceServerTest,WriteCharacteristicWithoutResponse)712 TEST_F(Gatt2RemoteServiceServerTest, WriteCharacteristicWithoutResponse) {
713 constexpr bt::att::Handle kHandle = 3;
714 constexpr bt::att::Handle kValueHandle = kHandle + 1;
715 const auto kValue = bt::StaticByteBuffer(0x00, 0x01, 0x02, 0x03, 0x04);
716
717 bt::gatt::CharacteristicData char_data(
718 bt::gatt::Property::kWriteWithoutResponse,
719 std::nullopt,
720 kHandle,
721 kValueHandle,
722 kServiceUuid);
723 fake_client()->set_characteristics({char_data});
724
725 int write_count = 0;
726 fake_client()->set_write_without_rsp_callback(
727 [&](bt::att::Handle handle,
728 const bt::ByteBuffer& value,
729 bt::att::ResultFunction<> cb) {
730 write_count++;
731 EXPECT_EQ(handle, kValueHandle);
732 EXPECT_TRUE(ContainersEqual(value, kValue));
733 cb(fit::ok());
734 });
735
736 std::optional<std::vector<fbg::Characteristic>> fidl_characteristics;
737 service_proxy()->DiscoverCharacteristics(
738 [&](std::vector<fbg::Characteristic> chars) {
739 fidl_characteristics = std::move(chars);
740 });
741 RunLoopUntilIdle();
742 ASSERT_TRUE(fidl_characteristics.has_value());
743 ASSERT_EQ(fidl_characteristics->size(), 1u);
744 const fbg::Characteristic& fidl_char = fidl_characteristics->front();
745 ASSERT_TRUE(fidl_char.has_handle());
746
747 fbg::WriteOptions options;
748 options.set_write_mode(fbg::WriteMode::WITHOUT_RESPONSE);
749
750 std::optional<fpromise::result<void, fbg::Error>> fidl_result;
751 service_proxy()->WriteCharacteristic(
752 fidl_char.handle(),
753 kValue.ToVector(),
754 std::move(options),
755 [&](auto result) { fidl_result = std::move(result); });
756 RunLoopUntilIdle();
757 ASSERT_TRUE(fidl_result.has_value());
758 EXPECT_TRUE(fidl_result->is_ok());
759 EXPECT_EQ(write_count, 1);
760 }
761
TEST_F(Gatt2RemoteServiceServerTest,WriteCharacteristicWithoutResponseValueTooLong)762 TEST_F(Gatt2RemoteServiceServerTest,
763 WriteCharacteristicWithoutResponseValueTooLong) {
764 constexpr bt::att::Handle kHandle = 3;
765 constexpr bt::att::Handle kValueHandle = kHandle + 1;
766 ASSERT_EQ(fake_client()->mtu(), bt::att::kLEMinMTU);
767 bt::StaticByteBuffer<bt::att::kLEMinMTU> kValue;
768 kValue.Fill(0x03);
769
770 bt::gatt::CharacteristicData char_data(
771 bt::gatt::Property::kWriteWithoutResponse,
772 std::nullopt,
773 kHandle,
774 kValueHandle,
775 kServiceUuid);
776 fake_client()->set_characteristics({char_data});
777
778 int write_count = 0;
779 fake_client()->set_write_without_rsp_callback(
780 [&](bt::att::Handle handle,
781 const bt::ByteBuffer& value,
782 bt::att::ResultFunction<> callback) {
783 write_count++;
784 EXPECT_EQ(handle, kValueHandle);
785 EXPECT_TRUE(ContainersEqual(value, kValue));
786 callback(bt::ToResult(bt::HostError::kFailed));
787 });
788
789 std::optional<std::vector<fbg::Characteristic>> fidl_characteristics;
790 service_proxy()->DiscoverCharacteristics(
791 [&](std::vector<fbg::Characteristic> chars) {
792 fidl_characteristics = std::move(chars);
793 });
794 RunLoopUntilIdle();
795 ASSERT_TRUE(fidl_characteristics.has_value());
796 ASSERT_EQ(fidl_characteristics->size(), 1u);
797 const fbg::Characteristic& fidl_char = fidl_characteristics->front();
798 ASSERT_TRUE(fidl_char.has_handle());
799
800 fbg::WriteOptions options;
801 options.set_write_mode(fbg::WriteMode::WITHOUT_RESPONSE);
802
803 std::optional<fpromise::result<void, fbg::Error>> fidl_result;
804 service_proxy()->WriteCharacteristic(
805 fidl_char.handle(),
806 kValue.ToVector(),
807 std::move(options),
808 [&](auto result) { fidl_result = std::move(result); });
809 RunLoopUntilIdle();
810 EXPECT_EQ(write_count, 1);
811 ASSERT_TRUE(fidl_result.has_value());
812 ASSERT_TRUE(fidl_result->is_error());
813 EXPECT_EQ(fidl_result->error(), fbg::Error::UNLIKELY_ERROR);
814 }
815
TEST_F(Gatt2RemoteServiceServerTest,WriteShortCharacteristic)816 TEST_F(Gatt2RemoteServiceServerTest, WriteShortCharacteristic) {
817 constexpr bt::att::Handle kHandle = 3;
818 constexpr bt::att::Handle kValueHandle = kHandle + 1;
819 const auto kValue = bt::StaticByteBuffer(0x00, 0x01, 0x02, 0x03, 0x04);
820
821 bt::gatt::CharacteristicData char_data(bt::gatt::Property::kWrite,
822 std::nullopt,
823 kHandle,
824 kValueHandle,
825 kServiceUuid);
826 fake_client()->set_characteristics({char_data});
827
828 int write_count = 0;
829 fake_client()->set_write_request_callback(
830 [&](bt::att::Handle handle,
831 const bt::ByteBuffer& value,
832 bt::att::ResultFunction<> callback) {
833 write_count++;
834 EXPECT_EQ(handle, kValueHandle);
835 EXPECT_TRUE(ContainersEqual(value, kValue));
836 callback(fit::ok());
837 });
838
839 std::optional<std::vector<fbg::Characteristic>> fidl_characteristics;
840 service_proxy()->DiscoverCharacteristics(
841 [&](std::vector<fbg::Characteristic> chars) {
842 fidl_characteristics = std::move(chars);
843 });
844 RunLoopUntilIdle();
845 ASSERT_TRUE(fidl_characteristics.has_value());
846 ASSERT_EQ(fidl_characteristics->size(), 1u);
847 const fbg::Characteristic& fidl_char = fidl_characteristics->front();
848 ASSERT_TRUE(fidl_char.has_handle());
849
850 fbg::WriteOptions options;
851 std::optional<fpromise::result<void, fbg::Error>> fidl_result;
852 service_proxy()->WriteCharacteristic(
853 fidl_char.handle(),
854 kValue.ToVector(),
855 std::move(options),
856 [&](auto result) { fidl_result = std::move(result); });
857 RunLoopUntilIdle();
858 ASSERT_TRUE(fidl_result.has_value());
859 EXPECT_TRUE(fidl_result->is_ok());
860 EXPECT_EQ(write_count, 1);
861 }
862
TEST_F(Gatt2RemoteServiceServerTest,WriteShortCharacteristicWithNonZeroOffset)863 TEST_F(Gatt2RemoteServiceServerTest,
864 WriteShortCharacteristicWithNonZeroOffset) {
865 constexpr bt::att::Handle kHandle = 3;
866 constexpr bt::att::Handle kValueHandle = kHandle + 1;
867 const auto kValue = bt::StaticByteBuffer(0x00, 0x01, 0x02, 0x03, 0x04);
868 const uint16_t kOffset = 1;
869
870 bt::gatt::CharacteristicData char_data(bt::gatt::Property::kWrite,
871 std::nullopt,
872 kHandle,
873 kValueHandle,
874 kServiceUuid);
875 fake_client()->set_characteristics({char_data});
876
877 int write_count = 0;
878 fake_client()->set_execute_prepare_writes_callback(
879 [&](bt::att::PrepareWriteQueue prep_write_queue,
880 bt::gatt::ReliableMode reliable,
881 bt::att::ResultFunction<> callback) {
882 write_count++;
883 ASSERT_EQ(prep_write_queue.size(), 1u);
884 EXPECT_EQ(prep_write_queue.front().handle(), kValueHandle);
885 EXPECT_EQ(prep_write_queue.front().offset(), kOffset);
886 EXPECT_EQ(reliable, bt::gatt::ReliableMode::kDisabled);
887 EXPECT_TRUE(ContainersEqual(prep_write_queue.front().value(), kValue));
888 callback(fit::ok());
889 });
890
891 std::optional<std::vector<fbg::Characteristic>> fidl_characteristics;
892 service_proxy()->DiscoverCharacteristics(
893 [&](std::vector<fbg::Characteristic> chars) {
894 fidl_characteristics = std::move(chars);
895 });
896 RunLoopUntilIdle();
897 ASSERT_TRUE(fidl_characteristics.has_value());
898 ASSERT_EQ(fidl_characteristics->size(), 1u);
899 const fbg::Characteristic& fidl_char = fidl_characteristics->front();
900 ASSERT_TRUE(fidl_char.has_handle());
901
902 fbg::WriteOptions options;
903 options.set_offset(kOffset);
904 std::optional<fpromise::result<void, fbg::Error>> fidl_result;
905 service_proxy()->WriteCharacteristic(
906 fidl_char.handle(),
907 kValue.ToVector(),
908 std::move(options),
909 [&](auto result) { fidl_result = std::move(result); });
910 RunLoopUntilIdle();
911 ASSERT_TRUE(fidl_result.has_value());
912 EXPECT_TRUE(fidl_result->is_ok());
913 EXPECT_EQ(write_count, 1);
914 }
915
TEST_F(Gatt2RemoteServiceServerTest,WriteShortCharacteristicWithReliableMode)916 TEST_F(Gatt2RemoteServiceServerTest, WriteShortCharacteristicWithReliableMode) {
917 constexpr bt::att::Handle kHandle = 3;
918 constexpr bt::att::Handle kValueHandle = kHandle + 1;
919 const auto kValue = bt::StaticByteBuffer(0x00, 0x01, 0x02, 0x03, 0x04);
920
921 bt::gatt::CharacteristicData char_data(bt::gatt::Property::kWrite,
922 std::nullopt,
923 kHandle,
924 kValueHandle,
925 kServiceUuid);
926 fake_client()->set_characteristics({char_data});
927
928 int write_count = 0;
929 fake_client()->set_execute_prepare_writes_callback(
930 [&](bt::att::PrepareWriteQueue prep_write_queue,
931 bt::gatt::ReliableMode reliable,
932 bt::att::ResultFunction<> callback) {
933 write_count++;
934 ASSERT_EQ(prep_write_queue.size(), 1u);
935 EXPECT_EQ(reliable, bt::gatt::ReliableMode::kEnabled);
936 EXPECT_EQ(prep_write_queue.front().handle(), kValueHandle);
937 EXPECT_EQ(prep_write_queue.front().offset(), 0u);
938 EXPECT_TRUE(ContainersEqual(prep_write_queue.front().value(), kValue));
939 callback(fit::ok());
940 });
941
942 std::optional<std::vector<fbg::Characteristic>> fidl_characteristics;
943 service_proxy()->DiscoverCharacteristics(
944 [&](std::vector<fbg::Characteristic> chars) {
945 fidl_characteristics = std::move(chars);
946 });
947 RunLoopUntilIdle();
948 ASSERT_TRUE(fidl_characteristics.has_value());
949 ASSERT_EQ(fidl_characteristics->size(), 1u);
950 const fbg::Characteristic& fidl_char = fidl_characteristics->front();
951 ASSERT_TRUE(fidl_char.has_handle());
952
953 fbg::WriteOptions options;
954 options.set_write_mode(fbg::WriteMode::RELIABLE);
955 std::optional<fpromise::result<void, fbg::Error>> fidl_result;
956 service_proxy()->WriteCharacteristic(
957 fidl_char.handle(),
958 kValue.ToVector(),
959 std::move(options),
960 [&](auto result) { fidl_result = std::move(result); });
961 RunLoopUntilIdle();
962 ASSERT_TRUE(fidl_result.has_value());
963 EXPECT_TRUE(fidl_result->is_ok());
964 EXPECT_EQ(write_count, 1);
965 }
966
TEST_F(Gatt2RemoteServiceServerTest,WriteLongCharacteristicDefaultOptions)967 TEST_F(Gatt2RemoteServiceServerTest, WriteLongCharacteristicDefaultOptions) {
968 constexpr bt::att::Handle kHandle = 3;
969 constexpr bt::att::Handle kValueHandle = kHandle + 1;
970 constexpr size_t kHeaderSize =
971 sizeof(bt::att::OpCode) + sizeof(bt::att::PrepareWriteRequestParams);
972 const uint16_t kMtu = fake_client()->mtu();
973 const size_t kFirstPacketValueSize = kMtu - kHeaderSize;
974 bt::DynamicByteBuffer kValue(kMtu);
975 kValue.Fill(0x03);
976
977 bt::gatt::CharacteristicData char_data(bt::gatt::Property::kWrite,
978 std::nullopt,
979 kHandle,
980 kValueHandle,
981 kServiceUuid);
982 fake_client()->set_characteristics({char_data});
983
984 int write_count = 0;
985 fake_client()->set_execute_prepare_writes_callback(
986 [&](bt::att::PrepareWriteQueue prep_write_queue,
987 bt::gatt::ReliableMode reliable,
988 bt::att::ResultFunction<> callback) {
989 write_count++;
990 EXPECT_EQ(reliable, bt::gatt::ReliableMode::kDisabled);
991 ASSERT_EQ(prep_write_queue.size(), 2u);
992 EXPECT_EQ(prep_write_queue.front().handle(), kValueHandle);
993 EXPECT_EQ(prep_write_queue.front().offset(), 0u);
994 EXPECT_TRUE(ContainersEqual(kValue.view(0, kFirstPacketValueSize),
995 prep_write_queue.front().value()));
996 prep_write_queue.pop();
997 EXPECT_EQ(prep_write_queue.front().handle(), kValueHandle);
998 EXPECT_EQ(prep_write_queue.front().offset(), kFirstPacketValueSize);
999 EXPECT_TRUE(ContainersEqual(kValue.view(kFirstPacketValueSize),
1000 prep_write_queue.front().value()));
1001 callback(fit::ok());
1002 });
1003
1004 std::optional<std::vector<fbg::Characteristic>> fidl_characteristics;
1005 service_proxy()->DiscoverCharacteristics(
1006 [&](std::vector<fbg::Characteristic> chars) {
1007 fidl_characteristics = std::move(chars);
1008 });
1009 RunLoopUntilIdle();
1010 ASSERT_TRUE(fidl_characteristics.has_value());
1011 ASSERT_EQ(fidl_characteristics->size(), 1u);
1012 const fbg::Characteristic& fidl_char = fidl_characteristics->front();
1013 ASSERT_TRUE(fidl_char.has_handle());
1014
1015 std::optional<fpromise::result<void, fbg::Error>> fidl_result;
1016 service_proxy()->WriteCharacteristic(
1017 fidl_char.handle(),
1018 kValue.ToVector(),
1019 fbg::WriteOptions(),
1020 [&](auto result) { fidl_result = std::move(result); });
1021 RunLoopUntilIdle();
1022 ASSERT_TRUE(fidl_result.has_value());
1023 EXPECT_TRUE(fidl_result->is_ok());
1024 EXPECT_EQ(write_count, 1);
1025 }
1026
TEST_F(Gatt2RemoteServiceServerTest,WriteDescriptorHandleTooLarge)1027 TEST_F(Gatt2RemoteServiceServerTest, WriteDescriptorHandleTooLarge) {
1028 fbg::Handle handle;
1029 handle.value = std::numeric_limits<bt::att::Handle>::max() + 1ULL;
1030
1031 std::optional<fpromise::result<void, fbg::Error>> fidl_result;
1032 service_proxy()->WriteDescriptor(
1033 handle, /*value=*/{}, fbg::WriteOptions(), [&](auto result) {
1034 fidl_result = std::move(result);
1035 });
1036 RunLoopUntilIdle();
1037 ASSERT_TRUE(fidl_result.has_value());
1038 ASSERT_TRUE(fidl_result->is_error());
1039 EXPECT_EQ(fidl_result->error(), fbg::Error::INVALID_HANDLE);
1040 }
1041
TEST_F(Gatt2RemoteServiceServerTest,WriteDescriptorWithoutResponseNotSupported)1042 TEST_F(Gatt2RemoteServiceServerTest,
1043 WriteDescriptorWithoutResponseNotSupported) {
1044 constexpr bt::att::Handle kHandle = 3;
1045 fbg::WriteOptions options;
1046 options.set_write_mode(fbg::WriteMode::WITHOUT_RESPONSE);
1047
1048 std::optional<fpromise::result<void, fbg::Error>> fidl_result;
1049 service_proxy()->WriteDescriptor(
1050 fbg::Handle{kHandle}, /*value=*/{}, std::move(options), [&](auto result) {
1051 fidl_result = std::move(result);
1052 });
1053 RunLoopUntilIdle();
1054 ASSERT_TRUE(fidl_result.has_value());
1055 ASSERT_TRUE(fidl_result->is_error());
1056 EXPECT_EQ(fidl_result->error(), fbg::Error::INVALID_PARAMETERS);
1057 }
1058
TEST_F(Gatt2RemoteServiceServerTest,WriteDescriptorReliableNotSupported)1059 TEST_F(Gatt2RemoteServiceServerTest, WriteDescriptorReliableNotSupported) {
1060 constexpr bt::att::Handle kHandle = 3;
1061 fbg::WriteOptions options;
1062 options.set_write_mode(fbg::WriteMode::RELIABLE);
1063
1064 std::optional<fpromise::result<void, fbg::Error>> fidl_result;
1065 service_proxy()->WriteDescriptor(
1066 fbg::Handle{kHandle}, /*value=*/{}, std::move(options), [&](auto result) {
1067 fidl_result = std::move(result);
1068 });
1069 RunLoopUntilIdle();
1070 ASSERT_TRUE(fidl_result.has_value());
1071 ASSERT_TRUE(fidl_result->is_error());
1072 EXPECT_EQ(fidl_result->error(), fbg::Error::INVALID_PARAMETERS);
1073 }
1074
TEST_F(Gatt2RemoteServiceServerTest,WriteShortDescriptor)1075 TEST_F(Gatt2RemoteServiceServerTest, WriteShortDescriptor) {
1076 constexpr bt::att::Handle kHandle = 3;
1077 constexpr bt::att::Handle kCharacteristicValueHandle = kHandle + 1;
1078 bt::gatt::CharacteristicData char_data(bt::gatt::Property::kWrite,
1079 std::nullopt,
1080 kHandle,
1081 kCharacteristicValueHandle,
1082 kServiceUuid);
1083 fake_client()->set_characteristics({char_data});
1084
1085 constexpr bt::att::Handle kDescriptorHandle(kCharacteristicValueHandle + 1);
1086 const bt::UUID kDescriptorUuid(uint16_t{0x0001});
1087 bt::gatt::DescriptorData descriptor(kDescriptorHandle, kDescriptorUuid);
1088 const auto kValue = bt::StaticByteBuffer(0x00, 0x01, 0x02, 0x03, 0x04);
1089 fake_client()->set_descriptors({descriptor});
1090
1091 int write_count = 0;
1092 fake_client()->set_write_request_callback(
1093 [&](bt::att::Handle handle,
1094 const bt::ByteBuffer& value,
1095 bt::att::ResultFunction<> callback) {
1096 write_count++;
1097 EXPECT_EQ(handle, kDescriptorHandle);
1098 EXPECT_TRUE(ContainersEqual(value, kValue));
1099 callback(fit::ok());
1100 });
1101
1102 std::optional<std::vector<fbg::Characteristic>> fidl_characteristics;
1103 service_proxy()->DiscoverCharacteristics(
1104 [&](std::vector<fbg::Characteristic> chars) {
1105 fidl_characteristics = std::move(chars);
1106 });
1107 RunLoopUntilIdle();
1108 ASSERT_TRUE(fidl_characteristics.has_value());
1109 ASSERT_EQ(fidl_characteristics->size(), 1u);
1110 const fbg::Characteristic& fidl_char = fidl_characteristics->front();
1111 ASSERT_TRUE(fidl_char.has_descriptors());
1112 ASSERT_EQ(fidl_char.descriptors().size(), 1u);
1113
1114 fbg::WriteOptions options;
1115 std::optional<fpromise::result<void, fbg::Error>> fidl_result;
1116 service_proxy()->WriteDescriptor(
1117 fidl_char.descriptors().front().handle(),
1118 kValue.ToVector(),
1119 std::move(options),
1120 [&](auto result) { fidl_result = std::move(result); });
1121 RunLoopUntilIdle();
1122 ASSERT_TRUE(fidl_result.has_value());
1123 EXPECT_TRUE(fidl_result->is_ok());
1124 EXPECT_EQ(write_count, 1);
1125 }
1126
TEST_F(Gatt2RemoteServiceServerTest,WriteShortDescriptorWithNonZeroOffset)1127 TEST_F(Gatt2RemoteServiceServerTest, WriteShortDescriptorWithNonZeroOffset) {
1128 constexpr bt::att::Handle kHandle = 3;
1129 constexpr bt::att::Handle kCharacteristicValueHandle = kHandle + 1;
1130 bt::gatt::CharacteristicData char_data(bt::gatt::Property::kWrite,
1131 std::nullopt,
1132 kHandle,
1133 kCharacteristicValueHandle,
1134 kServiceUuid);
1135 fake_client()->set_characteristics({char_data});
1136
1137 constexpr bt::att::Handle kDescriptorHandle(kCharacteristicValueHandle + 1);
1138 const bt::UUID kDescriptorUuid(uint16_t{0x0001});
1139 bt::gatt::DescriptorData descriptor(kDescriptorHandle, kDescriptorUuid);
1140 fake_client()->set_descriptors({descriptor});
1141
1142 const auto kValue = bt::StaticByteBuffer(0x00, 0x01, 0x02, 0x03, 0x04);
1143 const uint16_t kOffset = 1;
1144
1145 int write_count = 0;
1146 fake_client()->set_execute_prepare_writes_callback(
1147 [&](bt::att::PrepareWriteQueue prep_write_queue,
1148 bt::gatt::ReliableMode reliable,
1149 bt::att::ResultFunction<> callback) {
1150 write_count++;
1151 ASSERT_EQ(prep_write_queue.size(), 1u);
1152 EXPECT_EQ(prep_write_queue.front().handle(), kDescriptorHandle);
1153 EXPECT_EQ(prep_write_queue.front().offset(), kOffset);
1154 EXPECT_EQ(reliable, bt::gatt::ReliableMode::kDisabled);
1155 EXPECT_TRUE(ContainersEqual(prep_write_queue.front().value(), kValue));
1156 callback(fit::ok());
1157 });
1158
1159 std::optional<std::vector<fbg::Characteristic>> fidl_characteristics;
1160 service_proxy()->DiscoverCharacteristics(
1161 [&](std::vector<fbg::Characteristic> chars) {
1162 fidl_characteristics = std::move(chars);
1163 });
1164 RunLoopUntilIdle();
1165 ASSERT_TRUE(fidl_characteristics.has_value());
1166 ASSERT_EQ(fidl_characteristics->size(), 1u);
1167 const fbg::Characteristic& fidl_char = fidl_characteristics->front();
1168 ASSERT_TRUE(fidl_char.has_descriptors());
1169 ASSERT_EQ(fidl_char.descriptors().size(), 1u);
1170
1171 fbg::WriteOptions options;
1172 options.set_offset(kOffset);
1173 std::optional<fpromise::result<void, fbg::Error>> fidl_result;
1174 service_proxy()->WriteDescriptor(
1175 fidl_char.descriptors().front().handle(),
1176 kValue.ToVector(),
1177 std::move(options),
1178 [&](auto result) { fidl_result = std::move(result); });
1179 RunLoopUntilIdle();
1180 ASSERT_TRUE(fidl_result.has_value());
1181 EXPECT_TRUE(fidl_result->is_ok());
1182 EXPECT_EQ(write_count, 1);
1183 }
1184
TEST_F(Gatt2RemoteServiceServerTest,WriteLongDescriptorDefaultOptions)1185 TEST_F(Gatt2RemoteServiceServerTest, WriteLongDescriptorDefaultOptions) {
1186 constexpr bt::att::Handle kHandle = 3;
1187 constexpr bt::att::Handle kCharacteristicValueHandle = kHandle + 1;
1188 bt::gatt::CharacteristicData char_data(bt::gatt::Property::kWrite,
1189 std::nullopt,
1190 kHandle,
1191 kCharacteristicValueHandle,
1192 kServiceUuid);
1193 fake_client()->set_characteristics({char_data});
1194
1195 constexpr bt::att::Handle kDescriptorHandle(kCharacteristicValueHandle + 1);
1196 const bt::UUID kDescriptorUuid(uint16_t{0x0001});
1197 bt::gatt::DescriptorData descriptor(kDescriptorHandle, kDescriptorUuid);
1198 fake_client()->set_descriptors({descriptor});
1199
1200 constexpr size_t kHeaderSize =
1201 sizeof(bt::att::OpCode) + sizeof(bt::att::PrepareWriteRequestParams);
1202 const uint16_t kMtu = fake_client()->mtu();
1203 const size_t kFirstPacketValueSize = kMtu - kHeaderSize;
1204 bt::DynamicByteBuffer kValue(kMtu);
1205 kValue.Fill(0x03);
1206
1207 int write_count = 0;
1208 fake_client()->set_execute_prepare_writes_callback(
1209 [&](bt::att::PrepareWriteQueue prep_write_queue,
1210 bt::gatt::ReliableMode reliable,
1211 bt::att::ResultFunction<> callback) {
1212 write_count++;
1213 EXPECT_EQ(reliable, bt::gatt::ReliableMode::kDisabled);
1214 ASSERT_EQ(prep_write_queue.size(), 2u);
1215 EXPECT_EQ(prep_write_queue.front().handle(), kDescriptorHandle);
1216 EXPECT_EQ(prep_write_queue.front().offset(), 0u);
1217 EXPECT_TRUE(ContainersEqual(kValue.view(0, kFirstPacketValueSize),
1218 prep_write_queue.front().value()));
1219 prep_write_queue.pop();
1220 EXPECT_EQ(prep_write_queue.front().handle(), kDescriptorHandle);
1221 EXPECT_EQ(prep_write_queue.front().offset(), kFirstPacketValueSize);
1222 EXPECT_TRUE(ContainersEqual(kValue.view(kFirstPacketValueSize),
1223 prep_write_queue.front().value()));
1224 callback(fit::ok());
1225 });
1226
1227 std::optional<std::vector<fbg::Characteristic>> fidl_characteristics;
1228 service_proxy()->DiscoverCharacteristics(
1229 [&](std::vector<fbg::Characteristic> chars) {
1230 fidl_characteristics = std::move(chars);
1231 });
1232 RunLoopUntilIdle();
1233 ASSERT_TRUE(fidl_characteristics.has_value());
1234 ASSERT_EQ(fidl_characteristics->size(), 1u);
1235 const fbg::Characteristic& fidl_char = fidl_characteristics->front();
1236 ASSERT_TRUE(fidl_char.has_descriptors());
1237 ASSERT_EQ(fidl_char.descriptors().size(), 1u);
1238
1239 std::optional<fpromise::result<void, fbg::Error>> fidl_result;
1240 service_proxy()->WriteDescriptor(
1241 fidl_char.descriptors().front().handle(),
1242 kValue.ToVector(),
1243 fbg::WriteOptions(),
1244 [&](auto result) { fidl_result = std::move(result); });
1245 RunLoopUntilIdle();
1246 ASSERT_TRUE(fidl_result.has_value());
1247 EXPECT_TRUE(fidl_result->is_ok());
1248 EXPECT_EQ(write_count, 1);
1249 }
1250
1251 class FakeCharacteristicNotifier
1252 : public fbg::testing::CharacteristicNotifier_TestBase {
1253 public:
1254 struct Notification {
1255 fbg::ReadValue value;
1256 OnNotificationCallback notification_cb;
1257 };
FakeCharacteristicNotifier(fidl::InterfaceRequest<fbg::CharacteristicNotifier> request)1258 explicit FakeCharacteristicNotifier(
1259 fidl::InterfaceRequest<fbg::CharacteristicNotifier> request)
1260 : binding_(this, std::move(request)) {
1261 binding_.set_error_handler([this](zx_status_t status) { error_ = status; });
1262 }
1263
Unbind()1264 void Unbind() { binding_.Unbind(); }
1265
OnNotification(fbg::ReadValue value,OnNotificationCallback callback)1266 void OnNotification(fbg::ReadValue value,
1267 OnNotificationCallback callback) override {
1268 notifications_.push_back(
1269 Notification{std::move(value), std::move(callback)});
1270 }
1271
notifications()1272 std::vector<Notification>& notifications() { return notifications_; }
1273
error() const1274 std::optional<zx_status_t> error() const { return error_; }
1275
1276 private:
NotImplemented_(const std::string & name)1277 void NotImplemented_(const std::string& name) override {
1278 FAIL() << name << " is not implemented";
1279 }
1280
1281 fidl::Binding<fbg::CharacteristicNotifier> binding_;
1282 std::vector<Notification> notifications_;
1283 std::optional<zx_status_t> error_;
1284 };
1285
1286 class Gatt2RemoteServiceServerCharacteristicNotifierTest
1287 : public Gatt2RemoteServiceServerTest {
1288 public:
SetUp()1289 void SetUp() override {
1290 Gatt2RemoteServiceServerTest::SetUp();
1291 bt::gatt::CharacteristicData characteristic(bt::gatt::Property::kNotify,
1292 /*ext_props=*/std::nullopt,
1293 char_handle_,
1294 char_value_handle_,
1295 kCharacteristicUuid);
1296 fake_client()->set_characteristics({characteristic});
1297 bt::gatt::DescriptorData ccc_descriptor(
1298 ccc_descriptor_handle_, bt::gatt::types::kClientCharacteristicConfig);
1299 fake_client()->set_descriptors({ccc_descriptor});
1300
1301 std::optional<std::vector<fbg::Characteristic>> fidl_characteristics;
1302 service_proxy()->DiscoverCharacteristics(
1303 [&](std::vector<fbg::Characteristic> chars) {
1304 fidl_characteristics = std::move(chars);
1305 });
1306 RunLoopUntilIdle();
1307 ASSERT_TRUE(fidl_characteristics.has_value());
1308 ASSERT_EQ(fidl_characteristics->size(), 1u);
1309 characteristic_ = std::move(fidl_characteristics->front());
1310 }
1311
1312 protected:
characteristic() const1313 const fbg::Characteristic& characteristic() const { return characteristic_; }
characteristic_handle() const1314 bt::att::Handle characteristic_handle() const { return char_handle_; }
characteristic_value_handle() const1315 bt::att::Handle characteristic_value_handle() const {
1316 return char_value_handle_;
1317 }
ccc_descriptor_handle() const1318 bt::att::Handle ccc_descriptor_handle() const {
1319 return ccc_descriptor_handle_;
1320 }
1321
1322 private:
1323 fbg::Characteristic characteristic_;
1324 const bt::att::Handle char_handle_ = 2;
1325 const bt::att::Handle char_value_handle_ = 3;
1326 const bt::att::Handle ccc_descriptor_handle_ = 4;
1327 };
1328
TEST_F(Gatt2RemoteServiceServerCharacteristicNotifierTest,RegisterCharacteristicNotifierReceiveNotificationsAndUnregister)1329 TEST_F(Gatt2RemoteServiceServerCharacteristicNotifierTest,
1330 RegisterCharacteristicNotifierReceiveNotificationsAndUnregister) {
1331 const auto kValue0 = bt::StaticByteBuffer(0x01, 0x02, 0x03);
1332 const auto kValue1 = bt::StaticByteBuffer(0x04, 0x05, 0x06);
1333
1334 // Respond to CCC write with success status so that notifications are enabled.
1335 fake_client()->set_write_request_callback([&](bt::att::Handle handle,
1336 const bt::ByteBuffer& /*value*/,
1337 auto status_callback) {
1338 EXPECT_EQ(handle, ccc_descriptor_handle());
1339 status_callback(fit::ok());
1340 });
1341
1342 fidl::InterfaceHandle<fbg::CharacteristicNotifier> notifier_handle;
1343 FakeCharacteristicNotifier notifier_server(notifier_handle.NewRequest());
1344 auto& notifications = notifier_server.notifications();
1345
1346 std::optional<fpromise::result<void, fbg::Error>> register_result;
1347 auto register_cb = [&](fpromise::result<void, fbg::Error> result) {
1348 register_result = result;
1349 };
1350 service_proxy()->RegisterCharacteristicNotifier(characteristic().handle(),
1351 std::move(notifier_handle),
1352 std::move(register_cb));
1353 RunLoopUntilIdle();
1354 ASSERT_TRUE(register_result.has_value());
1355 EXPECT_TRUE(register_result->is_ok());
1356
1357 // Send 2 notifications to test flow control.
1358 service()->HandleNotificationForTesting(characteristic_value_handle(),
1359 kValue0,
1360 /*maybe_truncated=*/false);
1361 service()->HandleNotificationForTesting(characteristic_value_handle(),
1362 kValue1,
1363 /*maybe_truncated=*/true);
1364 RunLoopUntilIdle();
1365 ASSERT_EQ(notifications.size(), 1u);
1366 fbg::ReadValue& notification_0 = notifications[0].value;
1367 ASSERT_TRUE(notification_0.has_value());
1368 EXPECT_TRUE(bt::ContainersEqual(notification_0.value(), kValue0));
1369 ASSERT_TRUE(notification_0.has_handle());
1370 EXPECT_EQ(notification_0.handle().value,
1371 static_cast<uint64_t>(characteristic_value_handle()));
1372 ASSERT_TRUE(notification_0.has_maybe_truncated());
1373 ASSERT_FALSE(notification_0.maybe_truncated());
1374
1375 notifications[0].notification_cb();
1376 RunLoopUntilIdle();
1377 ASSERT_EQ(notifications.size(), 2u);
1378 fbg::ReadValue& notification_1 = notifications[1].value;
1379 ASSERT_TRUE(notification_1.has_value());
1380 EXPECT_TRUE(bt::ContainersEqual(notification_1.value(), kValue1));
1381 ASSERT_TRUE(notification_1.has_handle());
1382 EXPECT_EQ(notification_1.handle().value,
1383 static_cast<uint64_t>(characteristic_value_handle()));
1384 ASSERT_TRUE(notification_1.has_maybe_truncated());
1385 ASSERT_TRUE(notification_1.maybe_truncated());
1386
1387 notifications[1].notification_cb();
1388 RunLoopUntilIdle();
1389 EXPECT_EQ(notifications.size(), 2u);
1390
1391 notifier_server.Unbind();
1392 RunLoopUntilIdle();
1393
1394 // Notifications should be ignored after notifier is unregistered.
1395 service()->HandleNotificationForTesting(characteristic_value_handle(),
1396 kValue0,
1397 /*maybe_truncated=*/false);
1398 RunLoopUntilIdle();
1399 }
1400
TEST_F(Gatt2RemoteServiceServerCharacteristicNotifierTest,QueueTooManyNotificationsAndCloseNotifier)1401 TEST_F(Gatt2RemoteServiceServerCharacteristicNotifierTest,
1402 QueueTooManyNotificationsAndCloseNotifier) {
1403 const auto kValue = bt::StaticByteBuffer(0x01, 0x02, 0x03);
1404
1405 // Respond to CCC write with success status so that notifications are enabled.
1406 fake_client()->set_write_request_callback([&](bt::att::Handle handle,
1407 const bt::ByteBuffer& /*value*/,
1408 auto status_callback) {
1409 EXPECT_EQ(handle, ccc_descriptor_handle());
1410 status_callback(fit::ok());
1411 });
1412
1413 fidl::InterfaceHandle<fbg::CharacteristicNotifier> notifier_handle;
1414 FakeCharacteristicNotifier notifier_server(notifier_handle.NewRequest());
1415 auto& notifications = notifier_server.notifications();
1416
1417 std::optional<fpromise::result<void, fbg::Error>> register_result;
1418 auto register_cb = [&](fpromise::result<void, fbg::Error> result) {
1419 register_result = result;
1420 };
1421 service_proxy()->RegisterCharacteristicNotifier(characteristic().handle(),
1422 std::move(notifier_handle),
1423 std::move(register_cb));
1424 RunLoopUntilIdle();
1425 ASSERT_TRUE(register_result.has_value());
1426 EXPECT_TRUE(register_result->is_ok());
1427
1428 // Fill the pending notifier values queue.
1429 for (size_t i = 0; i < Gatt2RemoteServiceServer::kMaxPendingNotifierValues;
1430 i++) {
1431 service()->HandleNotificationForTesting(characteristic_value_handle(),
1432 kValue,
1433 /*maybe_truncated=*/false);
1434 }
1435 RunLoopUntilIdle();
1436 ASSERT_EQ(notifications.size(), 1u);
1437 EXPECT_FALSE(notifier_server.error().has_value());
1438
1439 // This notification should exceed the max queue size.
1440 service()->HandleNotificationForTesting(characteristic_value_handle(),
1441 kValue,
1442 /*maybe_truncated=*/false);
1443 RunLoopUntilIdle();
1444 EXPECT_TRUE(notifier_server.error().has_value());
1445
1446 // Notifications should be ignored after notifier is unregistered due to an
1447 // error.
1448 service()->HandleNotificationForTesting(characteristic_value_handle(),
1449 kValue,
1450 /*maybe_truncated=*/false);
1451 RunLoopUntilIdle();
1452 notifications[0].notification_cb();
1453 EXPECT_EQ(notifications.size(), 1u);
1454 }
1455
TEST_F(Gatt2RemoteServiceServerCharacteristicNotifierTest,RegisterCharacteristicNotifierWriteError)1456 TEST_F(Gatt2RemoteServiceServerCharacteristicNotifierTest,
1457 RegisterCharacteristicNotifierWriteError) {
1458 // Respond to CCC write with error status so that registration fails.
1459 fake_client()->set_write_request_callback([&](bt::att::Handle handle,
1460 const bt::ByteBuffer& /*value*/,
1461 auto status_callback) {
1462 EXPECT_EQ(handle, ccc_descriptor_handle());
1463 status_callback(
1464 bt::ToResult(bt::att::ErrorCode::kInsufficientAuthentication));
1465 });
1466
1467 fidl::InterfaceHandle<fbg::CharacteristicNotifier> notifier_handle;
1468 FakeCharacteristicNotifier notifier_server(notifier_handle.NewRequest());
1469 std::optional<fpromise::result<void, fbg::Error>> register_result;
1470 auto register_cb = [&](fpromise::result<void, fbg::Error> result) {
1471 register_result = result;
1472 };
1473 service_proxy()->RegisterCharacteristicNotifier(characteristic().handle(),
1474 std::move(notifier_handle),
1475 std::move(register_cb));
1476 RunLoopUntilIdle();
1477 ASSERT_TRUE(register_result.has_value());
1478 ASSERT_TRUE(register_result->is_error());
1479 EXPECT_EQ(register_result->error(), fbg::Error::INSUFFICIENT_AUTHENTICATION);
1480 EXPECT_TRUE(notifier_server.error().has_value());
1481 }
1482
TEST_F(Gatt2RemoteServiceServerCharacteristicNotifierTest,RegisterCharacteristicNotifierAndDestroyServerBeforeStatusCallbackCausesNotificationsToBeDisabled)1483 TEST_F(
1484 Gatt2RemoteServiceServerCharacteristicNotifierTest,
1485 RegisterCharacteristicNotifierAndDestroyServerBeforeStatusCallbackCausesNotificationsToBeDisabled) {
1486 // Respond to CCC write with success status so that notifications are enabled.
1487 int ccc_write_count = 0;
1488 bt::att::ResultFunction<> enable_notifications_status_cb = nullptr;
1489 fake_client()->set_write_request_callback(
1490 [&](bt::att::Handle handle,
1491 const bt::ByteBuffer& value,
1492 bt::att::ResultFunction<> status_callback) {
1493 ccc_write_count++;
1494 EXPECT_EQ(handle, ccc_descriptor_handle());
1495 if (ccc_write_count == 1) {
1496 EXPECT_NE(value[0], 0u); // Enable value
1497 enable_notifications_status_cb = std::move(status_callback);
1498 } else {
1499 EXPECT_EQ(value[0], 0u); // Disable value
1500 status_callback(fit::ok());
1501 }
1502 });
1503
1504 fidl::InterfaceHandle<fbg::CharacteristicNotifier> notifier_handle;
1505 FakeCharacteristicNotifier notifier_server(notifier_handle.NewRequest());
1506
1507 std::optional<fpromise::result<void, fbg::Error>> register_result;
1508 auto register_cb = [&](fpromise::result<void, fbg::Error> result) {
1509 register_result = result;
1510 };
1511 service_proxy()->RegisterCharacteristicNotifier(characteristic().handle(),
1512 std::move(notifier_handle),
1513 std::move(register_cb));
1514 RunLoopUntilIdle();
1515 EXPECT_FALSE(register_result.has_value());
1516 EXPECT_EQ(ccc_write_count, 1);
1517
1518 DestroyServer();
1519 ASSERT_TRUE(enable_notifications_status_cb);
1520 enable_notifications_status_cb(fit::ok());
1521 RunLoopUntilIdle();
1522 // Notifications should have been disabled in enable notifications status
1523 // callback.
1524 EXPECT_EQ(ccc_write_count, 2);
1525 }
1526
TEST_F(Gatt2RemoteServiceServerCharacteristicNotifierTest,RegisterCharacteristicNotifierAndDestroyServerAfterStatusCallbackCausesNotificationsToBeDisabled)1527 TEST_F(
1528 Gatt2RemoteServiceServerCharacteristicNotifierTest,
1529 RegisterCharacteristicNotifierAndDestroyServerAfterStatusCallbackCausesNotificationsToBeDisabled) {
1530 // Respond to CCC write with success status so that notifications are enabled.
1531 int ccc_write_count = 0;
1532 bt::att::ResultFunction<> enable_notifications_status_cb = nullptr;
1533 fake_client()->set_write_request_callback(
1534 [&](bt::att::Handle handle,
1535 const bt::ByteBuffer& value,
1536 bt::att::ResultFunction<> status_callback) {
1537 ccc_write_count++;
1538 EXPECT_EQ(handle, ccc_descriptor_handle());
1539 if (ccc_write_count == 1) {
1540 EXPECT_NE(value[0], 0u); // Enable value
1541 } else {
1542 EXPECT_EQ(value[0], 0u); // Disable value
1543 }
1544 status_callback(fit::ok());
1545 });
1546
1547 fidl::InterfaceHandle<fbg::CharacteristicNotifier> notifier_handle;
1548 FakeCharacteristicNotifier notifier_server(notifier_handle.NewRequest());
1549
1550 std::optional<fpromise::result<void, fbg::Error>> register_result;
1551 auto register_cb = [&](fpromise::result<void, fbg::Error> result) {
1552 register_result = result;
1553 };
1554 service_proxy()->RegisterCharacteristicNotifier(characteristic().handle(),
1555 std::move(notifier_handle),
1556 std::move(register_cb));
1557 RunLoopUntilIdle();
1558 EXPECT_TRUE(register_result.has_value());
1559 EXPECT_TRUE(register_result->is_ok());
1560 EXPECT_EQ(ccc_write_count, 1);
1561
1562 DestroyServer();
1563 RunLoopUntilIdle();
1564 // Notifications should have been disabled in the server destructor.
1565 EXPECT_EQ(ccc_write_count, 2);
1566 }
1567
1568 } // namespace
1569 } // namespace bthost
1570