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